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 pathlib import Path
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]:
post = frontmatter.load(str(path))
# TODO: handle missing metadata
meta = post.metadata
# TODO: handle malformed metadata
metadata = from_dict(
data_class=Metadata,
data=meta,
)
"""
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))
except YAMLError as e:
raise ValueError(f"YAML frontmatter error in {path}: {e}")
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(
data_class=Metadata,
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

View file

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

View file

@ -1,3 +1,4 @@
import pytest
from datetime import date
from zona.models import Metadata
from zona.builder import split_metadata, discover, build
@ -24,6 +25,50 @@ description: This is a test.
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):
contentd = tmp_path / "content"
staticd = contentd / "static"