Skip to content

fix: keep non-mapping frontmatter blocks as content - #156

Closed
rahul05ranjan wants to merge 1 commit into
eyeseast:mainfrom
rahul05ranjan:155-non-mapping-frontmatter
Closed

rahul05ranjan wants to merge 1 commit into
eyeseast:mainfrom
rahul05ranjan:155-non-mapping-frontmatter

Conversation

@rahul05ranjan

@rahul05ranjan rahul05ranjan commented Nov 9, 2026 •

Copy link
Copy Markdown

Fixes #155

What's wrong

parse() only used the frontmatter block when it parsed to a dict:

fm_data = handler.load(fm)
if isinstance(fm_data, dict):
    metadata.update(fm_data)

Anything else — a plain string, a list, a number — was thrown away, along with the source text it came from. Nothing warned, so a loads() → dumps() round-trip silently deleted part of the file:

>>> frontmatter.loads("---\nsome markdown text\n---\nbody\n").content
'body'

The most realistic case is a Markdown file using --- thematic breaks near the top: everything between the first two rules parsed as a YAML string, wasn't a dict, and vanished. A list-valued block (---\n- a\n- b\n---) is valid YAML with the same fate.

The fix

Treat the whole file as content when the block parses to a non-mapping value — the same thing the no-frontmatter path already does. Empty frontmatter (which parses to None) keeps its existing behavior, so check() and the empty-frontmatter tests are unchanged.

>>> post = frontmatter.loads("---\nsome markdown text\n---\nbody\n")
>>> post.metadata
{}
>>> post.content
'---\nsome markdown text\n---\nbody'

parse()'s docstring is updated to document this; tests are in tests/unit_test.py as suggested in CONTRIBUTING.

Verification

  • New tests (test_non_mapping_frontmatter_is_content, test_list_frontmatter_is_content, test_thematic_break_file_roundtrip_loses_no_text) fail on main, pass with this change.
  • pytest . --doctest-modules --doctest-glob "README.md": 61 passed, 9 failed with the fix vs 58 passed, 9 failed on main — the failures are all the pre-existing TOML-suite ones (this host has no toml package installed) and are identical on both runs; the +3 delta is exactly the new tests.
  • black --check . clean; mypy couldn't run locally (host lacks the toolchain), happy to fix anything CI flags.

AI tools

Yes — this issue (#155) and this PR were prepared with the help of an AI coding assistant (GLM, via OpenRouter): finding the repro, drafting the fix, tests and this write-up. The verification commands above were run directly against this branch and against main, and their output is quoted as it was produced.

A frontmatter block that parses to a non-mapping value (a plain
string, a list) was silently discarded: loads() dropped both the
parsed value and the source text between the delimiters, so a
loads->dumps round-trip deleted part of the file. Most often this
hits Markdown files that use --- thematic breaks near the top.

Treat the whole file as content in that case, the same as the
no-frontmatter path. Empty frontmatter (which parses to None) keeps
its existing behavior.

Fixes eyeseast#155

Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
@eyeseast eyeseast closed this Nov 9, 2026
@rahul05ranjan

Copy link
Copy Markdown
Author

Saw this was closed — thanks for looking. If the behavior change itself was the concern (I read the empty-None case as intentional), I'm happy to drop this. If a different approach to --- thematic breaks would be welcome instead, point me at it and I'll rework.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-mapping frontmatter between --- delimiters is silently discarded, losing that text on parse and round-trip

2 participants