from __future__ import annotations from collections.abc import Mapping from dataclasses import dataclass, field from datetime import datetime from typing import Protocol, runtime_checkable CAPABILITY_REPORTING_REGISTRY = "reporting.registry" CAPABILITY_REPORTING_RUNNER = "reporting.runner" CAPABILITY_REPORTING_SCHEDULER = "reporting.scheduler" CAPABILITY_REPORTING_CHART_RENDERER = "reporting.chart_renderer" CAPABILITY_REPORTING_PUBLICATION_FILES = "reporting.publication.files" CAPABILITY_REPORTING_PUBLICATION_MAIL = "reporting.publication.mail" @dataclass(frozen=True, slots=True) class ReportingDatasetReadRequest: source_ref: str source_revision: int | None parameters: Mapping[str, object] = field(default_factory=dict) row_limit: int = 2_000 expected_definition_hash: str | None = None expected_source_fingerprints: tuple[Mapping[str, object], ...] = () @dataclass(frozen=True, slots=True) class ReportingDatasetReadResult: rows: tuple[Mapping[str, object], ...] total_rows: int truncated: bool output_hash: str executor_version: str definition_hash: str | None = None source_fingerprints: tuple[Mapping[str, object], ...] = () diagnostics: tuple[Mapping[str, object], ...] = () generated_at: datetime | None = None provenance: Mapping[str, object] = field(default_factory=dict) @runtime_checkable class ReportingReadModelProvider(Protocol): def read_dataset( self, session: object, principal: object, *, request: ReportingDatasetReadRequest, ) -> ReportingDatasetReadResult: ... @dataclass(frozen=True, slots=True) class ReportingRowPolicyRequest: dataset_id: str dataset_revision: int policy_ref: str rows: tuple[Mapping[str, object], ...] @dataclass(frozen=True, slots=True) class ReportingRowPolicyResult: rows: tuple[Mapping[str, object], ...] decision_ref: str provenance: Mapping[str, object] = field(default_factory=dict) @runtime_checkable class ReportingRowPolicyProvider(Protocol): def authorize_rows( self, session: object, principal: object, *, request: ReportingRowPolicyRequest, ) -> ReportingRowPolicyResult: ... @dataclass(frozen=True, slots=True) class ReportingPublicationPayload: publication_id: str execution_id: str tenant_id: str report_id: str report_revision: int format: str target_ref: str | None rows: tuple[Mapping[str, object], ...] schema: tuple[Mapping[str, object], ...] output_hash: str options: Mapping[str, object] = field(default_factory=dict) @runtime_checkable class ReportingPublicationTarget(Protocol): def publish_report( self, session: object, principal: object, *, payload: ReportingPublicationPayload, ) -> Mapping[str, object]: ... @runtime_checkable class ReportingChartRenderer(Protocol): def render( self, *, visualization: object, result: object ) -> Mapping[str, object]: ... def capability(registry: object | None, name: str) -> object | None: if ( registry is None or not hasattr(registry, "has_capability") or not hasattr(registry, "capability") or not registry.has_capability(name) ): return None return registry.capability(name) __all__ = [ "CAPABILITY_REPORTING_CHART_RENDERER", "CAPABILITY_REPORTING_PUBLICATION_FILES", "CAPABILITY_REPORTING_PUBLICATION_MAIL", "CAPABILITY_REPORTING_REGISTRY", "CAPABILITY_REPORTING_RUNNER", "CAPABILITY_REPORTING_SCHEDULER", "ReportingChartRenderer", "ReportingDatasetReadRequest", "ReportingDatasetReadResult", "ReportingPublicationPayload", "ReportingPublicationTarget", "ReportingReadModelProvider", "ReportingRowPolicyProvider", "ReportingRowPolicyRequest", "ReportingRowPolicyResult", "capability", ]