trellis-datamodel 0.3.3__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.
- trellis_datamodel/__init__.py +8 -0
- trellis_datamodel/adapters/__init__.py +41 -0
- trellis_datamodel/adapters/base.py +147 -0
- trellis_datamodel/adapters/dbt_core.py +975 -0
- trellis_datamodel/cli.py +292 -0
- trellis_datamodel/config.py +239 -0
- trellis_datamodel/models/__init__.py +13 -0
- trellis_datamodel/models/schemas.py +28 -0
- trellis_datamodel/routes/__init__.py +11 -0
- trellis_datamodel/routes/data_model.py +221 -0
- trellis_datamodel/routes/manifest.py +110 -0
- trellis_datamodel/routes/schema.py +183 -0
- trellis_datamodel/server.py +101 -0
- trellis_datamodel/static/_app/env.js +1 -0
- trellis_datamodel/static/_app/immutable/assets/0.ByDwyx3a.css +1 -0
- trellis_datamodel/static/_app/immutable/assets/2.DLAp_5AW.css +1 -0
- trellis_datamodel/static/_app/immutable/assets/trellis_squared.CTOnsdDx.svg +127 -0
- trellis_datamodel/static/_app/immutable/chunks/8ZaN1sxc.js +1 -0
- trellis_datamodel/static/_app/immutable/chunks/BfBfOTnK.js +1 -0
- trellis_datamodel/static/_app/immutable/chunks/C3yhlRfZ.js +2 -0
- trellis_datamodel/static/_app/immutable/chunks/CK3bXPEX.js +1 -0
- trellis_datamodel/static/_app/immutable/chunks/CXDUumOQ.js +1 -0
- trellis_datamodel/static/_app/immutable/chunks/DDNfEvut.js +1 -0
- trellis_datamodel/static/_app/immutable/chunks/DUdVct7e.js +1 -0
- trellis_datamodel/static/_app/immutable/chunks/QRltG_J6.js +2 -0
- trellis_datamodel/static/_app/immutable/chunks/zXDdy2c_.js +1 -0
- trellis_datamodel/static/_app/immutable/entry/app.abCkWeAJ.js +2 -0
- trellis_datamodel/static/_app/immutable/entry/start.B7CjH6Z7.js +1 -0
- trellis_datamodel/static/_app/immutable/nodes/0.bFI_DI3G.js +1 -0
- trellis_datamodel/static/_app/immutable/nodes/1.J_r941Qf.js +1 -0
- trellis_datamodel/static/_app/immutable/nodes/2.WqbMkq6o.js +27 -0
- trellis_datamodel/static/_app/version.json +1 -0
- trellis_datamodel/static/index.html +40 -0
- trellis_datamodel/static/robots.txt +3 -0
- trellis_datamodel/static/trellis_squared.svg +127 -0
- trellis_datamodel/tests/__init__.py +2 -0
- trellis_datamodel/tests/conftest.py +132 -0
- trellis_datamodel/tests/test_cli.py +526 -0
- trellis_datamodel/tests/test_data_model.py +151 -0
- trellis_datamodel/tests/test_dbt_schema.py +892 -0
- trellis_datamodel/tests/test_manifest.py +72 -0
- trellis_datamodel/tests/test_server_static.py +44 -0
- trellis_datamodel/tests/test_yaml_handler.py +228 -0
- trellis_datamodel/utils/__init__.py +2 -0
- trellis_datamodel/utils/yaml_handler.py +365 -0
- trellis_datamodel-0.3.3.dist-info/METADATA +333 -0
- trellis_datamodel-0.3.3.dist-info/RECORD +52 -0
- trellis_datamodel-0.3.3.dist-info/WHEEL +5 -0
- trellis_datamodel-0.3.3.dist-info/entry_points.txt +2 -0
- trellis_datamodel-0.3.3.dist-info/licenses/LICENSE +661 -0
- trellis_datamodel-0.3.3.dist-info/licenses/NOTICE +6 -0
- trellis_datamodel-0.3.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"1766080526003"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
7
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
8
|
+
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
9
|
+
|
|
10
|
+
<link rel="modulepreload" href="/_app/immutable/entry/start.B7CjH6Z7.js">
|
|
11
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/CXDUumOQ.js">
|
|
12
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/zXDdy2c_.js">
|
|
13
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/8ZaN1sxc.js">
|
|
14
|
+
<link rel="modulepreload" href="/_app/immutable/entry/app.abCkWeAJ.js">
|
|
15
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/QRltG_J6.js">
|
|
16
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/DDNfEvut.js">
|
|
17
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/BfBfOTnK.js">
|
|
18
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/DUdVct7e.js">
|
|
19
|
+
</head>
|
|
20
|
+
<body data-sveltekit-preload-data="hover">
|
|
21
|
+
<div style="display: contents">
|
|
22
|
+
<script>
|
|
23
|
+
{
|
|
24
|
+
__sveltekit_nmm995 = {
|
|
25
|
+
base: ""
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const element = document.currentScript.parentElement;
|
|
29
|
+
|
|
30
|
+
Promise.all([
|
|
31
|
+
import("/_app/immutable/entry/start.B7CjH6Z7.js"),
|
|
32
|
+
import("/_app/immutable/entry/app.abCkWeAJ.js")
|
|
33
|
+
]).then(([kit, app]) => {
|
|
34
|
+
kit.start(app, element);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
</div>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
3
|
+
|
|
4
|
+
<svg
|
|
5
|
+
width="632.17517"
|
|
6
|
+
height="616.88739"
|
|
7
|
+
viewBox="0 0 632.17517 616.88739"
|
|
8
|
+
version="1.1"
|
|
9
|
+
id="svg1"
|
|
10
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
11
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
|
14
|
+
<sodipodi:namedview
|
|
15
|
+
id="namedview1"
|
|
16
|
+
pagecolor="#505050"
|
|
17
|
+
bordercolor="#eeeeee"
|
|
18
|
+
borderopacity="1"
|
|
19
|
+
inkscape:showpageshadow="0"
|
|
20
|
+
inkscape:pageopacity="0"
|
|
21
|
+
inkscape:pagecheckerboard="0"
|
|
22
|
+
inkscape:deskcolor="#505050"
|
|
23
|
+
inkscape:document-units="px"
|
|
24
|
+
inkscape:export-bgcolor="#ffffff00" />
|
|
25
|
+
<defs
|
|
26
|
+
id="defs1" />
|
|
27
|
+
<g
|
|
28
|
+
inkscape:label="Layer 1"
|
|
29
|
+
inkscape:groupmode="layer"
|
|
30
|
+
id="layer1"
|
|
31
|
+
transform="translate(-85.523941,-103.00706)">
|
|
32
|
+
<rect
|
|
33
|
+
style="fill:#0f766e;fill-opacity:1;stroke:#ffffff;stroke-width:8;stroke-dasharray:none"
|
|
34
|
+
id="rect2"
|
|
35
|
+
width="624.17517"
|
|
36
|
+
height="608.88739"
|
|
37
|
+
x="89.523941"
|
|
38
|
+
y="107.00706"
|
|
39
|
+
ry="63.55658" />
|
|
40
|
+
<g
|
|
41
|
+
id="g5"
|
|
42
|
+
transform="matrix(0.93741364,0,0,1,14.19907,8.8683603)">
|
|
43
|
+
<g
|
|
44
|
+
id="path2"
|
|
45
|
+
transform="translate(-4.1805851,-45.986436)">
|
|
46
|
+
<path
|
|
47
|
+
style="color:#000000;fill:#0f766e;-inkscape-stroke:none"
|
|
48
|
+
d="M 136.58691,304.3442 647.2728,256.50993"
|
|
49
|
+
id="path3" />
|
|
50
|
+
<path
|
|
51
|
+
style="color:#000000;fill:#ffffff;-inkscape-stroke:none"
|
|
52
|
+
d="M 656.86575,233.04229 145.1331,284.01172 138.49219,324.67578 649.17773,276.8418 Z"
|
|
53
|
+
id="path4"
|
|
54
|
+
sodipodi:nodetypes="ccccc" />
|
|
55
|
+
</g>
|
|
56
|
+
<g
|
|
57
|
+
id="path2-1"
|
|
58
|
+
transform="translate(18.716165,120.25339)">
|
|
59
|
+
<path
|
|
60
|
+
style="color:#000000;fill:#0f766e;-inkscape-stroke:none"
|
|
61
|
+
d="M 136.58691,304.3442 647.2728,256.50993"
|
|
62
|
+
id="path3-9" />
|
|
63
|
+
<path
|
|
64
|
+
style="color:#000000;fill:#ffffff;-inkscape-stroke:none"
|
|
65
|
+
d="M 656.86575,233.04229 145.1331,284.01172 138.49219,324.67578 649.17773,276.8418 Z"
|
|
66
|
+
id="path4-2"
|
|
67
|
+
sodipodi:nodetypes="ccccc" />
|
|
68
|
+
</g>
|
|
69
|
+
<g
|
|
70
|
+
id="path2-8"
|
|
71
|
+
transform="translate(10.891685,286.98367)">
|
|
72
|
+
<path
|
|
73
|
+
style="color:#000000;fill:#0f766e;-inkscape-stroke:none"
|
|
74
|
+
d="M 136.58691,304.3442 647.2728,256.50993"
|
|
75
|
+
id="path3-8" />
|
|
76
|
+
<path
|
|
77
|
+
style="color:#000000;fill:#ffffff;-inkscape-stroke:none"
|
|
78
|
+
d="M 656.86575,233.04229 145.1331,284.01172 138.49219,324.67578 649.17773,276.8418 Z"
|
|
79
|
+
id="path4-4"
|
|
80
|
+
sodipodi:nodetypes="ccccc" />
|
|
81
|
+
</g>
|
|
82
|
+
</g>
|
|
83
|
+
<g
|
|
84
|
+
id="g4"
|
|
85
|
+
transform="matrix(1,0,0,0.91186122,-1.4780604,38.567585)">
|
|
86
|
+
<g
|
|
87
|
+
id="path2-7"
|
|
88
|
+
transform="rotate(-88.136049,543.15395,249.92424)">
|
|
89
|
+
<path
|
|
90
|
+
style="color:#000000;fill:#0f766e;-inkscape-stroke:none"
|
|
91
|
+
d="M 136.58691,304.3442 647.2728,256.50993"
|
|
92
|
+
id="path3-1" />
|
|
93
|
+
<path
|
|
94
|
+
style="color:#000000;fill:#ffffff;-inkscape-stroke:none"
|
|
95
|
+
d="M 656.86575,233.04229 145.1331,284.01172 138.49219,324.67578 649.17773,276.8418 Z"
|
|
96
|
+
id="path4-5"
|
|
97
|
+
sodipodi:nodetypes="ccccc" />
|
|
98
|
+
</g>
|
|
99
|
+
<g
|
|
100
|
+
id="path2-7-4"
|
|
101
|
+
transform="rotate(-88.136049,461.52659,338.48873)">
|
|
102
|
+
<path
|
|
103
|
+
style="color:#000000;fill:#0f766e;-inkscape-stroke:none"
|
|
104
|
+
d="M 136.58691,304.3442 647.2728,256.50993"
|
|
105
|
+
id="path3-1-8" />
|
|
106
|
+
<path
|
|
107
|
+
style="color:#000000;fill:#ffffff;-inkscape-stroke:none"
|
|
108
|
+
d="M 656.86575,233.04229 145.1331,284.01172 138.49219,324.67578 649.17773,276.8418 Z"
|
|
109
|
+
id="path4-5-2"
|
|
110
|
+
sodipodi:nodetypes="ccccc" />
|
|
111
|
+
</g>
|
|
112
|
+
<g
|
|
113
|
+
id="path2-7-4-8"
|
|
114
|
+
transform="rotate(-88.136049,377.62543,435.71562)">
|
|
115
|
+
<path
|
|
116
|
+
style="color:#000000;fill:#0f766e;-inkscape-stroke:none"
|
|
117
|
+
d="M 136.58691,304.3442 647.2728,256.50993"
|
|
118
|
+
id="path3-1-8-5" />
|
|
119
|
+
<path
|
|
120
|
+
style="color:#000000;fill:#ffffff;-inkscape-stroke:none"
|
|
121
|
+
d="M 656.86575,233.04229 145.1331,284.01172 138.49219,324.67578 649.17773,276.8418 Z"
|
|
122
|
+
id="path4-5-2-1"
|
|
123
|
+
sodipodi:nodetypes="ccccc" />
|
|
124
|
+
</g>
|
|
125
|
+
</g>
|
|
126
|
+
</g>
|
|
127
|
+
</svg>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Pytest fixtures for backend tests."""
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import tempfile
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
import pytest
|
|
8
|
+
from fastapi.testclient import TestClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Create a persistent temp directory for the entire test session
|
|
12
|
+
# This is set BEFORE any backend modules are imported
|
|
13
|
+
_TEST_TEMP_DIR = tempfile.mkdtemp(prefix="datamodel_test_")
|
|
14
|
+
os.environ["DATAMODEL_TEST_DIR"] = _TEST_TEMP_DIR
|
|
15
|
+
|
|
16
|
+
# Create required directory structure
|
|
17
|
+
os.makedirs(os.path.join(_TEST_TEMP_DIR, "models", "3_core"), exist_ok=True)
|
|
18
|
+
|
|
19
|
+
# Create minimal config.yml
|
|
20
|
+
with open(os.path.join(_TEST_TEMP_DIR, "config.yml"), "w") as f:
|
|
21
|
+
f.write("dbt_project_path: .\n")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def pytest_sessionfinish(session, exitstatus):
|
|
25
|
+
"""Clean up temp directory after all tests complete."""
|
|
26
|
+
if os.path.exists(_TEST_TEMP_DIR):
|
|
27
|
+
shutil.rmtree(_TEST_TEMP_DIR, ignore_errors=True)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture(autouse=True)
|
|
31
|
+
def clean_test_files():
|
|
32
|
+
"""Clean up test files before each test to ensure isolation."""
|
|
33
|
+
# Clean data model file before each test
|
|
34
|
+
data_model_path = os.path.join(_TEST_TEMP_DIR, "data_model.yml")
|
|
35
|
+
if os.path.exists(data_model_path):
|
|
36
|
+
os.remove(data_model_path)
|
|
37
|
+
|
|
38
|
+
# Clean canvas layout file before each test
|
|
39
|
+
canvas_layout_path = os.path.join(_TEST_TEMP_DIR, "canvas_layout.yml")
|
|
40
|
+
if os.path.exists(canvas_layout_path):
|
|
41
|
+
os.remove(canvas_layout_path)
|
|
42
|
+
|
|
43
|
+
# Clean manifest file
|
|
44
|
+
manifest_path = os.path.join(_TEST_TEMP_DIR, "manifest.json")
|
|
45
|
+
if os.path.exists(manifest_path):
|
|
46
|
+
os.remove(manifest_path)
|
|
47
|
+
|
|
48
|
+
# Clean model yml files (recursively) to avoid cross-test leakage
|
|
49
|
+
models_dir = os.path.join(_TEST_TEMP_DIR, "models", "3_core")
|
|
50
|
+
if os.path.exists(models_dir):
|
|
51
|
+
for root, _, files in os.walk(models_dir):
|
|
52
|
+
for fname in files:
|
|
53
|
+
if fname.endswith((".yml", ".yaml")):
|
|
54
|
+
os.remove(os.path.join(root, fname))
|
|
55
|
+
|
|
56
|
+
yield
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@pytest.fixture
|
|
60
|
+
def temp_dir():
|
|
61
|
+
"""Return the shared test temp directory."""
|
|
62
|
+
return _TEST_TEMP_DIR
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.fixture
|
|
66
|
+
def temp_data_model_path():
|
|
67
|
+
"""Return path for the data model file (in session temp dir)."""
|
|
68
|
+
return os.path.join(_TEST_TEMP_DIR, "data_model.yml")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@pytest.fixture
|
|
72
|
+
def temp_canvas_layout_path():
|
|
73
|
+
"""Return path for the canvas layout file (in session temp dir)."""
|
|
74
|
+
return os.path.join(_TEST_TEMP_DIR, "canvas_layout.yml")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def temp_dbt_project():
|
|
79
|
+
"""Return the test dbt project directory."""
|
|
80
|
+
return _TEST_TEMP_DIR
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@pytest.fixture
|
|
84
|
+
def mock_manifest_data():
|
|
85
|
+
"""Return mock manifest data."""
|
|
86
|
+
return {
|
|
87
|
+
"nodes": {
|
|
88
|
+
"model.project.users": {
|
|
89
|
+
"unique_id": "model.project.users",
|
|
90
|
+
"resource_type": "model",
|
|
91
|
+
"name": "users",
|
|
92
|
+
"schema": "public",
|
|
93
|
+
"alias": "users",
|
|
94
|
+
"original_file_path": "models/3_core/users.sql",
|
|
95
|
+
"columns": {
|
|
96
|
+
"id": {"name": "id", "type": "integer"},
|
|
97
|
+
"name": {"name": "name", "type": "text"},
|
|
98
|
+
},
|
|
99
|
+
"description": "User table",
|
|
100
|
+
"config": {"materialized": "table"},
|
|
101
|
+
"tags": ["core"],
|
|
102
|
+
},
|
|
103
|
+
"model.project.orders": {
|
|
104
|
+
"unique_id": "model.project.orders",
|
|
105
|
+
"resource_type": "model",
|
|
106
|
+
"name": "orders",
|
|
107
|
+
"schema": "public",
|
|
108
|
+
"alias": "orders",
|
|
109
|
+
"original_file_path": "models/3_core/orders.sql",
|
|
110
|
+
"columns": {},
|
|
111
|
+
"description": "Orders table",
|
|
112
|
+
"config": {"materialized": "view"},
|
|
113
|
+
"tags": [],
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@pytest.fixture
|
|
120
|
+
def mock_manifest(mock_manifest_data):
|
|
121
|
+
"""Create a mock manifest.json file."""
|
|
122
|
+
manifest_path = os.path.join(_TEST_TEMP_DIR, "manifest.json")
|
|
123
|
+
with open(manifest_path, "w") as f:
|
|
124
|
+
json.dump(mock_manifest_data, f)
|
|
125
|
+
return manifest_path
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@pytest.fixture
|
|
129
|
+
def test_client(mock_manifest):
|
|
130
|
+
"""Create a test client. Config is already set via environment variables."""
|
|
131
|
+
from trellis_datamodel.server import app
|
|
132
|
+
return TestClient(app)
|