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

Controlling display of YAML metadata #95

Closed nk9 closed 2 years ago

nk9 commented 2 years ago

When I do this:

post = frontmatter.Post("Hello world", title="", date=None)
frontmatter.dump(post, path)

The generated file looks like this:

---
date: null
title: ''
---

Hello world

I would like to be able to:

  1. Control the order of the frontmatter elements. Presently they seem to be sorted alphabetically by key.
  2. Generate YAML keys with completely empty values. No double quotes, no "null". Just a space and then a newline that I can go and fill in by hand later.

How can I achieve this?

nk9 commented 2 years ago

I have solved these issues with a custom formatter. I subclassed YAMLHandler and then implemented this solution to get the dumper to format None as an empty string.

import yaml
from yaml import CSafeDumper as SafeDumper

class FrontmatterHandler(frontmatter.YAMLHandler):
    def export(self, metadata, **kwargs):
        kwargs.setdefault("Dumper", SafeDumper)
        kwargs.setdefault("default_flow_style", False)
        kwargs.setdefault("allow_unicode", True)
        kwargs.setdefault("sort_keys", False)  # You can also just pass sort_keys=False to dump()

        SafeDumper.add_representer(
            type(None), lambda dumper, value: dumper.represent_scalar("tag:yaml.org,2002:null", "")
        )

        metadata = yaml.dump(metadata, **kwargs).strip()
        return metadata
eyeseast commented 2 years ago

That's a good way to do it. You could also pass Dumper and other kwargs to frontmatter.dumps(). This should work:

import frontmatter
from yaml import CSafeDumper as SafeDumper

SafeDumper.add_representer(
    type(None), lambda dumper, value: dumper.represent_scalar("tag:yaml.org,2002:null", "")
)

# yaml is the default handler
post = frontmatter.Post("Hello world", title="", date=None)
frontmatter.dump(post, path, Dumper=SafeDumper)

Any kwargs you use in frontmatter.dump get passed through to yaml.dump (https://github.com/eyeseast/python-frontmatter/blob/main/frontmatter/default_handlers.py#L243-L252).

nk9 commented 2 years ago

Oh, cool, that's a bit simpler. Thanks for the code! I'll close this now as I've got a working solution.