aptdata 0.0.2__py3-none-any.whl
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.
- aptdata/__init__.py +3 -0
- aptdata/cli/__init__.py +5 -0
- aptdata/cli/app.py +247 -0
- aptdata/cli/commands/__init__.py +9 -0
- aptdata/cli/commands/config_cmd.py +128 -0
- aptdata/cli/commands/mesh_cmd.py +435 -0
- aptdata/cli/commands/plugin_cmd.py +107 -0
- aptdata/cli/commands/system_cmd.py +90 -0
- aptdata/cli/commands/telemetry_cmd.py +57 -0
- aptdata/cli/completions.py +56 -0
- aptdata/cli/interactive.py +269 -0
- aptdata/cli/rendering/__init__.py +31 -0
- aptdata/cli/rendering/console.py +119 -0
- aptdata/cli/rendering/logger.py +26 -0
- aptdata/cli/rendering/panels.py +87 -0
- aptdata/cli/rendering/tables.py +81 -0
- aptdata/cli/scaffold.py +1089 -0
- aptdata/config/__init__.py +13 -0
- aptdata/config/parser.py +136 -0
- aptdata/config/schema.py +27 -0
- aptdata/config/secrets.py +60 -0
- aptdata/core/__init__.py +46 -0
- aptdata/core/context.py +31 -0
- aptdata/core/dataset.py +39 -0
- aptdata/core/lineage.py +213 -0
- aptdata/core/state.py +27 -0
- aptdata/core/system.py +317 -0
- aptdata/core/workflow.py +372 -0
- aptdata/mcp/__init__.py +5 -0
- aptdata/mcp/server.py +198 -0
- aptdata/plugins/__init__.py +77 -0
- aptdata/plugins/ai/__init__.py +6 -0
- aptdata/plugins/ai/chunking.py +66 -0
- aptdata/plugins/ai/embeddings.py +56 -0
- aptdata/plugins/base.py +57 -0
- aptdata/plugins/dataset.py +62 -0
- aptdata/plugins/governance/__init__.py +32 -0
- aptdata/plugins/governance/catalog.py +115 -0
- aptdata/plugins/governance/classification.py +44 -0
- aptdata/plugins/governance/lineage_store.py +49 -0
- aptdata/plugins/governance/rules.py +180 -0
- aptdata/plugins/local_fs.py +241 -0
- aptdata/plugins/manager.py +142 -0
- aptdata/plugins/postgres.py +113 -0
- aptdata/plugins/quality/__init__.py +39 -0
- aptdata/plugins/quality/contract.py +128 -0
- aptdata/plugins/quality/expectations.py +310 -0
- aptdata/plugins/quality/report.py +94 -0
- aptdata/plugins/quality/validator.py +139 -0
- aptdata/plugins/rest.py +135 -0
- aptdata/plugins/transform/__init__.py +14 -0
- aptdata/plugins/transform/pandas.py +129 -0
- aptdata/plugins/transform/spark.py +134 -0
- aptdata/plugins/vector/__init__.py +6 -0
- aptdata/plugins/vector/base.py +19 -0
- aptdata/plugins/vector/qdrant.py +41 -0
- aptdata/telemetry/__init__.py +5 -0
- aptdata/telemetry/instrumentation.py +164 -0
- aptdata/tui/__init__.py +5 -0
- aptdata/tui/monitor.py +279 -0
- aptdata-0.0.2.dist-info/METADATA +330 -0
- aptdata-0.0.2.dist-info/RECORD +65 -0
- aptdata-0.0.2.dist-info/WHEEL +4 -0
- aptdata-0.0.2.dist-info/entry_points.txt +3 -0
- aptdata-0.0.2.dist-info/licenses/LICENSE +21 -0
aptdata/__init__.py
ADDED
aptdata/cli/__init__.py
ADDED
aptdata/cli/app.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""Typer-based static CLI for aptdata.
|
|
2
|
+
|
|
3
|
+
Design goals
|
|
4
|
+
------------
|
|
5
|
+
* Machine / AI-readable: every outcome is emitted as a single JSON line on
|
|
6
|
+
stdout (success) or stderr (error).
|
|
7
|
+
* Exit codes: 0 = success, 1 = error.
|
|
8
|
+
* Self-documenting: Typer generates --help automatically from the docstrings
|
|
9
|
+
and type annotations.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import sys
|
|
16
|
+
import time
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
import typer
|
|
20
|
+
from opentelemetry import trace
|
|
21
|
+
|
|
22
|
+
from aptdata.cli.scaffold import scaffold
|
|
23
|
+
from aptdata.config.schema import write_domain_schema
|
|
24
|
+
|
|
25
|
+
app = typer.Typer(
|
|
26
|
+
name="aptdata",
|
|
27
|
+
help="Smart Data – declarative data-pipeline framework.",
|
|
28
|
+
add_completion=False,
|
|
29
|
+
)
|
|
30
|
+
schema_app = typer.Typer(help="Schema utilities for declarative configuration.")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _emit(payload: dict, *, error: bool = False) -> None:
|
|
34
|
+
"""Emit *payload* as a single JSON line to stdout or stderr."""
|
|
35
|
+
event = dict(payload)
|
|
36
|
+
span_context = trace.get_current_span().get_span_context()
|
|
37
|
+
event["trace_id"] = (
|
|
38
|
+
f"{span_context.trace_id:032x}" if span_context.is_valid else None
|
|
39
|
+
)
|
|
40
|
+
line = json.dumps(event, default=str)
|
|
41
|
+
if error:
|
|
42
|
+
print(line, file=sys.stderr, flush=True)
|
|
43
|
+
else:
|
|
44
|
+
print(line, flush=True)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@app.command()
|
|
48
|
+
def run(
|
|
49
|
+
pipeline: str = typer.Argument(..., help="Pipeline name / identifier to run."),
|
|
50
|
+
env: str = typer.Option("dev", "--env", "-e", help="Target execution environment."),
|
|
51
|
+
dry_run: bool = typer.Option(
|
|
52
|
+
False,
|
|
53
|
+
"--dry-run",
|
|
54
|
+
help="Validate and compile the pipeline without executing it.",
|
|
55
|
+
),
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Run a registered data pipeline.
|
|
58
|
+
|
|
59
|
+
Emits structured JSON logs and returns exit code 0 on success or 1 on
|
|
60
|
+
failure so that orchestrators and AI agents can parse the outcome.
|
|
61
|
+
|
|
62
|
+
Examples
|
|
63
|
+
--------
|
|
64
|
+
aptdata run pipeline_x --env prod
|
|
65
|
+
aptdata run pipeline_x --env staging --dry-run
|
|
66
|
+
"""
|
|
67
|
+
started_at = time.time()
|
|
68
|
+
_emit(
|
|
69
|
+
{
|
|
70
|
+
"event": "pipeline.started",
|
|
71
|
+
"pipeline": pipeline,
|
|
72
|
+
"env": env,
|
|
73
|
+
"dry_run": dry_run,
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
# Plugin registry look-up (stub – real implementations are in plugins/)
|
|
79
|
+
from aptdata.plugins import registry # noqa: PLC0415
|
|
80
|
+
|
|
81
|
+
pipeline_cls = registry.get(pipeline)
|
|
82
|
+
if pipeline_cls is None:
|
|
83
|
+
raise LookupError(f"Pipeline '{pipeline}' not found in registry.")
|
|
84
|
+
|
|
85
|
+
instance = pipeline_cls(system_id=pipeline)
|
|
86
|
+
|
|
87
|
+
if not dry_run:
|
|
88
|
+
instance.run()
|
|
89
|
+
|
|
90
|
+
elapsed = round(time.time() - started_at, 3)
|
|
91
|
+
_emit(
|
|
92
|
+
{
|
|
93
|
+
"event": "pipeline.completed",
|
|
94
|
+
"pipeline": pipeline,
|
|
95
|
+
"env": env,
|
|
96
|
+
"dry_run": dry_run,
|
|
97
|
+
"elapsed_seconds": elapsed,
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
raise SystemExit(0)
|
|
101
|
+
|
|
102
|
+
except LookupError as exc:
|
|
103
|
+
elapsed = round(time.time() - started_at, 3)
|
|
104
|
+
_emit(
|
|
105
|
+
{
|
|
106
|
+
"event": "pipeline.error",
|
|
107
|
+
"pipeline": pipeline,
|
|
108
|
+
"env": env,
|
|
109
|
+
"error": str(exc),
|
|
110
|
+
"elapsed_seconds": elapsed,
|
|
111
|
+
},
|
|
112
|
+
error=True,
|
|
113
|
+
)
|
|
114
|
+
raise SystemExit(1) from exc
|
|
115
|
+
|
|
116
|
+
except Exception as exc: # noqa: BLE001
|
|
117
|
+
elapsed = round(time.time() - started_at, 3)
|
|
118
|
+
_emit(
|
|
119
|
+
{
|
|
120
|
+
"event": "pipeline.error",
|
|
121
|
+
"pipeline": pipeline,
|
|
122
|
+
"env": env,
|
|
123
|
+
"error": str(exc),
|
|
124
|
+
"elapsed_seconds": elapsed,
|
|
125
|
+
},
|
|
126
|
+
error=True,
|
|
127
|
+
)
|
|
128
|
+
raise SystemExit(1) from exc
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@app.command()
|
|
132
|
+
def monitor(
|
|
133
|
+
refresh: float = typer.Option(
|
|
134
|
+
1.0,
|
|
135
|
+
"--refresh",
|
|
136
|
+
"-r",
|
|
137
|
+
help="Dashboard refresh interval in seconds.",
|
|
138
|
+
),
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Open the interactive TUI monitoring dashboard.
|
|
141
|
+
|
|
142
|
+
Displays the pipeline DAG, memory usage and task status in real time.
|
|
143
|
+
Press **q** or **Ctrl+C** to exit.
|
|
144
|
+
|
|
145
|
+
Examples
|
|
146
|
+
--------
|
|
147
|
+
aptdata monitor
|
|
148
|
+
aptdata monitor --refresh 0.5
|
|
149
|
+
"""
|
|
150
|
+
from aptdata.tui.monitor import MonitorApp # noqa: PLC0415
|
|
151
|
+
|
|
152
|
+
app_instance = MonitorApp(refresh_interval=refresh)
|
|
153
|
+
app_instance.run()
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@app.command()
|
|
157
|
+
def mcp_start(
|
|
158
|
+
transport: str = typer.Option(
|
|
159
|
+
"stdio",
|
|
160
|
+
"--transport",
|
|
161
|
+
"-t",
|
|
162
|
+
help="MCP transport to use (stdio or sse).",
|
|
163
|
+
),
|
|
164
|
+
) -> None:
|
|
165
|
+
"""Start the MCP (Model Context Protocol) server.
|
|
166
|
+
|
|
167
|
+
This exposes aptdata tools and resources so that AI agents
|
|
168
|
+
(Claude Desktop, Copilot, Devin, …) can discover and run pipelines.
|
|
169
|
+
|
|
170
|
+
Examples
|
|
171
|
+
--------
|
|
172
|
+
aptdata mcp-start
|
|
173
|
+
aptdata mcp-start --transport sse
|
|
174
|
+
"""
|
|
175
|
+
_emit({"event": "mcp.server.starting", "transport": transport})
|
|
176
|
+
try:
|
|
177
|
+
from aptdata.mcp.server import mcp as mcp_server # noqa: PLC0415
|
|
178
|
+
|
|
179
|
+
mcp_server.run(transport=transport)
|
|
180
|
+
except Exception as exc: # noqa: BLE001
|
|
181
|
+
_emit(
|
|
182
|
+
{"event": "mcp.server.error", "error": str(exc)},
|
|
183
|
+
error=True,
|
|
184
|
+
)
|
|
185
|
+
raise SystemExit(1) from exc
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
app.command()(scaffold)
|
|
189
|
+
app.add_typer(schema_app, name="schema")
|
|
190
|
+
|
|
191
|
+
from aptdata.cli.commands import ( # noqa: E402
|
|
192
|
+
config_app,
|
|
193
|
+
mesh_app,
|
|
194
|
+
plugin_app,
|
|
195
|
+
system_app,
|
|
196
|
+
telemetry_app,
|
|
197
|
+
)
|
|
198
|
+
from aptdata.cli.interactive import interactive_command # noqa: E402
|
|
199
|
+
|
|
200
|
+
app.add_typer(system_app, name="system")
|
|
201
|
+
app.add_typer(plugin_app, name="plugin")
|
|
202
|
+
app.add_typer(config_app, name="config")
|
|
203
|
+
app.add_typer(telemetry_app, name="telemetry")
|
|
204
|
+
app.add_typer(mesh_app, name="mesh")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@app.command("interactive")
|
|
208
|
+
def interactive() -> None:
|
|
209
|
+
"""Launch the interactive wizard mode."""
|
|
210
|
+
interactive_command()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@schema_app.command("export")
|
|
214
|
+
def schema_export(
|
|
215
|
+
output: Path = typer.Option(
|
|
216
|
+
...,
|
|
217
|
+
"--output",
|
|
218
|
+
"-o",
|
|
219
|
+
help="Output path for the generated JSON Schema.",
|
|
220
|
+
),
|
|
221
|
+
) -> None:
|
|
222
|
+
"""Export JSON Schema for declarative YAML configs."""
|
|
223
|
+
started_at = time.time()
|
|
224
|
+
_emit({"event": "schema.export.started", "output": str(output)})
|
|
225
|
+
try:
|
|
226
|
+
write_domain_schema(output)
|
|
227
|
+
elapsed = round(time.time() - started_at, 3)
|
|
228
|
+
_emit(
|
|
229
|
+
{
|
|
230
|
+
"event": "schema.export.completed",
|
|
231
|
+
"output": str(output),
|
|
232
|
+
"elapsed_seconds": elapsed,
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
raise SystemExit(0)
|
|
236
|
+
except Exception as exc: # noqa: BLE001
|
|
237
|
+
elapsed = round(time.time() - started_at, 3)
|
|
238
|
+
_emit(
|
|
239
|
+
{
|
|
240
|
+
"event": "schema.export.error",
|
|
241
|
+
"output": str(output),
|
|
242
|
+
"error": str(exc),
|
|
243
|
+
"elapsed_seconds": elapsed,
|
|
244
|
+
},
|
|
245
|
+
error=True,
|
|
246
|
+
)
|
|
247
|
+
raise SystemExit(1) from exc
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""CLI sub-command packages for aptdata."""
|
|
2
|
+
|
|
3
|
+
from aptdata.cli.commands.config_cmd import config_app
|
|
4
|
+
from aptdata.cli.commands.mesh_cmd import mesh_app
|
|
5
|
+
from aptdata.cli.commands.plugin_cmd import plugin_app
|
|
6
|
+
from aptdata.cli.commands.system_cmd import system_app
|
|
7
|
+
from aptdata.cli.commands.telemetry_cmd import telemetry_app
|
|
8
|
+
|
|
9
|
+
__all__ = ["system_app", "plugin_app", "config_app", "telemetry_app", "mesh_app"]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""CLI sub-commands for YAML configuration management."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from aptdata.cli.rendering.console import SmartConsole
|
|
10
|
+
from aptdata.cli.rendering.panels import yaml_preview
|
|
11
|
+
from aptdata.cli.rendering.tables import config_summary_table
|
|
12
|
+
|
|
13
|
+
config_app = typer.Typer(name="config", help="Manage declarative YAML configurations.")
|
|
14
|
+
|
|
15
|
+
_STARTER_YAML = """\
|
|
16
|
+
# aptdata declarative pipeline configuration
|
|
17
|
+
metadata:
|
|
18
|
+
name: my_pipeline
|
|
19
|
+
version: "1.0"
|
|
20
|
+
description: A sample pipeline
|
|
21
|
+
|
|
22
|
+
system:
|
|
23
|
+
system_id: my_pipeline
|
|
24
|
+
flows:
|
|
25
|
+
- flow_id: main_flow
|
|
26
|
+
components:
|
|
27
|
+
- component_id: extract
|
|
28
|
+
metadata:
|
|
29
|
+
kind: EXTRACT
|
|
30
|
+
description: Extract raw data
|
|
31
|
+
- component_id: transform
|
|
32
|
+
metadata:
|
|
33
|
+
kind: TRANSFORM
|
|
34
|
+
description: Transform data
|
|
35
|
+
- component_id: load
|
|
36
|
+
metadata:
|
|
37
|
+
kind: LOAD
|
|
38
|
+
description: Load to destination
|
|
39
|
+
edges:
|
|
40
|
+
- source_id: extract
|
|
41
|
+
target_id: transform
|
|
42
|
+
- source_id: transform
|
|
43
|
+
target_id: load
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@config_app.command("validate")
|
|
48
|
+
def config_validate(
|
|
49
|
+
path: Path = typer.Argument(..., help="Path to YAML config file.", exists=True),
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Parse and validate a YAML config file."""
|
|
52
|
+
from aptdata.config.parser import YamlConfigParser # noqa: PLC0415
|
|
53
|
+
|
|
54
|
+
console = SmartConsole(json_mode=False)
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
with console.spinner(f"Validating '{path}'..."):
|
|
58
|
+
parser = YamlConfigParser()
|
|
59
|
+
parsed = parser.parse_file(path)
|
|
60
|
+
console.success(f"Config valid: system_id='{parsed.system.system_id}'")
|
|
61
|
+
except Exception as exc: # noqa: BLE001
|
|
62
|
+
console.error(f"Validation failed: {exc}")
|
|
63
|
+
raise typer.Exit(1) from exc
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@config_app.command("init")
|
|
67
|
+
def config_init(
|
|
68
|
+
output: Path = typer.Option(
|
|
69
|
+
Path("pipeline.yaml"),
|
|
70
|
+
"--output",
|
|
71
|
+
"-o",
|
|
72
|
+
help="Output file path.",
|
|
73
|
+
),
|
|
74
|
+
template: bool = typer.Option(
|
|
75
|
+
False, "--template", help="Use the starter template."
|
|
76
|
+
),
|
|
77
|
+
) -> None:
|
|
78
|
+
"""Generate a starter YAML configuration file."""
|
|
79
|
+
console = SmartConsole(json_mode=False)
|
|
80
|
+
|
|
81
|
+
if output.exists():
|
|
82
|
+
console.error(f"File '{output}' already exists.")
|
|
83
|
+
raise typer.Exit(1)
|
|
84
|
+
|
|
85
|
+
output.write_text(_STARTER_YAML, encoding="utf-8")
|
|
86
|
+
console.success(f"Config template written to '{output}'.")
|
|
87
|
+
console.render(yaml_preview(_STARTER_YAML))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@config_app.command("show")
|
|
91
|
+
def config_show(
|
|
92
|
+
path: Path = typer.Argument(..., help="Path to YAML config file.", exists=True),
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Pretty-print a YAML config file with syntax highlighting."""
|
|
95
|
+
console = SmartConsole(json_mode=False)
|
|
96
|
+
content = path.read_text(encoding="utf-8")
|
|
97
|
+
console.render(yaml_preview(content))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@config_app.command("run")
|
|
101
|
+
def config_run(
|
|
102
|
+
path: Path = typer.Argument(..., help="Path to YAML config file.", exists=True),
|
|
103
|
+
env: str = typer.Option("dev", "--env", "-e", help="Target environment."),
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Parse a YAML config, register the system, and execute it."""
|
|
106
|
+
from aptdata.config.parser import YamlConfigParser # noqa: PLC0415
|
|
107
|
+
from aptdata.plugins import registry # noqa: PLC0415
|
|
108
|
+
|
|
109
|
+
console = SmartConsole(json_mode=False)
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
with console.spinner(f"Parsing '{path}'..."):
|
|
113
|
+
parser = YamlConfigParser()
|
|
114
|
+
parsed = parser.parse_file(path)
|
|
115
|
+
|
|
116
|
+
system_id = parsed.system.system_id
|
|
117
|
+
system_cls = type(parsed.system)
|
|
118
|
+
registry.register(system_id, system_cls)
|
|
119
|
+
|
|
120
|
+
console.render(config_summary_table(parsed))
|
|
121
|
+
|
|
122
|
+
with console.spinner(f"Running '{system_id}' [{env}]..."):
|
|
123
|
+
parsed.system.run()
|
|
124
|
+
|
|
125
|
+
console.success(f"System '{system_id}' executed successfully.")
|
|
126
|
+
except Exception as exc: # noqa: BLE001
|
|
127
|
+
console.error(f"Execution failed: {exc}")
|
|
128
|
+
raise typer.Exit(1) from exc
|