@@ -0,0 +1,70 @@
|
||||
"""Section-scoped and continuous object numbering."""
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
APPENDIX_LETTERS = "АБВГДЕЖИКЛМНПРСТУФХЦШЩЭЮЯ" # without Ё З Й О Ч Ь Ы Ъ
|
||||
|
||||
|
||||
class Numberer:
|
||||
"""Assigns object numbers.
|
||||
|
||||
* ``section`` (MIREA): ``1.1``, ``2.3`` or ``Б.1`` — counters reset per section/appendix.
|
||||
* ``continuous`` (PIS_custom): ``1``, ``2``, ``3`` — сквозная нумерация по всему документу.
|
||||
"""
|
||||
|
||||
def __init__(self, mode: str = "section"):
|
||||
if mode not in ("section", "continuous"):
|
||||
raise ValueError(f"Unknown numbering mode: {mode!r}")
|
||||
self._mode = mode
|
||||
self._section: int = 0
|
||||
self._appendix: str | None = None
|
||||
self._counters: dict[str, int] = defaultdict(int)
|
||||
self._labels: dict[tuple[str, str], str] = {} # (category, unique_name) -> number string
|
||||
|
||||
@property
|
||||
def mode(self) -> str:
|
||||
return self._mode
|
||||
|
||||
@property
|
||||
def section(self) -> int:
|
||||
return self._section
|
||||
|
||||
@property
|
||||
def appendix(self) -> str | None:
|
||||
return self._appendix
|
||||
|
||||
def enter_section(self, section_number: int) -> None:
|
||||
"""Start a numbered chapter (Heading 1 numbered)."""
|
||||
self._section = section_number
|
||||
self._appendix = None
|
||||
if self._mode != "continuous":
|
||||
self._counters.clear()
|
||||
|
||||
def enter_appendix(self, letter: str) -> None:
|
||||
"""Start an appendix (letter А, Б, …)."""
|
||||
self._appendix = letter
|
||||
if self._mode != "continuous":
|
||||
self._counters.clear()
|
||||
|
||||
def next_number(self, category: str, unique_name: str | None = None) -> str:
|
||||
"""Allocate next number for category; optionally bind a label."""
|
||||
self._counters[category] += 1
|
||||
n = self._counters[category]
|
||||
if self._mode == "continuous":
|
||||
number = str(n)
|
||||
elif self._appendix:
|
||||
number = f"{self._appendix}.{n}"
|
||||
elif self._section:
|
||||
number = f"{self._section}.{n}"
|
||||
else:
|
||||
number = str(n)
|
||||
if unique_name:
|
||||
self._labels[(category, unique_name)] = number
|
||||
return number
|
||||
|
||||
def resolve(self, category: str, unique_name: str) -> str | None:
|
||||
return self._labels.get((category, unique_name))
|
||||
|
||||
def register_label(self, category: str, unique_name: str, number: str) -> None:
|
||||
self._labels[(category, unique_name)] = number
|
||||
Reference in New Issue
Block a user