diff --git a/frontmatter/__init__.py b/frontmatter/__init__.py index 04f4029..66c9b45 100644 --- a/frontmatter/__init__.py +++ b/frontmatter/__init__.py @@ -191,7 +191,13 @@ def loads( text = u(text, encoding) handler = handler or detect_format(text, handlers) metadata, content = parse(text, encoding, handler, **defaults) - return Post(content, handler, **metadata) + # Assign the metadata dict directly rather than splatting it as keyword + # arguments: YAML/TOML mappings allow non-string keys (ints, booleans, + # dates), and Post(content, handler, **metadata) raises "keywords must be + # strings" on those, even though the front matter itself is valid. + post = Post(content, handler) + post.metadata = metadata + return post def dump( diff --git a/tests/unit_test.py b/tests/unit_test.py index 188fb4c..d58488e 100644 --- a/tests/unit_test.py +++ b/tests/unit_test.py @@ -61,6 +61,14 @@ def test_check_empty_frontmatter(self): self.assertEqual(ret, True) + def test_non_string_metadata_keys(self): + "YAML allows non-string mapping keys (e.g. ints); loads must not choke on them." + post = frontmatter.loads("---\n1: one\n2: two\n---\nbody") + self.assertEqual(post.metadata, {1: "one", 2: "two"}) + self.assertEqual(post.content, "body") + # and the post still round-trips through dumps/loads + self.assertEqual(frontmatter.loads(frontmatter.dumps(post)).metadata, post.metadata) + def test_no_frontmatter(self): "This is not a zen exercise." post = frontmatter.load("tests/empty/no-frontmatter.txt")