| from __future__ import annotations | |
| import re | |
| from typing import List | |
| from db.parsers.bsa.legal_models import Part | |
| class PartParser: | |
| """ | |
| Supports: | |
| PART I | |
| PRELIMINARY | |
| PART II | |
| RELEVANCY OF FACTS | |
| PART III | |
| FACTS WHICH NEED NOT BE PROVED | |
| """ | |
| # ========================================== | |
| # PART HEADER | |
| # ========================================== | |
| PART_RE = re.compile( | |
| r"(?im)^PART\s+([IVXLCDM0-9A-Z]+)\s*$" | |
| ) | |
| # ========================================== | |
| # EXTRACT PARTS | |
| # ========================================== | |
| def extract_parts( | |
| self, | |
| text: str | |
| ) -> List[Part]: | |
| matches = list( | |
| self.PART_RE.finditer( | |
| text | |
| ) | |
| ) | |
| if not matches: | |
| return [] | |
| parts = [] | |
| for i, match in enumerate( | |
| matches | |
| ): | |
| start = match.start() | |
| end = ( | |
| matches[i + 1].start() | |
| if i + 1 < len(matches) | |
| else len(text) | |
| ) | |
| block = ( | |
| text[start:end] | |
| .strip() | |
| ) | |
| lines = [ | |
| line.strip() | |
| for line in block.splitlines() | |
| if line.strip() | |
| ] | |
| part_no = ( | |
| match.group(1) | |
| ) | |
| title = "" | |
| if len(lines) >= 2: | |
| title = lines[1] | |
| parts.append( | |
| Part( | |
| document="bsa", | |
| part_no=part_no, | |
| title=title, | |
| text=block | |
| ) | |
| ) | |
| return parts | |
| # ========================================== | |
| # VALIDATION | |
| # ========================================== | |
| def validate_parts( | |
| self, | |
| parts: List[Part] | |
| ) -> List[str]: | |
| errors = [] | |
| seen = set() | |
| for part in parts: | |
| if part.part_no in seen: | |
| errors.append( | |
| f"Duplicate Part " | |
| f"{part.part_no}" | |
| ) | |
| seen.add( | |
| part.part_no | |
| ) | |
| if not part.title: | |
| errors.append( | |
| f"Part {part.part_no} " | |
| f"missing title" | |
| ) | |
| return errors | |
| if __name__ == "__main__": | |
| sample = """ | |
| PART I | |
| PRELIMINARY | |
| 1. Short title. | |
| PART II | |
| RELEVANCY OF FACTS | |
| 2. Evidence may be given. | |
| """ | |
| parser = PartParser() | |
| parts = parser.extract_parts( | |
| sample | |
| ) | |
| for part in parts: | |
| print( | |
| part.part_no, | |
| part.title | |
| ) |