modm_data.html.chapter
1# Copyright 2022, Niklas Hauser 2# SPDX-License-Identifier: MPL-2.0 3 4import re 5import logging 6from pathlib import Path 7from functools import cached_property 8from .parser import Parser 9from .table import Table 10from .text import Heading, Text 11 12LOGGER = logging.getLogger(__name__) 13 14 15class Chapter: 16 def __init__(self, path: str): 17 self._path = Path(path) 18 19 @cached_property 20 def _parser(self): 21 parser = Parser() 22 parser.feed(self._path.read_text()) 23 return parser 24 25 @property 26 def _relpath(self) -> str: 27 return self._path.relative_to(Path().cwd()) 28 29 @property 30 def name(self) -> str: 31 return self._path.stem.replace("_", " ") 32 33 @property 34 def number(self) -> int: 35 return int(self._path.stem.split("_")[1]) 36 37 @property 38 def items(self) -> list: 39 return self._parser._items 40 41 def headings(self) -> list[str]: 42 return [h for h in self.items if isinstance(h, Heading)] 43 44 def texts(self) -> list[str]: 45 return [t for t in self.items if isinstance(t, Text)] 46 47 def _heading_objects(self, obj_type, pattern, **subs) -> list: 48 heading_texts = [] 49 current = [None, []] 50 for item in self.items: 51 if isinstance(item, Heading): 52 if current[1]: 53 heading_texts.append(tuple(current)) 54 current = [item, []] 55 elif isinstance(item, obj_type): 56 current[1].append(item) 57 if current[1]: 58 heading_texts.append(tuple(current)) 59 if pattern is None: return heading_texts 60 return [ht for ht in heading_texts if re.search(pattern, 61 ht[0].text(**subs) if ht[0] is not None else "", re.IGNORECASE)] 62 63 def heading_texts(self, pattern=None, **subs) -> list: 64 return self._heading_objects(Text, pattern, **subs) 65 66 def heading_tables(self, pattern=None, **subs) -> list: 67 return self._heading_objects(Table, pattern, **subs) 68 69 def tables(self, pattern: str = None, **subs) -> list[Table]: 70 tables = [t for t in self.items if isinstance(t, Table)] 71 if pattern is None: return tables 72 return [t for t in tables if re.search(pattern, t.caption(**subs), re.IGNORECASE)] 73 74 def table(self, pattern: str) -> Table: 75 tables = self.tables(pattern) 76 if len(tables) == 0: 77 LOGGER.error(f"Cannot find table with pattern '{pattern}'!") 78 if len(tables) > 1: 79 LOGGER.error(f"Found multiple tables with pattern '{pattern}'!") 80 assert len(tables) == 1 81 return tables[0] 82 83 def __hash__(self) -> int: 84 return hash(self._path.stem) 85 86 def __eq__(self) -> int: 87 return hash(self._path.stem) 88 89 def __repr__(self) -> str: 90 return f"Chapter({self.name})"
LOGGER =
<Logger modm_data.html.chapter (WARNING)>
class
Chapter:
16class Chapter: 17 def __init__(self, path: str): 18 self._path = Path(path) 19 20 @cached_property 21 def _parser(self): 22 parser = Parser() 23 parser.feed(self._path.read_text()) 24 return parser 25 26 @property 27 def _relpath(self) -> str: 28 return self._path.relative_to(Path().cwd()) 29 30 @property 31 def name(self) -> str: 32 return self._path.stem.replace("_", " ") 33 34 @property 35 def number(self) -> int: 36 return int(self._path.stem.split("_")[1]) 37 38 @property 39 def items(self) -> list: 40 return self._parser._items 41 42 def headings(self) -> list[str]: 43 return [h for h in self.items if isinstance(h, Heading)] 44 45 def texts(self) -> list[str]: 46 return [t for t in self.items if isinstance(t, Text)] 47 48 def _heading_objects(self, obj_type, pattern, **subs) -> list: 49 heading_texts = [] 50 current = [None, []] 51 for item in self.items: 52 if isinstance(item, Heading): 53 if current[1]: 54 heading_texts.append(tuple(current)) 55 current = [item, []] 56 elif isinstance(item, obj_type): 57 current[1].append(item) 58 if current[1]: 59 heading_texts.append(tuple(current)) 60 if pattern is None: return heading_texts 61 return [ht for ht in heading_texts if re.search(pattern, 62 ht[0].text(**subs) if ht[0] is not None else "", re.IGNORECASE)] 63 64 def heading_texts(self, pattern=None, **subs) -> list: 65 return self._heading_objects(Text, pattern, **subs) 66 67 def heading_tables(self, pattern=None, **subs) -> list: 68 return self._heading_objects(Table, pattern, **subs) 69 70 def tables(self, pattern: str = None, **subs) -> list[Table]: 71 tables = [t for t in self.items if isinstance(t, Table)] 72 if pattern is None: return tables 73 return [t for t in tables if re.search(pattern, t.caption(**subs), re.IGNORECASE)] 74 75 def table(self, pattern: str) -> Table: 76 tables = self.tables(pattern) 77 if len(tables) == 0: 78 LOGGER.error(f"Cannot find table with pattern '{pattern}'!") 79 if len(tables) > 1: 80 LOGGER.error(f"Found multiple tables with pattern '{pattern}'!") 81 assert len(tables) == 1 82 return tables[0] 83 84 def __hash__(self) -> int: 85 return hash(self._path.stem) 86 87 def __eq__(self) -> int: 88 return hash(self._path.stem) 89 90 def __repr__(self) -> str: 91 return f"Chapter({self.name})"
75 def table(self, pattern: str) -> Table: 76 tables = self.tables(pattern) 77 if len(tables) == 0: 78 LOGGER.error(f"Cannot find table with pattern '{pattern}'!") 79 if len(tables) > 1: 80 LOGGER.error(f"Found multiple tables with pattern '{pattern}'!") 81 assert len(tables) == 1 82 return tables[0]