Source code for cadrumo.adapters.outbound.aeat.sede._declarations_diagnostics

"""Diagnostics helpers for the declarations register walker."""

from __future__ import annotations

from .....core.hashing import sha256_hex
from .._html import parse_html
from .._playwright import Page, PlaywrightError
from ._adapter_utils import bounded_text, normalize_response_text, redacted_url
from ._declarations_listbox import NO_RESULTS_TEXT, _has_class


[docs] async def declarations_page_shape_context_from_page( page: Page, *, stage: str, modelo: str | None = None, ejercicio: int | None = None, ) -> dict[str, object]: try: html = await page.content() except PlaywrightError: html = "" return declarations_page_shape_context( html, landing_url=getattr(page, "url", "") or "", stage=stage, modelo=modelo, ejercicio=ejercicio, )
[docs] def declarations_page_shape_context( html: str, *, landing_url: str, stage: str, modelo: str | None = None, ejercicio: int | None = None, ) -> dict[str, object]: """Project one register page's observable shape into a diagnostic context. ``modelo`` and ``ejercicio`` are optional because the availability reader navigates the same form with no pair in hand. They are reported as ``None`` rather than as a placeholder, so a diagnostic never states a pair the caller was not querying. """ from bs4 import Tag soup = parse_html(html) normalized_text = normalize_response_text(soup.get_text(" ", strip=True)) buttons = tuple(bounded_text(button.get_text(" ", strip=True)) for button in soup.find_all("button")[:12]) headers = tuple( bounded_text(header.get_text(" ", strip=True)) for header in soup.find_all(class_=_has_class("z-listheader"))[:12] ) _title_tag = soup.find("title") _title_text = bounded_text(_title_tag.get_text(" ", strip=True)) if isinstance(_title_tag, Tag) else "" return { "stage": stage, "modelo": modelo, "ejercicio": ejercicio, "landing_url": redacted_url(landing_url), "title": _title_text, "has_modelo_label": "modelo (*)" in normalized_text, "has_ejercicio_label": "ejercicio (*)" in normalized_text, "has_buscar_button": any(button.casefold() == "buscar" for button in buttons), "has_no_results_text": normalize_response_text(NO_RESULTS_TEXT) in normalized_text, "listbox_count": len(soup.find_all(class_=_has_class("z-listbox"))), "listitem_count": len(soup.find_all(class_=_has_class("z-listitem"))), "comboitem_count": len(soup.find_all(class_=_has_class("z-comboitem"))), "table_count": len(soup.find_all("table")), "form_count": len(soup.find_all("form")), "buttons": buttons, "list_headers": headers, "raw_sha256": sha256_hex(html.encode("utf-8")), }
__all__ = [ "declarations_page_shape_context", "declarations_page_shape_context_from_page", ]