Set up mypy defaults and make sure codebase passes --strict

This commit is contained in:
2026-08-05 00:50:34 +02:00
parent b8a0a94ba9
commit 406ef9fd8d
4 changed files with 33 additions and 12 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ def setup_logging(verbose: bool = False, log_file: str | None = None) -> None:
logger.addHandler(console)
def main():
def main() -> None:
setup_logging(verbose=True)
site = Site(Path("."))
site.build()
+17 -8
View File
@@ -3,9 +3,9 @@ import re
from abc import ABC, abstractmethod
from pathlib import Path
from datetime import date
import typing
from typing import TYPE_CHECKING, Any, cast
if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from omicron.ssg.site import Site
import yaml
@@ -34,19 +34,26 @@ def _highlight_code(code: str, lang: str, attrs: str) -> str:
return pygments_highlight(code, lexer, HtmlFormatter())
def read_frontmatter(path) -> dict:
def read_frontmatter(path: Path) -> dict[str, Any]:
lines = []
with path.open("r", encoding="utf-8") as f:
if f.readline() != "---\n":
raise ContentError(f"Frontmatter opening delimiter not found for {path}")
while (line := f.readline()) != "---\n":
if line == "":
raise ContentError(f"Frontmatter closing delimiter not found for {path}")
raise ContentError(
f"Frontmatter closing delimiter not found for {path}"
)
lines.append(line)
return yaml.safe_load("".join(lines))
data = yaml.safe_load("".join(lines))
if not isinstance(data, dict) or not all(isinstance(k, str) for k in data):
raise ContentError(
f"Frontmatter must be a YAML mapping with string keys in {path}"
)
return cast(dict[str, Any], data)
def create_content(path) -> Content:
def create_content(path: Path) -> Content:
if path.suffix in FRONTMATTER_CONTENT:
meta = read_frontmatter(path)
elif path.suffix == ".yml":
@@ -93,7 +100,9 @@ class Content(ABC):
f.readline() # opening ---
while (line := f.readline()) != "---\n":
if line == "":
raise ContentError(f"Frontmatter closing delimiter not found for {self.source}")
raise ContentError(
f"Frontmatter closing delimiter not found for {self.source}"
)
return f.read()
@abstractmethod
@@ -102,7 +111,7 @@ class Content(ABC):
class Article(Content):
def __init__(self, path: Path, meta: dict):
def __init__(self, path: Path, meta: dict[str, Any]):
if "tags" not in meta:
log.warning("no tags for article in '%s'", path)
super().__init__(
+5 -3
View File
@@ -1,5 +1,5 @@
import logging
from typing import Any
from typing import Any, cast
from omicron.ssg.content import (
Content,
@@ -39,11 +39,13 @@ class Site:
log.debug("Reading config file %s", config_path)
with open(config_path, "r") as f:
config = yaml.safe_load(f)
if not isinstance(config, dict) or not all(isinstance(k, str) for k in config):
raise ConfigError("config file must be a YAML mapping with string keys")
if "name" not in config:
raise ConfigError("name value missing from config")
if "template" not in config:
raise ConfigError("template value missing from config")
return config
return cast(dict[str, Any], config)
@staticmethod
def resolve_template_path(template: str) -> Path:
@@ -84,7 +86,7 @@ class Site:
self.content.append(content)
log.info("Discovered %d content items", len(self.content))
def build(self):
def build(self) -> None:
self.discover()
self.output_path.mkdir(parents=True, exist_ok=True)
(self.output_path / "pygments.css").write_text(
+10
View File
@@ -13,9 +13,19 @@ dependencies = [
"PyYAML",
]
[project.optional-dependencies]
dev = [
"mypy",
"types-PyYAML",
"types-Pygments",
]
[project.scripts]
ossg = "omicron.ssg.cli:main"
[tool.mypy]
strict = true
[tool.setuptools.packages.find]
where = ["."]
include = ["omicron.ssg*"]