from dataclasses import dataclass, field def unquote(value: str) -> str: if value.startswith('"') and value.endswith('"'): return value[1:-1] else: return value @dataclass class FepFile: fep: str frontmatter: list[str] = field(default_factory=list) content: list[str] = field(default_factory=list) def __post_init__(self): with open(self.filename) as f: lines = f.readlines() status = 0 for line in lines: if line == "---\n" and status <= 2: status += 1 elif status == 1: self.frontmatter.append(line.removesuffix("\n")) elif status >= 2: self.content.append(line.removesuffix("\n")) @property def filename(self) -> str: return f"fep/{self.fep}/fep-{self.fep}.md" def find_section_by_name(self, name): result = [] is_summary = False for x in self.content: if is_summary: if x.startswith("##"): return "\n".join(result) result.append(x) elif x == f"## {name}": is_summary = True @property def summary(self): return self.find_section_by_name("Summary") def write(self): with open(self.filename, "w") as f: f.write("---\n") for x in self.frontmatter: f.write(x + "\n") f.write("---\n") for x in self.content: f.write(x + "\n") @property def parsed_frontmatter(self): split = [x.split(":", 1) for x in self.frontmatter] return {a: unquote(b.strip()) for a, b in split} @property def status(self): return self.parsed_frontmatter["status"] @property def title(self) -> str: titles = [x for x in self.content if x.startswith("# ")] assert len(titles) > 0 title = titles[0] begin_title = f"# FEP-{self.fep}: " assert title.startswith(begin_title) true_title = title.removeprefix(begin_title) return true_title @property def implementation_count(self): if self.parsed_frontmatter.get("type") != "implementation": return 0 implementations = [] in_section = False for line in self.content: if line.startswith("#") and "Implementations" in line: in_section = True elif in_section is True and line.startswith("#"): in_section = False elif in_section is True and (line.startswith("-") or line.startswith("*")): implementations.append(line) return len(implementations) @staticmethod def parsefile(f) -> tuple[list[str], list[str]]: lines = f.readlines() status = 0 frontmatter = [] content = [] for line in lines: if line == "---\n" and status <= 2: status += 1 elif status == 1: frontmatter.append(line.removesuffix("\n")) elif status >= 2: content.append(line.removesuffix("\n")) return frontmatter, content def frontmatter_table(self) -> str: keys = " | ".join(self.parsed_frontmatter.keys()) values = " | ".join(self.parsed_frontmatter.values()) divider = " | ".join(["---"] * len(self.parsed_frontmatter)) return f""" | {keys} | | {divider} | | {values} | """ def content_and_title(self) -> tuple[str, str]: for j, line in enumerate(self.content): if line.startswith("# "): return line, "\n".join(self.content[j + 1 :]) raise Exception("Could not determine title and content")