Define bounded tabular source contracts

This commit is contained in:
2026-08-04 12:05:09 +02:00
parent 0c9bf6758c
commit 1974bf1a2b
4 changed files with 169 additions and 1 deletions
+27
View File
@@ -9,6 +9,14 @@ from govoplan_core.core.external_references import (
SOURCE_AUTHORITY_MODES,
SourceAuthorityMode,
)
from govoplan_core.core.tabular_sources import (
DEFAULT_PREVIEW_BYTES,
DEFAULT_PREVIEW_TIMEOUT_MS,
TabularPreviewDiagnostic,
TabularPushdown,
TabularSourceHealth,
TabularSourceMode,
)
CAPABILITY_DATASOURCE_CATALOGUE = "datasources.catalogue"
@@ -265,6 +273,8 @@ class DatasourceReadRequest:
offset: int = 0
columns: tuple[str, ...] = ()
expected_fingerprint: str | None = None
max_bytes: int = DEFAULT_PREVIEW_BYTES
timeout_ms: int = DEFAULT_PREVIEW_TIMEOUT_MS
@dataclass(frozen=True, slots=True)
@@ -274,6 +284,12 @@ class DatasourceReadResult:
total_rows: int
truncated: bool
materialization: DatasourceMaterialization | None = None
returned_bytes: int = 0
elapsed_ms: int = 0
effective_row_limit: int = 0
effective_byte_limit: int = 0
effective_timeout_ms: int = 0
diagnostics: tuple[TabularPreviewDiagnostic, ...] = ()
@dataclass(frozen=True, slots=True)
@@ -339,6 +355,9 @@ class DatasourceOrigin:
updated_at: datetime | None = None
capabilities: tuple[str, ...] = ("read",)
metadata: Mapping[str, object] = field(default_factory=dict)
source_mode: TabularSourceMode = "cached"
pushdown: TabularPushdown = field(default_factory=TabularPushdown)
health: TabularSourceHealth = field(default_factory=TabularSourceHealth)
@dataclass(frozen=True, slots=True)
@@ -348,6 +367,8 @@ class DatasourceOriginReadRequest:
offset: int = 0
columns: tuple[str, ...] = ()
expected_fingerprint: str | None = None
max_bytes: int = DEFAULT_PREVIEW_BYTES
timeout_ms: int = DEFAULT_PREVIEW_TIMEOUT_MS
@dataclass(frozen=True, slots=True)
@@ -356,6 +377,12 @@ class DatasourceOriginReadResult:
rows: tuple[Mapping[str, object], ...]
total_rows: int
truncated: bool
returned_bytes: int = 0
elapsed_ms: int = 0
effective_row_limit: int = 0
effective_byte_limit: int = 0
effective_timeout_ms: int = 0
diagnostics: tuple[TabularPreviewDiagnostic, ...] = ()
@runtime_checkable
+55 -1
View File
@@ -6,11 +6,17 @@ import re
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field
from datetime import datetime
from typing import Protocol, runtime_checkable
from typing import Literal, Protocol, runtime_checkable
CAPABILITY_CONNECTORS_TABULAR_SOURCES = "connectors.tabularSources"
CAPABILITY_CONNECTORS_TABULAR_SNAPSHOT_WRITER = "connectors.tabularSnapshotWriter"
DEFAULT_PREVIEW_BYTES = 1_000_000
DEFAULT_PREVIEW_TIMEOUT_MS = 2_000
TabularSourceMode = Literal["live", "cached", "file_backed", "static"]
TabularHealthStatus = Literal["healthy", "warning", "error", "unknown"]
TabularDiagnosticSeverity = Literal["info", "warning", "error"]
class TabularSourceError(ValueError):
@@ -29,6 +35,10 @@ class TabularSourceValidationError(TabularSourceError):
pass
class TabularSourceUnavailableError(TabularSourceError):
pass
def parse_tabular_csv(
csv_text: str,
*,
@@ -131,6 +141,32 @@ class TabularColumn:
nullable: bool = True
@dataclass(frozen=True, slots=True)
class TabularPushdown:
projections: bool = False
pagination: bool = False
filters: tuple[str, ...] = ()
aggregations: tuple[str, ...] = ()
sorting: tuple[str, ...] = ()
@dataclass(frozen=True, slots=True)
class TabularSourceHealth:
status: TabularHealthStatus = "unknown"
code: str = "source.health_unknown"
summary: str = "Source health has not been checked."
checked_at: datetime | None = None
details: Mapping[str, object] = field(default_factory=dict)
@dataclass(frozen=True, slots=True)
class TabularPreviewDiagnostic:
severity: TabularDiagnosticSeverity
code: str
message: str
details: Mapping[str, object] = field(default_factory=dict)
@dataclass(frozen=True, slots=True)
class TabularSource:
"""Opaque, policy-filtered source reference exposed to consuming modules."""
@@ -148,6 +184,9 @@ class TabularSource:
updated_at: datetime | None = None
capabilities: tuple[str, ...] = ("read",)
metadata: Mapping[str, object] = field(default_factory=dict)
source_mode: TabularSourceMode = "cached"
pushdown: TabularPushdown = field(default_factory=TabularPushdown)
health: TabularSourceHealth = field(default_factory=TabularSourceHealth)
@dataclass(frozen=True, slots=True)
@@ -157,6 +196,8 @@ class TabularReadRequest:
offset: int = 0
columns: tuple[str, ...] = ()
expected_fingerprint: str | None = None
max_bytes: int = DEFAULT_PREVIEW_BYTES
timeout_ms: int = DEFAULT_PREVIEW_TIMEOUT_MS
@dataclass(frozen=True, slots=True)
@@ -165,6 +206,12 @@ class TabularReadResult:
rows: tuple[Mapping[str, object], ...]
total_rows: int
truncated: bool
returned_bytes: int = 0
elapsed_ms: int = 0
effective_row_limit: int = 0
effective_byte_limit: int = 0
effective_timeout_ms: int = 0
diagnostics: tuple[TabularPreviewDiagnostic, ...] = ()
@dataclass(frozen=True, slots=True)
@@ -247,7 +294,11 @@ def _capability(registry: object | None, name: str) -> object | None:
__all__ = [
"CAPABILITY_CONNECTORS_TABULAR_SNAPSHOT_WRITER",
"CAPABILITY_CONNECTORS_TABULAR_SOURCES",
"DEFAULT_PREVIEW_BYTES",
"DEFAULT_PREVIEW_TIMEOUT_MS",
"TabularColumn",
"TabularPreviewDiagnostic",
"TabularPushdown",
"TabularReadRequest",
"TabularReadResult",
"TabularSnapshotInput",
@@ -257,6 +308,9 @@ __all__ = [
"TabularSourceError",
"TabularSourceNotFoundError",
"TabularSourceProvider",
"TabularSourceHealth",
"TabularSourceMode",
"TabularSourceUnavailableError",
"TabularSourceValidationError",
"parse_tabular_csv",
"tabular_snapshot_writer",