agentic-data-contracts 0.2.3__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/CHANGELOG.md +8 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/PKG-INFO +4 -2
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/README.md +3 -1
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/pyproject.toml +1 -1
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/adapters/base.py +1 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/adapters/duckdb.py +12 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/core/contract.py +18 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/tools/factory.py +9 -0
- agentic_data_contracts-0.2.4/tests/test_core/test_wildcard_tables.py +106 -0
- agentic_data_contracts-0.2.4/tests/test_tools/test_wildcard_tools.py +76 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/uv.lock +1 -1
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/.github/dependabot.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/.github/workflows/ci.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/.gitignore +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/.pre-commit-config.yaml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/.python-version +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/CLAUDE.md +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/LICENSE +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/docs/architecture.md +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/agent.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/contract.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/semantic.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/setup_db.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/adapters/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/bridge/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/bridge/compiler.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/core/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/core/schema.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/core/session.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/py.typed +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/semantic/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/semantic/base.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/semantic/cube.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/semantic/dbt.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/semantic/yaml_source.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/tools/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/tools/middleware.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/tools/sdk.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/validation/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/validation/checkers.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/validation/explain.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/validation/validator.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/conftest.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/minimal_contract.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/sample_cube_schema.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/sample_dbt_manifest.json +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/semantic_source.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/valid_contract.yml +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_adapters/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_adapters/test_duckdb.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_bridge/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_bridge/test_compiler.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_contract.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_load_semantic_source.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_schema.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_sdk_config.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_session.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_system_prompt_metrics.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_public_api.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/test_cube.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/test_dbt.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/test_search.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/test_yaml_source.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_auto_load.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_factory.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_middleware.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_sdk.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_semantic_tools.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_validation/__init__.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_validation/test_checkers.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_validation/test_explain.py +0 -0
- {agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_validation/test_validator.py +0 -0
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.4] - 2026-03-29
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Wildcard table support**: Use `tables: ["*"]` in `allowed_tables` to allow all tables in a schema, discovered from the database at runtime via `adapter.list_tables()`
|
|
10
|
+
- **`DataContract.resolve_tables(adapter)`**: Expands wildcard entries using the database adapter; called automatically by `create_tools()` when an adapter is provided
|
|
11
|
+
- **`DatabaseAdapter.list_tables(schema)`**: New protocol method for listing tables in a schema; implemented in `DuckDBAdapter` via `information_schema.tables`
|
|
12
|
+
|
|
5
13
|
## [0.2.3] - 2026-03-29
|
|
6
14
|
|
|
7
15
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-data-contracts
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: YAML-first data contract governance for AI agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/flyersworder/agentic-data-contracts
|
|
6
6
|
Project-URL: Repository, https://github.com/flyersworder/agentic-data-contracts
|
|
@@ -117,7 +117,9 @@ semantic:
|
|
|
117
117
|
path: "./semantic.yml"
|
|
118
118
|
allowed_tables:
|
|
119
119
|
- schema: analytics
|
|
120
|
-
tables: [
|
|
120
|
+
tables: ["*"] # all tables in schema (discovered from database)
|
|
121
|
+
- schema: marketing
|
|
122
|
+
tables: [campaigns] # or list specific tables
|
|
121
123
|
forbidden_operations: [DELETE, DROP, TRUNCATE, UPDATE, INSERT]
|
|
122
124
|
rules:
|
|
123
125
|
- name: tenant_isolation
|
|
@@ -64,7 +64,9 @@ semantic:
|
|
|
64
64
|
path: "./semantic.yml"
|
|
65
65
|
allowed_tables:
|
|
66
66
|
- schema: analytics
|
|
67
|
-
tables: [
|
|
67
|
+
tables: ["*"] # all tables in schema (discovered from database)
|
|
68
|
+
- schema: marketing
|
|
69
|
+
tables: [campaigns] # or list specific tables
|
|
68
70
|
forbidden_operations: [DELETE, DROP, TRUNCATE, UPDATE, INSERT]
|
|
69
71
|
rules:
|
|
70
72
|
- name: tenant_isolation
|
|
@@ -37,6 +37,7 @@ class DatabaseAdapter(Protocol):
|
|
|
37
37
|
def execute(self, sql: str) -> QueryResult: ...
|
|
38
38
|
def explain(self, sql: str) -> ExplainResult: ...
|
|
39
39
|
def describe_table(self, schema: str, table: str) -> TableSchema: ...
|
|
40
|
+
def list_tables(self, schema: str) -> list[str]: ...
|
|
40
41
|
|
|
41
42
|
@property
|
|
42
43
|
def dialect(self) -> str: ...
|
|
@@ -59,6 +59,18 @@ class DuckDBAdapter:
|
|
|
59
59
|
last_estimate = int(match.group(1))
|
|
60
60
|
return last_estimate
|
|
61
61
|
|
|
62
|
+
def list_tables(self, schema: str) -> list[str]:
|
|
63
|
+
rows = self.connection.execute(
|
|
64
|
+
"""
|
|
65
|
+
SELECT table_name
|
|
66
|
+
FROM information_schema.tables
|
|
67
|
+
WHERE table_schema = ?
|
|
68
|
+
ORDER BY table_name
|
|
69
|
+
""",
|
|
70
|
+
[schema],
|
|
71
|
+
).fetchall()
|
|
72
|
+
return [row[0] for row in rows]
|
|
73
|
+
|
|
62
74
|
def describe_table(self, schema: str, table: str) -> TableSchema:
|
|
63
75
|
rows = self.connection.execute(
|
|
64
76
|
"""
|
|
@@ -14,6 +14,7 @@ from agentic_data_contracts.core.schema import (
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
|
+
from agentic_data_contracts.adapters.base import DatabaseAdapter
|
|
17
18
|
from agentic_data_contracts.semantic.base import SemanticSource
|
|
18
19
|
|
|
19
20
|
|
|
@@ -38,10 +39,27 @@ class DataContract:
|
|
|
38
39
|
schema = DataContractSchema.model_validate(raw)
|
|
39
40
|
return cls(schema=schema)
|
|
40
41
|
|
|
42
|
+
def has_wildcard_tables(self) -> bool:
|
|
43
|
+
"""Check if any schema uses wildcard ('*') for tables."""
|
|
44
|
+
return any("*" in entry.tables for entry in self.schema.semantic.allowed_tables)
|
|
45
|
+
|
|
46
|
+
def resolve_tables(self, adapter: DatabaseAdapter) -> None:
|
|
47
|
+
"""Expand wildcard tables using the database adapter.
|
|
48
|
+
|
|
49
|
+
Replaces ["*"] entries with actual table names from the database.
|
|
50
|
+
Call this once after creating the adapter. Results are cached
|
|
51
|
+
on the schema object.
|
|
52
|
+
"""
|
|
53
|
+
for entry in self.schema.semantic.allowed_tables:
|
|
54
|
+
if "*" in entry.tables:
|
|
55
|
+
entry.tables = adapter.list_tables(entry.schema_)
|
|
56
|
+
|
|
41
57
|
def allowed_table_names(self) -> list[str]:
|
|
42
58
|
names: list[str] = []
|
|
43
59
|
for entry in self.schema.semantic.allowed_tables:
|
|
44
60
|
for table in entry.tables:
|
|
61
|
+
if table == "*":
|
|
62
|
+
continue # unresolved wildcard — skip
|
|
45
63
|
names.append(f"{entry.schema_}.{table}")
|
|
46
64
|
return names
|
|
47
65
|
|
|
@@ -41,6 +41,10 @@ def create_tools(
|
|
|
41
41
|
if semantic_source is None:
|
|
42
42
|
semantic_source = contract.load_semantic_source()
|
|
43
43
|
|
|
44
|
+
# Resolve wildcard tables if adapter is available
|
|
45
|
+
if adapter is not None and contract.has_wildcard_tables():
|
|
46
|
+
contract.resolve_tables(adapter)
|
|
47
|
+
|
|
44
48
|
dialect = adapter.dialect if adapter else None
|
|
45
49
|
validator = Validator(contract, dialect=dialect, explain_adapter=adapter)
|
|
46
50
|
|
|
@@ -60,6 +64,11 @@ def create_tools(
|
|
|
60
64
|
for entry in contract.schema.semantic.allowed_tables:
|
|
61
65
|
if schema_filter and entry.schema_ != schema_filter:
|
|
62
66
|
continue
|
|
67
|
+
if "*" in entry.tables:
|
|
68
|
+
return _text_response(
|
|
69
|
+
f"Schema '{entry.schema_}' uses wildcard tables"
|
|
70
|
+
" but no database adapter is available to resolve them."
|
|
71
|
+
)
|
|
63
72
|
for table in entry.tables:
|
|
64
73
|
info: dict[str, Any] = {
|
|
65
74
|
"schema": entry.schema_,
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Tests for wildcard table support in allowed_tables."""
|
|
2
|
+
|
|
3
|
+
from agentic_data_contracts.adapters.duckdb import DuckDBAdapter
|
|
4
|
+
from agentic_data_contracts.core.contract import DataContract
|
|
5
|
+
from agentic_data_contracts.core.schema import (
|
|
6
|
+
AllowedTable,
|
|
7
|
+
DataContractSchema,
|
|
8
|
+
SemanticConfig,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _make_contract(tables_config: list[dict]) -> DataContract:
|
|
13
|
+
allowed = [AllowedTable.model_validate(t) for t in tables_config]
|
|
14
|
+
schema = DataContractSchema(
|
|
15
|
+
name="test",
|
|
16
|
+
semantic=SemanticConfig(allowed_tables=allowed),
|
|
17
|
+
)
|
|
18
|
+
return DataContract(schema)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _make_adapter() -> DuckDBAdapter:
|
|
22
|
+
db = DuckDBAdapter(":memory:")
|
|
23
|
+
db.connection.execute("""
|
|
24
|
+
CREATE SCHEMA IF NOT EXISTS analytics;
|
|
25
|
+
CREATE TABLE analytics.orders (id INTEGER);
|
|
26
|
+
CREATE TABLE analytics.customers (id INTEGER);
|
|
27
|
+
CREATE TABLE analytics.products (id INTEGER);
|
|
28
|
+
CREATE SCHEMA IF NOT EXISTS raw;
|
|
29
|
+
CREATE TABLE raw.events (id INTEGER);
|
|
30
|
+
""")
|
|
31
|
+
return db
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_has_wildcard_tables_true() -> None:
|
|
35
|
+
dc = _make_contract([{"schema": "analytics", "tables": ["*"]}])
|
|
36
|
+
assert dc.has_wildcard_tables()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_has_wildcard_tables_false() -> None:
|
|
40
|
+
dc = _make_contract(
|
|
41
|
+
[
|
|
42
|
+
{"schema": "analytics", "tables": ["orders"]},
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
assert not dc.has_wildcard_tables()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_resolve_tables_expands_wildcard() -> None:
|
|
49
|
+
dc = _make_contract([{"schema": "analytics", "tables": ["*"]}])
|
|
50
|
+
adapter = _make_adapter()
|
|
51
|
+
dc.resolve_tables(adapter)
|
|
52
|
+
|
|
53
|
+
names = dc.allowed_table_names()
|
|
54
|
+
assert "analytics.orders" in names
|
|
55
|
+
assert "analytics.customers" in names
|
|
56
|
+
assert "analytics.products" in names
|
|
57
|
+
assert not any(n.startswith("raw.") for n in names)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_resolve_tables_mixed() -> None:
|
|
61
|
+
dc = _make_contract(
|
|
62
|
+
[
|
|
63
|
+
{"schema": "analytics", "tables": ["*"]},
|
|
64
|
+
{"schema": "raw", "tables": []},
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
adapter = _make_adapter()
|
|
68
|
+
dc.resolve_tables(adapter)
|
|
69
|
+
|
|
70
|
+
names = dc.allowed_table_names()
|
|
71
|
+
assert "analytics.orders" in names
|
|
72
|
+
assert not any(n.startswith("raw.") for n in names)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_resolve_tables_preserves_explicit() -> None:
|
|
76
|
+
dc = _make_contract(
|
|
77
|
+
[
|
|
78
|
+
{"schema": "analytics", "tables": ["orders"]},
|
|
79
|
+
]
|
|
80
|
+
)
|
|
81
|
+
adapter = _make_adapter()
|
|
82
|
+
dc.resolve_tables(adapter)
|
|
83
|
+
|
|
84
|
+
names = dc.allowed_table_names()
|
|
85
|
+
assert names == ["analytics.orders"]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_unresolved_wildcard_skipped() -> None:
|
|
89
|
+
dc = _make_contract([{"schema": "analytics", "tables": ["*"]}])
|
|
90
|
+
# Without calling resolve_tables, wildcard is skipped
|
|
91
|
+
names = dc.allowed_table_names()
|
|
92
|
+
assert names == []
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_adapter_list_tables() -> None:
|
|
96
|
+
adapter = _make_adapter()
|
|
97
|
+
tables = adapter.list_tables("analytics")
|
|
98
|
+
assert "orders" in tables
|
|
99
|
+
assert "customers" in tables
|
|
100
|
+
assert "products" in tables
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_adapter_list_tables_empty_schema() -> None:
|
|
104
|
+
adapter = _make_adapter()
|
|
105
|
+
tables = adapter.list_tables("nonexistent")
|
|
106
|
+
assert tables == []
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Tests for tools with wildcard table resolution."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from agentic_data_contracts.adapters.duckdb import DuckDBAdapter
|
|
8
|
+
from agentic_data_contracts.core.contract import DataContract
|
|
9
|
+
from agentic_data_contracts.core.schema import (
|
|
10
|
+
AllowedTable,
|
|
11
|
+
DataContractSchema,
|
|
12
|
+
SemanticConfig,
|
|
13
|
+
)
|
|
14
|
+
from agentic_data_contracts.tools.factory import create_tools
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def adapter() -> DuckDBAdapter:
|
|
19
|
+
db = DuckDBAdapter(":memory:")
|
|
20
|
+
db.connection.execute("""
|
|
21
|
+
CREATE SCHEMA IF NOT EXISTS analytics;
|
|
22
|
+
CREATE TABLE analytics.orders (id INTEGER, amount DECIMAL);
|
|
23
|
+
CREATE TABLE analytics.customers (id INTEGER, name VARCHAR);
|
|
24
|
+
INSERT INTO analytics.orders VALUES (1, 100.00);
|
|
25
|
+
""")
|
|
26
|
+
return db
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
def wildcard_contract() -> DataContract:
|
|
31
|
+
schema = DataContractSchema(
|
|
32
|
+
name="test",
|
|
33
|
+
semantic=SemanticConfig(
|
|
34
|
+
allowed_tables=[
|
|
35
|
+
AllowedTable.model_validate({"schema": "analytics", "tables": ["*"]}),
|
|
36
|
+
],
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
return DataContract(schema)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.mark.asyncio
|
|
43
|
+
async def test_list_tables_after_wildcard_resolve(
|
|
44
|
+
wildcard_contract: DataContract, adapter: DuckDBAdapter
|
|
45
|
+
) -> None:
|
|
46
|
+
tools = create_tools(wildcard_contract, adapter=adapter)
|
|
47
|
+
tool = next(t for t in tools if t.name == "list_tables")
|
|
48
|
+
result = await tool.callable({})
|
|
49
|
+
text = result["content"][0]["text"]
|
|
50
|
+
data = json.loads(text)
|
|
51
|
+
table_names = [t["table"] for t in data["tables"]]
|
|
52
|
+
assert "orders" in table_names
|
|
53
|
+
assert "customers" in table_names
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@pytest.mark.asyncio
|
|
57
|
+
async def test_run_query_with_wildcard_tables(
|
|
58
|
+
wildcard_contract: DataContract, adapter: DuckDBAdapter
|
|
59
|
+
) -> None:
|
|
60
|
+
tools = create_tools(wildcard_contract, adapter=adapter)
|
|
61
|
+
tool = next(t for t in tools if t.name == "run_query")
|
|
62
|
+
result = await tool.callable({"sql": "SELECT id, amount FROM analytics.orders"})
|
|
63
|
+
text = result["content"][0]["text"]
|
|
64
|
+
assert "100" in text
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.mark.asyncio
|
|
68
|
+
async def test_validate_query_with_wildcard_tables(
|
|
69
|
+
wildcard_contract: DataContract, adapter: DuckDBAdapter
|
|
70
|
+
) -> None:
|
|
71
|
+
tools = create_tools(wildcard_contract, adapter=adapter)
|
|
72
|
+
tool = next(t for t in tools if t.name == "validate_query")
|
|
73
|
+
# analytics.orders should be allowed after wildcard resolution
|
|
74
|
+
result = await tool.callable({"sql": "SELECT id FROM analytics.orders"})
|
|
75
|
+
text = result["content"][0]["text"]
|
|
76
|
+
assert "valid" in text.lower()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/agent.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/contract.yml
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/semantic.yml
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/examples/revenue_agent/setup_db.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/src/agentic_data_contracts/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/minimal_contract.yml
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/sample_cube_schema.yml
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/semantic_source.yml
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/fixtures/valid_contract.yml
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_adapters/__init__.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_adapters/test_duckdb.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_bridge/test_compiler.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_schema.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_sdk_config.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_core/test_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/__init__.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/test_cube.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/test_dbt.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_semantic/test_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_auto_load.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_factory.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_tools/test_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_validation/__init__.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_validation/test_checkers.py
RENAMED
|
File without changes
|
{agentic_data_contracts-0.2.3 → agentic_data_contracts-0.2.4}/tests/test_validation/test_explain.py
RENAMED
|
File without changes
|
|
File without changes
|