dbdocs 0.0.0__tar.gz → 1.0.0__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.
- {dbdocs-0.0.0 → dbdocs-1.0.0}/PKG-INFO +2 -2
- {dbdocs-0.0.0 → dbdocs-1.0.0}/README.md +1 -1
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/extract/_sqlglot_lineage.py +40 -20
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/extract/column_lineage.py +7 -2
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/builder.py +3 -1
- {dbdocs-0.0.0 → dbdocs-1.0.0}/pyproject.toml +5 -2
- {dbdocs-0.0.0 → dbdocs-1.0.0}/.gitignore +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/LICENSE +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/__init__.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/__main__.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/cli/__init__.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/cli/main.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/core/__init__.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/core/artifacts.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/core/config.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/core/exceptions.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/core/log.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/extract/__init__.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/extract/erd.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/extract/erd_json.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/extract/graph.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/extract/nodes.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/main.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/__init__.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/assets/app.js +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/assets/favicon.svg +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/assets/graph/index.css +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/assets/graph/index.js +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/assets/style.css +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/assets/vendor/marked.min.js +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/assets/vendor/minisearch.min.js +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/bundle/index.html +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/deploy.py +0 -0
- {dbdocs-0.0.0 → dbdocs-1.0.0}/dbdocs/site/inject.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dbdocs
|
|
3
|
-
Version:
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Alternative dbt docs site: Catalog + ERD + column-level lineage
|
|
5
5
|
Project-URL: Homepage, https://github.com/datnguye/dbt-docs
|
|
6
6
|
Project-URL: Repository, https://github.com/datnguye/dbt-docs
|
|
@@ -27,7 +27,7 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
<p align="center"><b>An alternative dbt docs site — catalog + ERD + column-level lineage, baked into one file.</b></p>
|
|
28
28
|
|
|
29
29
|
<p align="center">
|
|
30
|
-
<a href="https://dbdocs.datnguye.me/demo/"><img src="https://img.shields.io/badge/live-demo-FF694A?style=flat&logo=rocket&logoColor=white" alt="live demo"></a>
|
|
30
|
+
<a href="https://dbdocs.datnguye.me/latest/demo/"><img src="https://img.shields.io/badge/live-demo-FF694A?style=flat&logo=rocket&logoColor=white" alt="live demo"></a>
|
|
31
31
|
<a href="https://dbdocs.datnguye.me/"><img src="https://img.shields.io/badge/docs-visit%20site-blue?style=flat&logo=gitbook&logoColor=white" alt="docs"></a>
|
|
32
32
|
<a href="https://pypi.org/project/dbdocs/"><img src="https://badge.fury.io/py/dbdocs.svg" alt="PyPI version"></a>
|
|
33
33
|
<img src="https://img.shields.io/badge/CLI-Python-FFCE3E?labelColor=14354C&logo=python&logoColor=white" alt="python-cli">
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<p align="center"><b>An alternative dbt docs site — catalog + ERD + column-level lineage, baked into one file.</b></p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<a href="https://dbdocs.datnguye.me/demo/"><img src="https://img.shields.io/badge/live-demo-FF694A?style=flat&logo=rocket&logoColor=white" alt="live demo"></a>
|
|
8
|
+
<a href="https://dbdocs.datnguye.me/latest/demo/"><img src="https://img.shields.io/badge/live-demo-FF694A?style=flat&logo=rocket&logoColor=white" alt="live demo"></a>
|
|
9
9
|
<a href="https://dbdocs.datnguye.me/"><img src="https://img.shields.io/badge/docs-visit%20site-blue?style=flat&logo=gitbook&logoColor=white" alt="docs"></a>
|
|
10
10
|
<a href="https://pypi.org/project/dbdocs/"><img src="https://badge.fury.io/py/dbdocs.svg" alt="PyPI version"></a>
|
|
11
11
|
<img src="https://img.shields.io/badge/CLI-Python-FFCE3E?labelColor=14354C&logo=python&logoColor=white" alt="python-cli">
|
|
@@ -44,19 +44,19 @@ class Node:
|
|
|
44
44
|
yield from d.walk()
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def
|
|
48
|
-
column: str | exp.Column,
|
|
47
|
+
def prepare_scope(
|
|
49
48
|
sql: str | exp.Expression,
|
|
50
49
|
schema: dict | Schema | None = None,
|
|
51
50
|
sources: t.Mapping[str, str | exp.Query] | None = None,
|
|
52
51
|
dialect: DialectType = None,
|
|
53
|
-
scope: Scope | None = None,
|
|
54
|
-
trim_selects: bool = True,
|
|
55
52
|
**kwargs,
|
|
56
|
-
) ->
|
|
57
|
-
"""
|
|
53
|
+
) -> Scope:
|
|
54
|
+
"""Parse, qualify, and build the optimizer scope for a SQL query once.
|
|
55
|
+
|
|
56
|
+
The expensive half of :func:`lineage`. Callers tracing many columns of one
|
|
57
|
+
query build the scope here and reuse it across :func:`lineage` calls.
|
|
58
|
+
"""
|
|
58
59
|
expression = maybe_parse(sql, dialect=dialect)
|
|
59
|
-
column = normalize_identifiers.normalize_identifiers(column, dialect=dialect).name
|
|
60
60
|
|
|
61
61
|
if sources:
|
|
62
62
|
expression = exp.expand(
|
|
@@ -65,22 +65,42 @@ def lineage(
|
|
|
65
65
|
dialect=dialect,
|
|
66
66
|
)
|
|
67
67
|
|
|
68
|
+
expression = qualify.qualify(
|
|
69
|
+
expression,
|
|
70
|
+
dialect=dialect,
|
|
71
|
+
schema=schema,
|
|
72
|
+
**{
|
|
73
|
+
"validate_qualify_columns": False,
|
|
74
|
+
"identify": False,
|
|
75
|
+
"allow_partial_qualification": True,
|
|
76
|
+
**kwargs,
|
|
77
|
+
},
|
|
78
|
+
)
|
|
79
|
+
scope = build_scope(expression)
|
|
68
80
|
if not scope:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
raise SqlglotError("Cannot build lineage, sql must be SELECT")
|
|
82
|
+
return scope
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def lineage(
|
|
86
|
+
column: str | exp.Column,
|
|
87
|
+
sql: str | exp.Expression,
|
|
88
|
+
schema: dict | Schema | None = None,
|
|
89
|
+
sources: t.Mapping[str, str | exp.Query] | None = None,
|
|
90
|
+
dialect: DialectType = None,
|
|
91
|
+
scope: Scope | None = None,
|
|
92
|
+
trim_selects: bool = True,
|
|
93
|
+
**kwargs,
|
|
94
|
+
) -> Node:
|
|
95
|
+
"""Build the lineage graph for a column of a SQL query.
|
|
96
|
+
|
|
97
|
+
Pass a prebuilt ``scope`` (from :func:`prepare_scope`) to skip the per-call
|
|
98
|
+
parse/qualify/build_scope when tracing many columns of the same query.
|
|
99
|
+
"""
|
|
100
|
+
column = normalize_identifiers.normalize_identifiers(column, dialect=dialect).name
|
|
81
101
|
|
|
82
102
|
if not scope:
|
|
83
|
-
|
|
103
|
+
scope = prepare_scope(sql, schema=schema, sources=sources, dialect=dialect, **kwargs)
|
|
84
104
|
|
|
85
105
|
select_names_original = {select.alias_or_name for select in scope.expression.selects}
|
|
86
106
|
select_names_lower = {name.lower(): name for name in select_names_original}
|
|
@@ -20,7 +20,7 @@ from sqlglot.errors import SqlglotError
|
|
|
20
20
|
from dbdocs.core.artifacts import db_schema, node_name
|
|
21
21
|
from dbdocs.core.exceptions import LineageError
|
|
22
22
|
from dbdocs.core.log import logger
|
|
23
|
-
from dbdocs.extract._sqlglot_lineage import Node, lineage
|
|
23
|
+
from dbdocs.extract._sqlglot_lineage import Node, lineage, prepare_scope
|
|
24
24
|
|
|
25
25
|
#: dbt adapter_type → sqlglot dialect, when the names differ. Most match 1:1.
|
|
26
26
|
_DIALECT_ALIASES = {
|
|
@@ -80,9 +80,14 @@ class ColumnLineageExtractor:
|
|
|
80
80
|
output_columns = (
|
|
81
81
|
list(getattr(catalog_node, "columns", {}) or {}) if catalog_node else []
|
|
82
82
|
)
|
|
83
|
+
if not output_columns:
|
|
84
|
+
return
|
|
85
|
+
# Build the scope once per model, then trace each column against it —
|
|
86
|
+
# qualify is the expensive part and is identical for every column.
|
|
87
|
+
scope = prepare_scope(compiled, schema=self.schema, dialect=self.dialect)
|
|
83
88
|
for column in output_columns:
|
|
84
89
|
try:
|
|
85
|
-
root = lineage(column, compiled,
|
|
90
|
+
root = lineage(column, compiled, dialect=self.dialect, scope=scope)
|
|
86
91
|
except SqlglotError:
|
|
87
92
|
# One unresolvable column shouldn't drop the rest of the model.
|
|
88
93
|
continue
|
|
@@ -115,8 +115,10 @@ class ReportBuilder:
|
|
|
115
115
|
data = self.build_data()
|
|
116
116
|
index = out / "index.html"
|
|
117
117
|
index.write_text(inject(index.read_text(encoding="utf-8"), data), encoding="utf-8")
|
|
118
|
+
# Compact, not indented — keeps the debug dump cheap on large projects.
|
|
118
119
|
(out / "dbdocs-data.json").write_text(
|
|
119
|
-
json.dumps(data,
|
|
120
|
+
json.dumps(data, separators=(",", ":"), default=self._json_default),
|
|
121
|
+
encoding="utf-8",
|
|
120
122
|
)
|
|
121
123
|
|
|
122
124
|
logger.info(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dbdocs"
|
|
3
|
-
|
|
3
|
+
dynamic = ["version"]
|
|
4
4
|
description = "Alternative dbt docs site: Catalog + ERD + column-level lineage"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -29,9 +29,12 @@ Repository = "https://github.com/datnguye/dbt-docs"
|
|
|
29
29
|
dbdocs = "dbdocs.main:main"
|
|
30
30
|
|
|
31
31
|
[build-system]
|
|
32
|
-
requires = ["hatchling"]
|
|
32
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
33
33
|
build-backend = "hatchling.build"
|
|
34
34
|
|
|
35
|
+
[tool.hatch.version]
|
|
36
|
+
source = "vcs"
|
|
37
|
+
|
|
35
38
|
[tool.hatch.build.targets.wheel]
|
|
36
39
|
packages = ["dbdocs"]
|
|
37
40
|
artifacts = [
|
|
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
|
|
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
|