eyeseast / python-frontmatter

Parse and manage posts with YAML (or other) frontmatter
http://python-frontmatter.rtfd.io
MIT License
329 stars 43 forks source link

How to load a dictionary as frontmatter? #106

Closed shivams closed 1 year ago

shivams commented 1 year ago

There seems to be no straightforward way to load a dictionary as a front-matter. How to achieve this seemingly simple yet important task?

eyeseast commented 1 year ago

Tell me more about what you mean. Do you have a dictionary and need to construct a text file with frontmatter?

shivams commented 1 year ago

Yes, I need to load a dictionary and then construct a text file with frontmatter having the same content as the dictionary.

Here is a simplified reproduction of the use-case:

dataDict = {'id': 123, 'tag': 'sometag'}

# Trying to parse the dictionary as frontmatter
frontmatter.parse(str(data), handler=JSONHandler())
# Output:
# ({}, "{'id': 123, 'tag': 'sometag'}")

As you can see in the output, the dictionary is parsed as "content" and not "metadata".

Furthermore, if I try to print the parsed dictionary as frontmatter, it gets printed as content and not metadata:

post = fm.loads(str(data), handler=JSONHandler())

fm.dumps(post)
# Output:
# "{}\n\n\n{'id': 123, 'tag': 'dfdfdf'}"
shivams commented 1 year ago

Okay. Here is a way that makes it work using json module:

# This does NOT work. Dict is not considered as metadata.
>>> frontmatter.parse(json.dumps(data), handler=JSONHandler())
({}, '{"id": 123, "tag": "sometag"}')

# This WORKS, if you indent the json output with 4 spaces. Dict is now considered as metadata.
>>> frontmatter.parse(json.dumps(data, indent=4), handler=JSONHandler())
({'id': 123, 'tag': 'sometag'}, '')

Both the above approaches have valid JSON. Yet, only the second works.

Moreover, it feels like a workaround. Is there a simpler way to parse a dict as frontmatter?

eyeseast commented 1 year ago

There is a way to do this. I don't think it's documented, since it wasn't originally an intended use case, but I think other people are using the library this way now:

import frontmatter

data = {"title": "Frontmatter", "link": "https://example.com"}

# this is the object returned by frontmatter.loads
post = frontmatter.Post("This is post content", **data)

# dump it as text
text = frontmatter.dumps(post)

# or export to a file
frontmatter.dump(post, "file.txt")

More on the Post object: https://python-frontmatter.readthedocs.io/en/latest/api.html#post-objects

Hope that helps.

shivams commented 1 year ago

Aaah. That does it!