-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodel.py
More file actions
64 lines (53 loc) Β· 2.17 KB
/
Copy pathmodel.py
File metadata and controls
64 lines (53 loc) Β· 2.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"""The in-memory representation of one error document."""
from __future__ import annotations
import re
from dataclasses import asdict, dataclass, field
from pathlib import Path
from .frontmatter import split_frontmatter
_SECTION_RE = re.compile(r"^##\s+(.+?)\s*$", re.MULTILINE)
@dataclass
class ErrorDoc:
"""A single parsed error document and its searchable fields."""
path: str
slug: str
title: str
technologies: list[str] = field(default_factory=list)
severity: str = "medium"
tags: list[str] = field(default_factory=list)
related: list[str] = field(default_factory=list)
message: str = ""
text: str = ""
@classmethod
def from_file(cls, path: str | Path, root: str | Path | None = None) -> ErrorDoc:
"""Load and parse an error document from disk."""
path = Path(path)
content = path.read_text(encoding="utf-8")
meta, body = split_frontmatter(content)
sections = _split_sections(body)
rel = str(path.relative_to(root)) if root else str(path)
return cls(
path=rel,
slug=str(meta.get("slug") or path.stem),
title=str(meta.get("title") or path.stem),
technologies=[str(t) for t in meta.get("technologies", [])],
severity=str(meta.get("severity", "medium")),
tags=[str(t).lower() for t in meta.get("tags", [])],
related=[str(r) for r in meta.get("related", [])],
message=sections.get("error message", "").strip(),
text=body.lower(),
)
def to_dict(self) -> dict[str, object]:
"""Return a JSON-serializable mapping (without the full body text)."""
data = asdict(self)
data.pop("text", None)
return data
def _split_sections(body: str) -> dict[str, str]:
"""Return a mapping of lowercased H2 heading -> section text."""
sections: dict[str, str] = {}
matches = list(_SECTION_RE.finditer(body))
for i, match in enumerate(matches):
name = match.group(1).strip().lower()
start = match.end()
end = matches[i + 1].start() if i + 1 < len(matches) else len(body)
sections[name] = body[start:end].strip()
return sections