datagraph-core 0.8.2__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.
- datagraph_core-0.8.2/LICENSE +21 -0
- datagraph_core-0.8.2/PKG-INFO +427 -0
- datagraph_core-0.8.2/README.md +381 -0
- datagraph_core-0.8.2/pyproject.toml +61 -0
- datagraph_core-0.8.2/setup.cfg +4 -0
- datagraph_core-0.8.2/src/datagraph/__init__.py +59 -0
- datagraph_core-0.8.2/src/datagraph/ai/__init__.py +6 -0
- datagraph_core-0.8.2/src/datagraph/ai/explain.py +52 -0
- datagraph_core-0.8.2/src/datagraph/ai/lineage.py +162 -0
- datagraph_core-0.8.2/src/datagraph/ai/providers.py +197 -0
- datagraph_core-0.8.2/src/datagraph/analysis/__init__.py +5 -0
- datagraph_core-0.8.2/src/datagraph/analysis/impact.py +85 -0
- datagraph_core-0.8.2/src/datagraph/analysis/modeling.py +514 -0
- datagraph_core-0.8.2/src/datagraph/analysis/relationships.py +64 -0
- datagraph_core-0.8.2/src/datagraph/analysis/risk.py +70 -0
- datagraph_core-0.8.2/src/datagraph/analysis/tests_recommender.py +55 -0
- datagraph_core-0.8.2/src/datagraph/cli.py +831 -0
- datagraph_core-0.8.2/src/datagraph/extractors/__init__.py +31 -0
- datagraph_core-0.8.2/src/datagraph/extractors/airflow_extractor.py +223 -0
- datagraph_core-0.8.2/src/datagraph/extractors/base.py +21 -0
- datagraph_core-0.8.2/src/datagraph/extractors/datahub_extractor.py +162 -0
- datagraph_core-0.8.2/src/datagraph/extractors/dbt_extractor.py +321 -0
- datagraph_core-0.8.2/src/datagraph/extractors/git_extractor.py +118 -0
- datagraph_core-0.8.2/src/datagraph/extractors/js_extractor.py +146 -0
- datagraph_core-0.8.2/src/datagraph/extractors/lambda_extractor.py +215 -0
- datagraph_core-0.8.2/src/datagraph/extractors/lineage_file_extractor.py +138 -0
- datagraph_core-0.8.2/src/datagraph/extractors/openlineage_extractor.py +130 -0
- datagraph_core-0.8.2/src/datagraph/extractors/python_extractor.py +231 -0
- datagraph_core-0.8.2/src/datagraph/extractors/registry.py +94 -0
- datagraph_core-0.8.2/src/datagraph/extractors/sql_extractor.py +256 -0
- datagraph_core-0.8.2/src/datagraph/extractors/sql_in_code.py +88 -0
- datagraph_core-0.8.2/src/datagraph/extractors/warehouse_extractor.py +240 -0
- datagraph_core-0.8.2/src/datagraph/graph/__init__.py +16 -0
- datagraph_core-0.8.2/src/datagraph/graph/graph.py +546 -0
- datagraph_core-0.8.2/src/datagraph/graph/model.py +106 -0
- datagraph_core-0.8.2/src/datagraph/html_report.py +240 -0
- datagraph_core-0.8.2/src/datagraph/knowledge.py +210 -0
- datagraph_core-0.8.2/src/datagraph/maintenance.py +109 -0
- datagraph_core-0.8.2/src/datagraph/mcp_server.py +120 -0
- datagraph_core-0.8.2/src/datagraph/profiling.py +202 -0
- datagraph_core-0.8.2/src/datagraph/report.py +162 -0
- datagraph_core-0.8.2/src/datagraph/security.py +96 -0
- datagraph_core-0.8.2/src/datagraph_core.egg-info/PKG-INFO +427 -0
- datagraph_core-0.8.2/src/datagraph_core.egg-info/SOURCES.txt +80 -0
- datagraph_core-0.8.2/src/datagraph_core.egg-info/dependency_links.txt +1 -0
- datagraph_core-0.8.2/src/datagraph_core.egg-info/entry_points.txt +2 -0
- datagraph_core-0.8.2/src/datagraph_core.egg-info/requires.txt +33 -0
- datagraph_core-0.8.2/src/datagraph_core.egg-info/top_level.txt +1 -0
- datagraph_core-0.8.2/tests/test_ai_layer.py +101 -0
- datagraph_core-0.8.2/tests/test_airflow.py +67 -0
- datagraph_core-0.8.2/tests/test_analyze.py +67 -0
- datagraph_core-0.8.2/tests/test_bom_files.py +50 -0
- datagraph_core-0.8.2/tests/test_bridge_detection.py +65 -0
- datagraph_core-0.8.2/tests/test_cli.py +43 -0
- datagraph_core-0.8.2/tests/test_cli_v2.py +76 -0
- datagraph_core-0.8.2/tests/test_column_impact.py +43 -0
- datagraph_core-0.8.2/tests/test_datahub.py +57 -0
- datagraph_core-0.8.2/tests/test_dbt_compiled_lineage.py +86 -0
- datagraph_core-0.8.2/tests/test_dbt_extractor.py +53 -0
- datagraph_core-0.8.2/tests/test_git_extractor.py +82 -0
- datagraph_core-0.8.2/tests/test_graph.py +56 -0
- datagraph_core-0.8.2/tests/test_jaffle_shop.py +69 -0
- datagraph_core-0.8.2/tests/test_js.py +56 -0
- datagraph_core-0.8.2/tests/test_knowledge.py +80 -0
- datagraph_core-0.8.2/tests/test_lambda.py +84 -0
- datagraph_core-0.8.2/tests/test_lineage.py +63 -0
- datagraph_core-0.8.2/tests/test_lineage_file.py +57 -0
- datagraph_core-0.8.2/tests/test_llm_lineage.py +142 -0
- datagraph_core-0.8.2/tests/test_mcp_maintenance.py +62 -0
- datagraph_core-0.8.2/tests/test_modeling.py +122 -0
- datagraph_core-0.8.2/tests/test_openlineage.py +53 -0
- datagraph_core-0.8.2/tests/test_plugins.py +54 -0
- datagraph_core-0.8.2/tests/test_profiling.py +72 -0
- datagraph_core-0.8.2/tests/test_provenance_exports.py +60 -0
- datagraph_core-0.8.2/tests/test_providers.py +147 -0
- datagraph_core-0.8.2/tests/test_python_extractor.py +31 -0
- datagraph_core-0.8.2/tests/test_report.py +35 -0
- datagraph_core-0.8.2/tests/test_security.py +103 -0
- datagraph_core-0.8.2/tests/test_sql_column_lineage.py +64 -0
- datagraph_core-0.8.2/tests/test_sql_extractor.py +55 -0
- datagraph_core-0.8.2/tests/test_warehouse.py +61 -0
- datagraph_core-0.8.2/tests/test_warehouse_sqlite.py +91 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 impactgraph contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: datagraph-core
|
|
3
|
+
Version: 0.8.2
|
|
4
|
+
Summary: AI-powered Change Impact Graph for data and code systems: answer 'if I change this, what can break?'
|
|
5
|
+
Author: Arati
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/sumit-gupta03/datagraph
|
|
8
|
+
Keywords: change-impact,lineage,dbt,sql,openlineage,dependency-graph,data-engineering,impact-analysis,mcp
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: networkx>=3.0
|
|
24
|
+
Requires-Dist: rich>=13.0
|
|
25
|
+
Provides-Extra: sql
|
|
26
|
+
Requires-Dist: sqlglot>=20.0; extra == "sql"
|
|
27
|
+
Provides-Extra: ai
|
|
28
|
+
Requires-Dist: anthropic>=0.40.0; extra == "ai"
|
|
29
|
+
Provides-Extra: bedrock
|
|
30
|
+
Requires-Dist: boto3>=1.34; extra == "bedrock"
|
|
31
|
+
Provides-Extra: mcp
|
|
32
|
+
Requires-Dist: mcp>=1.0; python_version >= "3.10" and extra == "mcp"
|
|
33
|
+
Provides-Extra: yaml
|
|
34
|
+
Requires-Dist: pyyaml>=6.0; extra == "yaml"
|
|
35
|
+
Provides-Extra: all
|
|
36
|
+
Requires-Dist: sqlglot>=20.0; extra == "all"
|
|
37
|
+
Requires-Dist: anthropic>=0.40.0; extra == "all"
|
|
38
|
+
Requires-Dist: boto3>=1.34; extra == "all"
|
|
39
|
+
Requires-Dist: mcp>=1.0; python_version >= "3.10" and extra == "all"
|
|
40
|
+
Requires-Dist: pyyaml>=6.0; extra == "all"
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
43
|
+
Requires-Dist: sqlglot>=20.0; extra == "dev"
|
|
44
|
+
Requires-Dist: pyyaml>=6.0; extra == "dev"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# datagraph
|
|
48
|
+
|
|
49
|
+
**The data engine: lineage · relationships · data profiling · dimensional modelling · knowledge graph for AI assistants — built deterministically from your database, dbt project, SQL and code.**
|
|
50
|
+
|
|
51
|
+
Give datagraph a connection (and/or a dbt manifest, SQL, code) and it builds one graph of tables, columns, models, jobs and code,
|
|
52
|
+
then answers from that graph — locally, in seconds, with no LLM in the loop:
|
|
53
|
+
|
|
54
|
+
- **Where does this table / column come from and what does it feed?** (lineage, column level)
|
|
55
|
+
- **How are my tables related?** (foreign keys, view lineage, schema map)
|
|
56
|
+
- **What does the data look like?** (row counts, freshness, nulls, distincts — sensitive columns masked)
|
|
57
|
+
- **What is my dimensional model?** (Kimball facts / dimensions / bus matrix / SCD / issues, or a proposed star from a wide table)
|
|
58
|
+
- **Give my AI assistant the context.** (`context` packs, a Markdown wiki + `llms.txt`, an MCP server)
|
|
59
|
+
- **If I change this, what breaks?** (impact, risk, owners, tests — and the companion PR check
|
|
60
|
+
[impactgraph](https://github.com/sumit-gupta03/impactgraph) built on this engine)
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
warehouse / dbt / SQL / Python / Airflow / Lambda / OpenLineage / DataHub ──► one deterministic graph
|
|
64
|
+
──► lineage · relationships · profiles · dimensional model · impact ──► CLI · HTML · JSON · wiki · MCP
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
<p align="center">
|
|
68
|
+
<img src="docs/images/lineage-jaffle-customers.png" alt="Lineage of the customers model in dbt's jaffle_shop project" width="900"><br>
|
|
69
|
+
<em><code>datagraph lineage customers --html</code> on dbt's public jaffle_shop project: upstream through staging models to seed files, downstream to the table and its columns.</em>
|
|
70
|
+
</p>
|
|
71
|
+
|
|
72
|
+
## Contents
|
|
73
|
+
|
|
74
|
+
1. [Install](#install)
|
|
75
|
+
2. [The standard flow: connection in → lineage, profiling, model out](#the-standard-flow-connection-in--lineage-profiling-model-out)
|
|
76
|
+
3. [What goes into the graph](#what-goes-into-the-graph)
|
|
77
|
+
4. [Commands](#commands)
|
|
78
|
+
5. [Dimensional modelling](#dimensional-modelling)
|
|
79
|
+
6. [Data profiling](#data-profiling)
|
|
80
|
+
7. [Knowledge base & MCP for AI assistants](#knowledge-base--mcp-for-ai-assistants)
|
|
81
|
+
8. [Impact analysis & the impactgraph companion](#impact-analysis--the-impactgraph-companion)
|
|
82
|
+
9. [Python API](#python-api)
|
|
83
|
+
10. [Security](#security)
|
|
84
|
+
11. [How it compares](#how-it-compares-graphify--datahub--openlineage--datagraph)
|
|
85
|
+
12. [Node ids, provenance, propagation](#node-ids-provenance-propagation)
|
|
86
|
+
13. [Development & roadmap](#development)
|
|
87
|
+
|
|
88
|
+
## Install
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install datagraph-core # core: graph, warehouse/dbt/code extractors, lineage, profiling, modelling, wiki
|
|
92
|
+
pip install "datagraph-core[sql]" # + sqlglot: SQL files, view definitions, column-level lineage (recommended)
|
|
93
|
+
pip install "datagraph-core[mcp]" # + MCP server for Claude Code / Claude Desktop / Cursor
|
|
94
|
+
pip install "datagraph-core[ai]" # + Anthropic Claude for explanations / LLM lineage fallback
|
|
95
|
+
pip install "datagraph-core[bedrock]" # + Amazon Bedrock (Nova, Claude on Bedrock, Llama ...) for the same; OpenAI-compatible needs nothing extra
|
|
96
|
+
pip install "datagraph-core[all]" # everything (also PyYAML for YAML lineage files / serverless.yml)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The PyPI distribution is **`datagraph-core`** (the bare name `datagraph` is not allowed on PyPI); the import name, CLI and MCP server are all `datagraph`:
|
|
100
|
+
`pip install datagraph-core` → `import datagraph` / `datagraph analyze …`.
|
|
101
|
+
|
|
102
|
+
Database drivers: SQLite and DuckDB files work out of the box; for Snowflake / Postgres / BigQuery / Redshift / MySQL / SQL Server
|
|
103
|
+
install SQLAlchemy plus the driver and pass a SQLAlchemy URL (or pass an open DB-API connection from Python).
|
|
104
|
+
From source: `pip install "datagraph-core[sql] @ git+https://github.com/sumit-gupta03/datagraph"`.
|
|
105
|
+
|
|
106
|
+
## The standard flow: connection in → lineage, profiling, model out
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
datagraph analyze --warehouse "snowflake://user:pw@account/db" --schemas analytics,raw -o out/
|
|
110
|
+
datagraph analyze --warehouse warehouse.db -o out/ # a SQLite / DuckDB file works too
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
One command runs the standard sequence (use a **read-only** database role; the password is never stored or logged):
|
|
114
|
+
|
|
115
|
+
| Step | What datagraph does | Output in `out/` |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| connect | opens the connection (`sqlite` / `duckdb` file, or any SQLAlchemy URL) | — |
|
|
118
|
+
| schema | reads `information_schema`: tables, views, columns + types, primary & foreign keys, view definitions → graph | `datagraph.json` |
|
|
119
|
+
| relationships | table↔table and column↔column relationships (FKs, view lineage), per-table column lists | `relationships.json` |
|
|
120
|
+
| profiling | row count, freshness, per-column null %, distinct, min/max, top values (sampled); sensitive-looking columns masked | stored on the graph |
|
|
121
|
+
| dimensional model | Kimball: facts, dimensions, bridges, bus matrix, grain, measures & additivity, SCD types, conformed dimensions, issues | `MODEL.md`, `model.json`, `er-diagram.mmd` |
|
|
122
|
+
| lineage view | interactive HTML of the whole graph | `lineage.html` |
|
|
123
|
+
| knowledge base | `index.md`, one page per table, `GRAPH_REPORT.md`, `MODEL.md`, `llms.txt` | `wiki/` |
|
|
124
|
+
|
|
125
|
+
Then ask questions against the saved graph:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
datagraph lineage fact_sales --graph out/datagraph.json # upstream / downstream (add --html lineage.html)
|
|
129
|
+
datagraph relationships --graph out/datagraph.json --search customer
|
|
130
|
+
datagraph context dim_customer --graph out/datagraph.json # compact knowledge pack for an assistant
|
|
131
|
+
datagraph model --graph out/datagraph.json --from-table wide_orders
|
|
132
|
+
datagraph mcp --graph out/datagraph.json # MCP server for your coding assistant
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Options: `--schemas a,b` · `--database NAME` · `--dialect snowflake|postgres|bigquery|…` (for view SQL) · `--no-profile` (metadata only) ·
|
|
136
|
+
`--sample N` · `--no-top-values` · `--no-inferred` (declared foreign keys only) · `--json`.
|
|
137
|
+
|
|
138
|
+
## What goes into the graph
|
|
139
|
+
|
|
140
|
+
`datagraph build` accepts any combination; fragments merge by shared node ids and table aliases (`analytics.orders` vs `prod.analytics.orders`) are linked automatically.
|
|
141
|
+
|
|
142
|
+
| Source | Flag | Contributes |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| Warehouse / database | `--warehouse DSN` (+ `--warehouse-schemas`, `--warehouse-database`) | tables, views, columns + types, primary keys, **foreign keys** (table and column level), view lineage |
|
|
145
|
+
| dbt project | `--dbt-manifest` (+ `--dbt-catalog`) | models, sources, seeds, snapshots, exposures, the DAG, materialized tables, columns + types, **owners**, **column-to-column lineage** from compiled SQL (expands `select *` with the catalog), compiled SQL and test names per model |
|
|
146
|
+
| Raw SQL files | `--sql DIR` | table/view lineage and column lineage (aliases, CTEs, renames) via sqlglot |
|
|
147
|
+
| Python | `--repo DIR` | files, functions, classes, imports, calls (*inferred*), and **SQL found inside code → table edges** |
|
|
148
|
+
| JavaScript / TypeScript | `--js DIR` | files, functions, imports, calls, SQL-in-code |
|
|
149
|
+
| Airflow | `--airflow DIR` | DAGs, tasks, dependencies (`>>`, lists, `chain`), `python_callable` links, SQL in operators |
|
|
150
|
+
| AWS Lambda | `--lambda FILE` | serverless.yml / SAM / CloudFormation: lambdas → handlers, HTTP APIs, S3/SQS/DynamoDB events, env-referenced tables |
|
|
151
|
+
| OpenLineage | `--openlineage FILE` | datasets, jobs, schema + `columnLineage` facets, ownership |
|
|
152
|
+
| DataHub | `--lineage-file FILE`, `--datahub URL` | curated lineage files, or a live GraphQL import of datasets, owners, table and column lineage |
|
|
153
|
+
| Git | `datagraph diff` | which files **and which functions** changed |
|
|
154
|
+
| Your own tool | `--<plugin>` | any package exposing a `datagraph.extractors` entry point (see Python API) |
|
|
155
|
+
|
|
156
|
+
## Commands
|
|
157
|
+
|
|
158
|
+
| Command | Purpose |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `analyze --warehouse DSN -o DIR` | the standard flow above, in one go |
|
|
161
|
+
| `build [inputs] -o datagraph.json` | build / refresh the graph from any inputs (`--update` skips when inputs are unchanged) |
|
|
162
|
+
| `lineage NODE [--html F] [--json]` | upstream (where it comes from) and downstream (what it feeds) |
|
|
163
|
+
| `relationships [--search X] [--json]` | schema map: every table with columns, foreign keys, lineage relationships, profiles |
|
|
164
|
+
| `profile --warehouse DSN [--tables a,b]` | data profiling stored on the graph |
|
|
165
|
+
| `model [--from-table T] [--mermaid F] [--markdown F] [--json]` | dimensional model / proposed star schema |
|
|
166
|
+
| `context NODE` | compact knowledge pack for one node |
|
|
167
|
+
| `wiki -o DIR` | Markdown knowledge base + `GRAPH_REPORT.md` + `MODEL.md` + `llms.txt` |
|
|
168
|
+
| `impact NODE` · `diff --repo .` · `paths A B` · `hotspots` | change impact: blast radius, risk, owners, tests; propagation paths; riskiest nodes |
|
|
169
|
+
| `html NODE -o F` · `html --all -o F` · `export --format graphml\|dot\|cypher\|json` | pictures and exports |
|
|
170
|
+
| `nodes --search X` | find node ids |
|
|
171
|
+
| `graph-diff old.json new.json` | schema / dependency drift between two graphs |
|
|
172
|
+
| `watch` · `hook-install` | keep the graph fresh (file watcher, git pre-commit hook) |
|
|
173
|
+
| `enrich [--dry-run]` · `explain NODE` | optional LLM lineage fallback / plain-language explanation (`[ai]`) |
|
|
174
|
+
| `mcp --graph F` | MCP server (`[mcp]`) |
|
|
175
|
+
| `plugins` | list installed extractor plugins |
|
|
176
|
+
|
|
177
|
+
Every command takes `--graph PATH` (default `datagraph.json`), most take `--json` and `--no-inferred`.
|
|
178
|
+
|
|
179
|
+
## Dimensional modelling
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
datagraph model # classify + star schema + issues + Mermaid ER diagram (Markdown to stdout)
|
|
183
|
+
datagraph model --markdown MODEL.md --mermaid er.mmd --json
|
|
184
|
+
datagraph model --from-table wide_orders # propose fact + dimensions from one flat / wide table
|
|
185
|
+
datagraph model --no-inferred # declared foreign keys only
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Standard Kimball approach, computed deterministically and **explained** (every classification lists its reasons):
|
|
189
|
+
|
|
190
|
+
- **Column roles** — pk / fk / date / measure / flag / attribute from names, declared types (warehouse or dbt catalog) and profiles.
|
|
191
|
+
- **Table roles** — fact / dimension / bridge / lookup / derived (views without key links) with a confidence and reasons: foreign keys
|
|
192
|
+
out/in, measures, dates, attributes, naming conventions, row counts.
|
|
193
|
+
- **Key links** — declared foreign keys (`extracted`) plus name inference such as `orders.customer_id → customers` (`inferred`, flagged to verify).
|
|
194
|
+
- **Star schema** — per fact: business process → **grain** → dimensions → facts (the four-step design), measures with additivity;
|
|
195
|
+
per dimension: key, attributes, used-by, **SCD type** (2 when `valid_from/valid_to/is_current` exist, 1 when `updated_at`, else
|
|
196
|
+
undecided with a recommendation); **bus matrix** (facts × dimensions) and **conformed dimensions**; snowflake chains.
|
|
197
|
+
- **Issues** — fact without a time grain, key with no dimension, fact-to-fact links, measures sitting in a dimension, unused
|
|
198
|
+
dimensions, natural/text keys (surrogate key advice), missing `dim_date`, high-null keys (late-arriving dimensions).
|
|
199
|
+
- **Propose from a wide table** — groups low-cardinality attributes by prefix into dimensions (`customer_name`, `customer_country` →
|
|
200
|
+
`dim_customer`), numeric columns into measures, dates into `dim_date`; near-unique text stays as degenerate dimensions.
|
|
201
|
+
|
|
202
|
+
`MODEL.md` is part of the wiki, `model` is an MCP tool, and the role shows up in `context` packs.
|
|
203
|
+
|
|
204
|
+
## Data profiling
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
datagraph profile --warehouse prod.db [--tables customers,orders] [--sample 100000] [--no-top-values]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Per table: row count, freshness (max of date-like columns); per column: null %, distinct, min/max, top values (sampled). Results are
|
|
211
|
+
stored on the graph nodes and surface in `relationships`, `context`, lineage HTML tooltips and the wiki. Columns whose names look
|
|
212
|
+
sensitive (email, phone, name, address, card, token, …) keep counts only — no sample values. Profiles also make the risk score
|
|
213
|
+
data-aware (empty tables count half, >1M-row tables 1.5×) and feed the optional LLM lineage fallback.
|
|
214
|
+
|
|
215
|
+
## Knowledge base & MCP for AI assistants
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
datagraph context dim_customer # description, owner, columns (+type, pk, profile, where each column comes from),
|
|
219
|
+
# upstream, downstream, relationships, dbt tests, modelling role,
|
|
220
|
+
# risk-if-changed + test plan, and the SQL that builds it
|
|
221
|
+
datagraph wiki -o kb/ # index.md, nodes/*.md (cross-linked), GRAPH_REPORT.md, MODEL.md, llms.txt
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`GRAPH_REPORT.md` lists hotspots, high-impact dbt models without tests, ownerless nodes, roots and leaves. Everything is generated
|
|
225
|
+
from the graph, so an assistant explains rather than guesses.
|
|
226
|
+
|
|
227
|
+
**MCP** (Claude Code, Claude Desktop, Cursor — any MCP client), after `pip install "datagraph-core[mcp]"` and one `analyze`/`build`:
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"mcpServers": {
|
|
232
|
+
"datagraph": {
|
|
233
|
+
"command": "python",
|
|
234
|
+
"args": ["-m", "datagraph.cli", "mcp", "--graph", "/path/to/out/datagraph.json"]
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
(`examples/mcp/claude-mcp.json`; for Claude Code put it in `.mcp.json` or run
|
|
241
|
+
`claude mcp add datagraph -- python -m datagraph.cli mcp --graph /path/to/datagraph.json`.) Tools: `impact`, `diff`, `find_nodes`,
|
|
242
|
+
`paths`, `hotspots`, `lineage`, `relationships`, `context`, `model`. The server is stdio-only, read-only over the graph file you pass,
|
|
243
|
+
and never receives connection strings.
|
|
244
|
+
|
|
245
|
+
**Claude Code skill:** copy `skills/datagraph/` to `.claude/skills/datagraph/` (or `~/.claude/skills/`) and ask *"where does
|
|
246
|
+
fact_booking come from?"*, *"how are these tables related?"*, *"what is the dimensional model?"*, *"what breaks if I change dim_customer?"*.
|
|
247
|
+
|
|
248
|
+
## Impact analysis & the impactgraph companion
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
datagraph impact dbt:customer # a model / table / column / function / task
|
|
252
|
+
datagraph diff --repo . --graph datagraph.json # what my uncommitted change can break
|
|
253
|
+
datagraph paths dbt:customer exposure:revenue_report
|
|
254
|
+
datagraph hotspots
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
⚠ Change Impact Changed: customer Risk: HIGH (score 24.5)
|
|
259
|
+
|
|
260
|
+
⬢ customer (dbt_model)
|
|
261
|
+
├── ⬢ dim_customer (dbt_model) via depends_on
|
|
262
|
+
│ └── ⬢ fact_booking (dbt_model) via depends_on
|
|
263
|
+
│ ├── 📊 revenue_report (dashboard) via exposes
|
|
264
|
+
│ └── 📊 customer_dashboard (dashboard) via exposes
|
|
265
|
+
└── ▤ prod.analytics.customer (view) via writes_to
|
|
266
|
+
|
|
267
|
+
Affected: 3 dbt model(s) · 2 dashboard(s) · 2 table(s)
|
|
268
|
+
Notify (owners of affected artifacts): finance: revenue_report · growth: customer_dashboard
|
|
269
|
+
Recommended tests:
|
|
270
|
+
✓ dbt build --select customer+ dim_customer+ fact_booking+
|
|
271
|
+
✓ Run a schema/contract check on prod.analytics.fact_booking
|
|
272
|
+
✓ Manually validate 'revenue_report' after deploy (numbers & filters)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
<p align="center">
|
|
276
|
+
<img src="docs/images/impact-demo.png" alt="Interactive blast-radius view" width="900"><br>
|
|
277
|
+
<em><code>datagraph html models/customer.sql</code> — one SQL file → models → tables → dashboards and the Python API, with risk, owners and the test plan.</em>
|
|
278
|
+
</p>
|
|
279
|
+
|
|
280
|
+
The **pull-request product** — `impactgraph check` / `pr`, a GitHub Action that comments the blast radius on every PR, `--fail-on`
|
|
281
|
+
gating — lives in **[impactgraph](https://github.com/sumit-gupta03/impactgraph)**, a thin layer over this engine that re-exports its
|
|
282
|
+
whole API. datagraph = everything data-related; impactgraph = "what breaks if I merge this?".
|
|
283
|
+
|
|
284
|
+
## Python API
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
from datagraph import (ImpactGraph, WarehouseExtractor, DbtExtractor, SqlExtractor, PythonExtractor,
|
|
288
|
+
AirflowExtractor, LambdaExtractor, JsExtractor, OpenLineageExtractor,
|
|
289
|
+
LineageFileExtractor, DataHubExtractor, analyze_impact,
|
|
290
|
+
profile_warehouse, star_schema, propose_from_table, classify_tables,
|
|
291
|
+
context, build_wiki, ExtractorPlugin, register)
|
|
292
|
+
|
|
293
|
+
# 1. build (any combination; a DSN, a file path or an open DB-API connection)
|
|
294
|
+
graph = ImpactGraph()
|
|
295
|
+
graph.merge(WarehouseExtractor("snowflake://...", schemas=["analytics"]).extract())
|
|
296
|
+
graph.merge(DbtExtractor("target/manifest.json", catalog_path="target/catalog.json").extract())
|
|
297
|
+
graph.merge(PythonExtractor("./src").extract())
|
|
298
|
+
graph.link_table_aliases()
|
|
299
|
+
|
|
300
|
+
# 2. lineage & relationships
|
|
301
|
+
graph.lineage("table:analytics.dim_customer") # {'upstream': {...}, 'downstream': {...}}
|
|
302
|
+
from datagraph.analysis.relationships import relationships
|
|
303
|
+
relationships(graph)["table_relationships"] # foreign keys + lineage between tables
|
|
304
|
+
|
|
305
|
+
# 3. profiling, dimensional model, knowledge base
|
|
306
|
+
profile_warehouse("snowflake://...", graph) # stores node.meta["profile"] (sensitive columns masked)
|
|
307
|
+
model = star_schema(graph) # facts, dimensions, bus_matrix, scd, issues
|
|
308
|
+
from datagraph.analysis.modeling import to_markdown, to_mermaid
|
|
309
|
+
print(to_markdown(model)); print(to_mermaid(model))
|
|
310
|
+
propose_from_table(graph, "wide_orders") # star from a flat table
|
|
311
|
+
print(context(graph, "dim_customer")) # compact text pack
|
|
312
|
+
build_wiki(graph, "kb/")
|
|
313
|
+
|
|
314
|
+
# 4. impact
|
|
315
|
+
analysis = analyze_impact(graph, ["dbt:customer"])
|
|
316
|
+
analysis.risk, analysis.owners, analysis.recommended_tests, analysis.trees
|
|
317
|
+
|
|
318
|
+
# 5. your own extractor (BI tool, orchestrator, catalog ...) -> also becomes `datagraph build --mytool X`
|
|
319
|
+
register(ExtractorPlugin(name="mytool", factory=MyToolExtractor, help="...", options={"token": "API token"}))
|
|
320
|
+
# or in your package's pyproject: [project.entry-points."datagraph.extractors"] mytool = "my_pkg:MyToolExtractor"
|
|
321
|
+
|
|
322
|
+
# 6. optional AI (pip install datagraph-core[ai])
|
|
323
|
+
from datagraph.ai import explain_impact, suggest_lineage, apply_suggestions
|
|
324
|
+
print(explain_impact(analysis)) # explains; never changes the graph
|
|
325
|
+
apply_suggestions(graph, suggest_lineage(graph), min_confidence=0.7) # tagged provenance=llm, excludable
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Optional AI layer and LLM providers
|
|
329
|
+
|
|
330
|
+
The AI layer is optional and never builds the graph: `datagraph explain` narrates an impact analysis, `datagraph enrich` /
|
|
331
|
+
`build --llm-fallback` asks for relationship *suggestions* (schema-validated, must reference existing nodes, tagged `llm`,
|
|
332
|
+
confidence-gated). Three interchangeable providers; pick with `--provider` or `DATAGRAPH_LLM_PROVIDER`, model with `--model` or
|
|
333
|
+
`DATAGRAPH_LLM_MODEL`; credentials always come from the environment / cloud SDK, never from the graph:
|
|
334
|
+
|
|
335
|
+
| Provider | Install | Credentials | Default model | Example |
|
|
336
|
+
|---|---|---|---|---|
|
|
337
|
+
| `anthropic` (default) | `datagraph-core[ai]` | `ANTHROPIC_API_KEY` | `claude-opus-5` | `datagraph explain dbt:customer` |
|
|
338
|
+
| `bedrock` — Amazon Nova, Claude on Bedrock, Llama, Mistral … | `datagraph-core[bedrock]` | standard AWS chain (`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`/`AWS_REGION`, profile, SSO, instance role) | `amazon.nova-pro-v1:0` | `datagraph explain dbt:customer --provider bedrock --model amazon.nova-pro-v1:0` |
|
|
339
|
+
| `openai` — any OpenAI-compatible endpoint (OpenAI, Azure, Ollama, vLLM, Groq …) | nothing extra | `DATAGRAPH_LLM_API_KEY` (+ `DATAGRAPH_LLM_BASE_URL`, e.g. `http://localhost:11434/v1` for Ollama) | `gpt-4o-mini` | `DATAGRAPH_LLM_PROVIDER=openai DATAGRAPH_LLM_BASE_URL=http://localhost:11434/v1 datagraph enrich --model llama3 --dry-run` |
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
from datagraph.ai import explain_impact, suggest_lineage, BedrockProvider
|
|
343
|
+
print(explain_impact(analysis, provider="bedrock", model="amazon.nova-pro-v1:0"))
|
|
344
|
+
suggest_lineage(graph, provider=BedrockProvider(model="anthropic.claude-3-5-sonnet-20241022-v2:0", region="us-east-1"))
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Tested live on Amazon Bedrock with `amazon.nova-lite-v1:0` (explain + enrich). Bedrock per-model output caps are handled automatically (`DATAGRAPH_LLM_MAX_TOKENS` to override).
|
|
348
|
+
|
|
349
|
+
Everything else — lineage, relationships, profiling, dimensional modelling, wiki, MCP — needs no LLM at all.
|
|
350
|
+
|
|
351
|
+
## Security
|
|
352
|
+
|
|
353
|
+
- **Deterministic core, no LLM in the loop.** Graph, lineage, profiling and the dimensional model are computed from artifacts; an LLM
|
|
354
|
+
is optional and only *explains* or *suggests* (suggestions are schema-validated, must reference existing nodes, are tagged `llm`
|
|
355
|
+
and gated by confidence). Nothing an LLM returns is executed.
|
|
356
|
+
- **Prompt injection.** Names, descriptions, docs and SQL are data from your repos and warehouses. Every LLM prompt wraps them in
|
|
357
|
+
`<data>` tags with an instruction to never follow instructions found inside; text is stripped of control/bidi characters and
|
|
358
|
+
truncated; wiki/context output and the MCP server instructions carry the same "untrusted text" notice for downstream assistants.
|
|
359
|
+
- **Secrets.** Connection strings are used only to open a connection; they are never written to the graph, the cache or outputs,
|
|
360
|
+
and passwords are redacted wherever a DSN is printed. Prefer environment variables / key-pair / SSO auth from your driver.
|
|
361
|
+
- **Personal data.** Profiling keeps counts but masks sample values (min/max/top values) for sensitive-looking columns;
|
|
362
|
+
`--no-top-values` disables value sampling; `--no-profile` skips data access entirely.
|
|
363
|
+
- **SQL / HTML injection.** Identifiers are quoted and literals escaped in every generated query; HTML reports escape embedded JSON.
|
|
364
|
+
- **MCP server.** stdio-only local process (no network port), read-only over the graph file you pass, accepts no connection strings.
|
|
365
|
+
- **Access.** Use a read-only database role; datagraph only issues `SELECT`s against `information_schema` and the tables you profile.
|
|
366
|
+
- **Plugins** are Python entry points — install only extractor packages you trust (same trust level as any pip package).
|
|
367
|
+
|
|
368
|
+
## How it compares: Graphify · DataHub · OpenLineage · datagraph
|
|
369
|
+
|
|
370
|
+
| | Graphify | DataHub | OpenLineage | datagraph |
|
|
371
|
+
|---|---|---|---|---|
|
|
372
|
+
| What it is | A skill that turns a folder into a knowledge graph for AI assistants | A deployed metadata platform / catalog | An open standard for emitting lineage events (Marquez as reference server) | A pip library + CLI + MCP for lineage, relationships, profiling, dimensional modelling and impact |
|
|
373
|
+
| Question answered | "Help my AI assistant understand this repo" | "What data exists, who owns it, how is it connected, is it healthy?" | "What did this job read and write at run time?" | "Where does this come from, how is it related, what does it look like, what is the model, what breaks if I change it?" |
|
|
374
|
+
| Inputs | 13 languages via tree-sitter, docs, PDFs, images | 50+ connectors, OpenLineage events | Emitters in Airflow, Spark, dbt, Flink… | warehouse information_schema (FKs, views), dbt manifest + catalog, SQL, Python/JS, git diff, Airflow, Lambda, OpenLineage, DataHub, plugins |
|
|
375
|
+
| Graph built by | AST + Claude for non-code | ingestion connectors | the emitting jobs | deterministic extractors; optional `llm` fallback clearly tagged |
|
|
376
|
+
| Knows application code | yes (structure) | no | no | yes — functions, calls, SQL-in-code, Lambda handlers, Airflow callables |
|
|
377
|
+
| Column-level lineage | no | yes (connectors) | yes (facet) | yes (sqlglot, catalog-aware; imports OL/DataHub column lineage) |
|
|
378
|
+
| Foreign keys / schema relationships | no | yes | no | yes |
|
|
379
|
+
| Data profiling | no | yes (ingestion recipes) | no | yes (light, masked, feeds risk & modelling) |
|
|
380
|
+
| Dimensional modelling | no | no | no | yes (Kimball: facts/dims/bus matrix/SCD/issues, wide-table proposals) |
|
|
381
|
+
| Direction-aware impact + risk + test plan | no | impact view only | no | yes, across code and data (and impactgraph for PRs) |
|
|
382
|
+
| AI assistant integration | skill + MCP | MCP / API | via a backend | skill, MCP, context packs, wiki + llms.txt |
|
|
383
|
+
| Infrastructure | none | platform (DB, search, Kafka) | events need a backend | none — pip, a JSON file; runs in CI |
|
|
384
|
+
|
|
385
|
+
**Positioning:** OpenLineage is the *wire format* lineage travels in; DataHub is the *catalog* it lands in; Graphify is the *repo map*
|
|
386
|
+
for an assistant; datagraph is the *local data engine* that reads your warehouse, dbt and code, and **imports** OpenLineage / DataHub
|
|
387
|
+
rather than competing with them. It is deliberately not a catalog (no search UI, glossary, governance or monitoring).
|
|
388
|
+
|
|
389
|
+
**Known limits:** code languages are Python and JS/TS (regex-based for JS); call edges are name-resolved (tagged *inferred*); column
|
|
390
|
+
lineage needs SQL or a catalog — otherwise a same-name heuristic (tagged *inferred*) or the opt-in `llm` fallback applies; dimensional
|
|
391
|
+
classification is heuristic and always shows its reasons and confidence.
|
|
392
|
+
|
|
393
|
+
## Node ids, provenance, propagation
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
table:prod.analytics.customer column:dim_customer.customer_key dbt:dim_customer source:raw.customers
|
|
397
|
+
file:models/customer.sql func:src/api.py::customers_endpoint class:src/models.py::Customer
|
|
398
|
+
exposure:revenue_report job:airflow/load_dim_customer dag:nightly task:nightly/build_dim lambda:GetBookings api:GET /bookings
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Every edge carries a provenance — `extracted` (from an artifact), `inferred` (heuristic: name-resolved call, same-name column,
|
|
402
|
+
name-inferred foreign key) or `llm` (accepted suggestion); `--no-inferred` keeps only `extracted`. Edges are typed and each type knows
|
|
403
|
+
which way change flows (`contains`, `writes_to`, `exposes` forward; `calls`, `imports`, `depends_on` reverse): `impact()` walks forward,
|
|
404
|
+
`upstream()` backward, `lineage()` both.
|
|
405
|
+
|
|
406
|
+
## Development
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
git clone https://github.com/sumit-gupta03/datagraph && cd datagraph
|
|
410
|
+
pip install -e ".[dev]"
|
|
411
|
+
pytest # 140 tests, offline, ~20 s — includes dbt's real jaffle_shop project as a fixture
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Docs: `docs/datagraph-documentation.pdf` (how it was built, A to Z) and `docs/datagraph-learning-guide.pdf` (graphs and lineage from
|
|
415
|
+
zero). Tagging `vX.Y.Z` builds wheels, creates a GitHub Release and publishes `datagraph-core` to PyPI via trusted publishing
|
|
416
|
+
(`.github/workflows/publish.yml`).
|
|
417
|
+
|
|
418
|
+
## Roadmap
|
|
419
|
+
|
|
420
|
+
- Plugin packages for Looker / Tableau / Power BI / Dagster / Prefect / Kafka (the `datagraph.extractors` entry point is ready)
|
|
421
|
+
- Tree-sitter parsers for Java / Scala / Go (today: Python via ast, JS/TS via regex)
|
|
422
|
+
- Data-quality rule suggestions from profiles + model (uniqueness of keys, referential integrity, freshness SLAs)
|
|
423
|
+
- Incremental per-file rebuilds (today `--update` skips unchanged inputs)
|
|
424
|
+
|
|
425
|
+
## License
|
|
426
|
+
|
|
427
|
+
MIT
|