aeat.domain.manuals._loader module

File-backed loader and query API for aeat.domain.manuals.

The loader walks the corpus/manuals/ directory hierarchy and produces strictly-validated Manual, Chapter, and Section records. Tests exercise it against hand-crafted temporary-directory fixtures so the contract is locked for downstream extraction work that lands real chapter trees.

Directory shape per part root:

<part_root>/
    source.pdf           # git-ignored, raw binary
    manifest.json        # FetchedManualPart record (committed)
    structure/
        manual.json      # Manual metadata (without embedded chapters)
        chapters.json    # tuple[Chapter, ...] with SectionRef entries
        sections/<chapter-id>/<section-id>.json  # Section records

For IVA (ManualPart.SINGLE) the <part_root> is corpus/manuals/iva/<year>/; for Renta the part root is nested inside the canonical ManualPart directory value.

resolve_part_root(*, manual_id, year, part, settings=None)[source]

Return the on-disk root for a specific (manual_id, year, part).

Parameters:
  • manual_id (ManualId) – Handbook identifier.

  • year (int) – Tax year.

  • part (ManualPart) – Volume split. SINGLE flattens the directory layout.

  • settings (Settings | None) – Optional settings instance; loaded on demand otherwise.

Return type:

Path

Returns:

The canonical directory path (not guaranteed to exist).

load_manual(manual_id, year, part=ManualPart.SINGLE, *, settings=None)[source]

Load a single Manual from corpus/manuals/.

Parameters:
  • manual_id (ManualId) – Handbook identifier.

  • year (int) – Tax year.

  • part (ManualPart) – Volume split within the year. Defaults to SINGLE.

  • settings (Settings | None) – Optional settings instance; loaded on demand otherwise.

Return type:

Manual

Returns:

A fully validated Manual including its chapter tree (but not resolved section bodies — those are loaded lazily by load_section() or iterated by find_rules()).

Raises:

ManualNotFoundError – If the required metadata files are absent.

load_section(part_root, section_ref)[source]

Load a single Section by resolving section_ref on disk.

Parameters:
  • part_root (Path) – Directory root for the owning manual part.

  • section_ref (SectionRef) – Pointer returned by the owning Chapter.

Return type:

Section

Returns:

A fully validated Section record.

Raises:

ManualParseError – If the file path escapes the manual root or fails schema validation.

load_catalogue(specs, *, settings=None)[source]

Load every requested (manual_id, year, part) into a catalogue.

Parameters:
Return type:

ManualCatalogue

Returns:

A ManualCatalogue containing every successfully loaded Manual. Missing specifiers raise immediately; partial loads are not supported so the catalogue always reflects a coherent on-disk state.

iter_sections(manual, *, settings=None)[source]

Yield every Section belonging to manual, in tree order.

Parameters:
Yields:

Section records resolved from the chapter tree.

Return type:

Iterator[Section]

find_rules(catalogue, *, casilla_reference=None, kind=None, lang=None, settings=None)[source]

Iterate every Rule in catalogue matching the filters.

Parameters:
  • catalogue (ManualCatalogue) – A loaded ManualCatalogue.

  • casilla_reference (ManualCasillaReference | None) – Optional structured modelo/casilla filter. Rules whose references_casillas does not contain this value are skipped.

  • kind (Optional[Literal['computation', 'applicability', 'valuation', 'deductibility', 'formal_obligation', 'procedural', 'other']]) – Optional RuleKind filter.

  • lang (str | None) – Optional str filter. When provided, rules whose statement cannot be resolved into lang under the configured fallback policy are skipped.

  • settings (Settings | None) – Optional settings instance.

Yields:

Rule records matching every supplied filter.

Return type:

Iterator[Rule]