dbdocs 1.0.1__tar.gz → 1.0.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.
Files changed (34) hide show
  1. {dbdocs-1.0.1 → dbdocs-1.0.2}/.gitignore +1 -0
  2. {dbdocs-1.0.1 → dbdocs-1.0.2}/PKG-INFO +1 -1
  3. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/extract/nodes.py +39 -14
  4. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/assets/app.js +16 -12
  5. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/assets/style.css +6 -10
  6. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/index.html +1 -1
  7. {dbdocs-1.0.1 → dbdocs-1.0.2}/LICENSE +0 -0
  8. {dbdocs-1.0.1 → dbdocs-1.0.2}/README.md +0 -0
  9. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/__init__.py +0 -0
  10. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/__main__.py +0 -0
  11. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/cli/__init__.py +0 -0
  12. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/cli/main.py +0 -0
  13. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/core/__init__.py +0 -0
  14. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/core/artifacts.py +0 -0
  15. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/core/config.py +0 -0
  16. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/core/exceptions.py +0 -0
  17. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/core/log.py +0 -0
  18. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/extract/__init__.py +0 -0
  19. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/extract/_sqlglot_lineage.py +0 -0
  20. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/extract/column_lineage.py +0 -0
  21. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/extract/erd.py +0 -0
  22. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/extract/erd_json.py +0 -0
  23. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/extract/graph.py +0 -0
  24. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/main.py +0 -0
  25. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/__init__.py +0 -0
  26. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/builder.py +0 -0
  27. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/assets/favicon.svg +0 -0
  28. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/assets/graph/index.css +0 -0
  29. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/assets/graph/index.js +0 -0
  30. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/assets/vendor/marked.min.js +0 -0
  31. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/bundle/assets/vendor/minisearch.min.js +0 -0
  32. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/deploy.py +0 -0
  33. {dbdocs-1.0.1 → dbdocs-1.0.2}/dbdocs/site/inject.py +0 -0
  34. {dbdocs-1.0.1 → dbdocs-1.0.2}/pyproject.toml +0 -0
@@ -166,3 +166,4 @@ pnpm-debug.log*
166
166
 
167
167
  # dbdocs DEBUG file log
168
168
  logs/
169
+ .DS_Store
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbdocs
3
- Version: 1.0.1
3
+ Version: 1.0.2
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
@@ -12,27 +12,52 @@ from typing import Any
12
12
  from dbdocs.core.artifacts import NODE_PREFIXES, db_schema, node_name
13
13
 
14
14
 
15
+ def _column_entry(name: str, manifest_column: Any, col_type: str) -> dict:
16
+ """One column record. Newlines in the description become ``<br>`` for HTML."""
17
+ description = getattr(manifest_column, "description", "") or "" if manifest_column else ""
18
+ return {
19
+ "name": name,
20
+ "type": col_type or "",
21
+ "tags": (getattr(manifest_column, "tags", []) or []) if manifest_column else [],
22
+ "description": description.replace("\n", "<br>"),
23
+ }
24
+
25
+
15
26
  def _columns(model: Any, catalog_node: Any) -> list:
16
- """Merge manifest column metadata (description/tags) with catalog types.
27
+ """Build a node's columns: the manifest is the source of truth, the catalog
28
+ enriches it.
29
+
30
+ The **manifest** decides which columns are documented and carries their
31
+ metadata (description, tags, ``data_type``); the **catalog** *enriches* — it
32
+ supplies the warehouse-confirmed type and any columns the manifest didn't
33
+ document. It never replaces the manifest, so a model absent from a
34
+ stale/partial ``catalog.json`` still shows every documented column.
17
35
 
18
- Iterates the catalog's columns (the warehouse truth for which columns exist
19
- and their types) and layers on the manifest description/tags when present.
20
- Newlines in descriptions become ``<br>`` so they survive HTML rendering.
36
+ Manifest columns come first, in manifest order, each with its type enriched
37
+ from the catalog when present (falling back to the manifest ``data_type``).
38
+ The catalog keys columns by the warehouse's casing (Snowflake upper-cases
39
+ them) while the manifest keeps the modeled casing, so the catalog type lookup
40
+ is case-insensitive. Catalog-only columns are appended afterwards.
21
41
  """
22
42
  manifest_columns = getattr(model, "columns", {}) or {}
23
43
  catalog_columns = getattr(catalog_node, "columns", {}) or {} if catalog_node else {}
44
+ catalog_by_lower = {str(name).lower(): col for name, col in catalog_columns.items()}
45
+
24
46
  columns = []
25
- for name in catalog_columns:
26
- manifest_column = manifest_columns.get(name)
27
- description = getattr(manifest_column, "description", "") or "" if manifest_column else ""
28
- columns.append(
29
- {
30
- "name": name,
31
- "type": catalog_columns[name].type,
32
- "tags": (getattr(manifest_column, "tags", []) or []) if manifest_column else [],
33
- "description": description.replace("\n", "<br>"),
34
- }
47
+ seen_lower = set()
48
+ for name, manifest_column in manifest_columns.items():
49
+ lower = str(name).lower()
50
+ seen_lower.add(lower)
51
+ catalog_column = catalog_by_lower.get(lower)
52
+ col_type = getattr(catalog_column, "type", None) or getattr(
53
+ manifest_column, "data_type", None
35
54
  )
55
+ columns.append(_column_entry(name, manifest_column, col_type or ""))
56
+
57
+ for name, catalog_column in catalog_columns.items():
58
+ if str(name).lower() in seen_lower:
59
+ continue
60
+ columns.append(_column_entry(name, None, getattr(catalog_column, "type", "") or ""))
36
61
  return columns
37
62
 
38
63
 
@@ -120,12 +120,23 @@
120
120
  el("span", {}, ["Generated by "]),
121
121
  el("a", { href: "https://github.com/datnguye/dbt-docs", target: "_blank", rel: "noopener" }, ["dbdocs"]),
122
122
  ]);
123
+ var meta = footerMeta();
124
+ if (meta) left.appendChild(el("span", { class: "cf-meta" }, [" · " + meta]));
123
125
  var right = el("a", { class: "cf-top", href: "#", onclick: function (e) { e.preventDefault(); app.scrollTop = 0; } }, ["↑ Back to top"]);
124
126
  foot.appendChild(left);
125
127
  foot.appendChild(right);
126
128
  return foot;
127
129
  }
128
130
 
131
+ /* "snowflake · N column-lineage edges" — the build metadata shown in the
132
+ content footer. The "Generated X" part lives in the topbar (see boot). */
133
+ function footerMeta() {
134
+ var parts = [];
135
+ if (META.adapter_type) parts.push(META.adapter_type);
136
+ parts.push(Object.keys(COLLIN).length + " column-lineage edges");
137
+ return parts.join(" · ");
138
+ }
139
+
129
140
  var RTYPE_ORDER = { model: 0, snapshot: 1, seed: 2, source: 3 };
130
141
 
131
142
  function buildNav() {
@@ -456,17 +467,6 @@
456
467
  link.hidden = false;
457
468
  }
458
469
 
459
- function initTopbarMeta() {
460
- var box = document.getElementById("topbar-meta");
461
- if (!box) return;
462
- var parts = [];
463
- if (META.generated_at) parts.push("Generated " + META.generated_at);
464
- if (META.adapter_type) parts.push(META.adapter_type);
465
- parts.push(Object.keys(COLLIN).length + " column-lineage edges");
466
- box.textContent = parts.join(" · ");
467
- box.hidden = false;
468
- }
469
-
470
470
  function initFooter() {
471
471
  var footer = document.getElementById("site-footer");
472
472
  if (!footer) return;
@@ -486,8 +486,12 @@
486
486
  function boot() {
487
487
  document.getElementById("brand-name").textContent = META.site_name || "dbt docs";
488
488
  document.title = META.site_name || "dbt docs";
489
+ if (META.generated_at) {
490
+ var gen = document.getElementById("brand-generated");
491
+ gen.textContent = "Generated " + META.generated_at;
492
+ gen.hidden = false;
493
+ }
489
494
  initRepo();
490
- initTopbarMeta();
491
495
  initFooter();
492
496
  initTheme();
493
497
  buildNav();
@@ -52,8 +52,9 @@ code, pre { font-family: "SF Mono", "Roboto Mono", Menlo, Consolas, monospace; }
52
52
  background: var(--bg-elev); border-bottom: 1px solid var(--border);
53
53
  position: sticky; top: 0; z-index: 30;
54
54
  }
55
- .brand { display: flex; align-items: center; gap: 8px; font-weight: 600; min-width: 160px; }
56
- .brand-mark { display: block; width: 24px; height: 24px; border-radius: 6px; }
55
+ .brand { display: flex; align-items: baseline; gap: 8px; font-weight: 600; min-width: 160px; }
56
+ .brand-mark { display: block; width: 24px; height: 24px; border-radius: 6px; align-self: center; }
57
+ .brand-generated { color: var(--text-soft); font-size: 12px; font-weight: 400; white-space: nowrap; }
57
58
  .search-wrap { position: relative; flex: 1; max-width: 520px; }
58
59
  #search {
59
60
  width: 100%; padding: 7px 12px; border-radius: var(--radius);
@@ -118,21 +119,16 @@ code, pre { font-family: "SF Mono", "Roboto Mono", Menlo, Consolas, monospace; }
118
119
  }
119
120
  .footer-copy { color: var(--text-soft); font-size: 12px; }
120
121
 
121
- /* Build metadata in the header (generated / adapter / edges) */
122
- .topbar-meta {
123
- color: var(--text-soft); font-size: 11.5px; white-space: nowrap;
124
- padding-right: 6px; flex-shrink: 0;
125
- }
126
- @media (max-width: 1100px) { .topbar-meta { display: none; } }
127
-
128
122
  /* End-of-page content footer */
129
123
  .content-foot {
130
124
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
131
125
  margin-top: 40px; padding-top: 16px; border-top: 1px solid var(--border);
132
126
  color: var(--text-soft); font-size: 12px;
133
127
  }
134
- .content-foot .cf-left { display: inline-flex; align-items: center; gap: 6px; }
128
+ .content-foot .cf-left { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
135
129
  .content-foot .cf-left .ic { color: var(--text-soft); }
130
+ /* Build metadata (generated / adapter / edges) appended to the footer's left */
131
+ .content-foot .cf-meta { color: var(--text-soft); }
136
132
  .content-foot .cf-top { color: var(--text-soft); }
137
133
  .content-foot .cf-top:hover { color: var(--accent); }
138
134
  .bmc {
@@ -14,8 +14,8 @@
14
14
  <div class="brand">
15
15
  <img class="brand-mark" src="assets/favicon.svg" alt="" width="24" height="24" />
16
16
  <span class="brand-name" id="brand-name">dbt docs</span>
17
+ <span class="brand-generated" id="brand-generated" hidden></span>
17
18
  </div>
18
- <div class="topbar-meta" id="topbar-meta" hidden></div>
19
19
  <div class="search-wrap">
20
20
  <input id="search" type="search" placeholder="Search models, sources, columns…" autocomplete="off" />
21
21
  <div id="search-results" class="search-results" hidden></div>
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