add better metadata handling

This commit is contained in:
Daniel Fichtinger 2025-06-21 16:53:24 -04:00
parent 71982435f3
commit 73215df2e8
3 changed files with 75 additions and 10 deletions

View file

@ -3,18 +3,38 @@ from zona import markdown as zmd
from zona import util from zona import util
from pathlib import Path from pathlib import Path
import frontmatter import frontmatter
from dacite import from_dict from dacite import Config, from_dict, DaciteError
from datetime import date
from yaml import YAMLError
def split_metadata(path: Path) -> tuple[Metadata, str]: def split_metadata(path: Path) -> tuple[Metadata, str]:
"""
Parses a file and returns parsed Metadata and its content. Defaults
are applied for missing fields. If there is no metadata, a Metadata
with default values is returned.
Raises:
ValueError: If the metadata block is malformed in any way.
"""
try:
post = frontmatter.load(str(path)) post = frontmatter.load(str(path))
# TODO: handle missing metadata except YAMLError as e:
meta = post.metadata raise ValueError(f"YAML frontmatter error in {path}: {e}")
# TODO: handle malformed metadata raw_meta = post.metadata or {}
defaults = {
"title": util.filename_to_title(path),
"date": date.fromtimestamp(path.stat().st_mtime),
}
meta = {**defaults, **raw_meta}
try:
metadata = from_dict( metadata = from_dict(
data_class=Metadata, data_class=Metadata,
data=meta, data=meta,
config=Config(check_types=True, strict=True),
) )
except DaciteError as e:
raise ValueError(f"Malformed metadata in {path}: {e}")
return metadata, post.content return metadata, post.content

View file

@ -9,7 +9,7 @@ from typing import Literal
class Metadata: class Metadata:
title: str title: str
date: date date: date
description: str description: str | None
# add more options later... # add more options later...

View file

@ -1,3 +1,4 @@
import pytest
from datetime import date from datetime import date
from zona.models import Metadata from zona.models import Metadata
from zona.builder import split_metadata, discover, build from zona.builder import split_metadata, discover, build
@ -24,6 +25,50 @@ description: This is a test.
assert content == "# Hello World" assert content == "# Hello World"
def test_no_metadata(tmp_path: Path):
content = "# Hello World"
test_file = tmp_path / "hello-world.md"
test_file.write_text(content)
meta, content = split_metadata(test_file)
assert isinstance(meta, Metadata)
assert meta.title == "Hello World"
assert meta.description is None
assert meta.date == date.today()
assert content == "# Hello World"
def test_malformed_metadata(tmp_path: Path):
with pytest.raises(ValueError):
tests = {
"""
---
title: Test Post
date: not a date!!!
description: This is a test.
---
""",
"""
---
title: Test Post
foobar:
something: what???
description: This is a test.
---
""",
"""
---
title Test Post
description: This is a test.
---
""",
}
for i, content in enumerate(tests):
test_file = tmp_path / str(i)
test_file.write_text(content)
split_metadata(test_file)
def test_discover(tmp_path: Path): def test_discover(tmp_path: Path):
contentd = tmp_path / "content" contentd = tmp_path / "content"
staticd = contentd / "static" staticd = contentd / "static"