dbt-bouncer 1.29.0__tar.gz → 1.30.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.
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/PKG-INFO +1 -1
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/pyproject.toml +3 -3
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_catalog.py +6 -3
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_common.py +3 -1
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_manifest.py +22 -11
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_run_results.py +4 -2
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_lineage.py +4 -2
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_metadata.py +6 -2
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_models.py +5 -1
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/config_file_parser.py +3 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/version.py +1 -1
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/LICENSE +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/README.md +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/__init__.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/dbt_cloud/README.md +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/dbt_cloud/catalog_latest.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/dbt_cloud/manifest_latest.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/dbt_cloud/run_results_latest.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/check_base.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/catalog/check_catalog_sources.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/catalog/check_columns.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/common.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_exposures.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_macros.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_semantic_models.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_snapshots.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_sources.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_unit_tests.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/run_results/check_run_results.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/config_file_validator.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/logger.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/main.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/runner.py +0 -0
- {dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/utils.py +0 -0
|
@@ -39,7 +39,7 @@ name = "dbt-bouncer"
|
|
|
39
39
|
readme = "README.md"
|
|
40
40
|
repository = "https://github.com/godatadriven/dbt-bouncer"
|
|
41
41
|
requires-python = ">=3.11,<3.14"
|
|
42
|
-
version = "1.
|
|
42
|
+
version = "1.30.0"
|
|
43
43
|
|
|
44
44
|
[project.scripts]
|
|
45
45
|
dbt-bouncer = "dbt_bouncer.main:cli"
|
|
@@ -108,11 +108,11 @@ autoflake = "^2"
|
|
|
108
108
|
black = "^25"
|
|
109
109
|
dbt-core = ">=1.10.0,<2"
|
|
110
110
|
dbt-duckdb = "^1"
|
|
111
|
-
isort = "^
|
|
111
|
+
isort = "^7"
|
|
112
112
|
mypy = "^1"
|
|
113
113
|
pex = "^2"
|
|
114
114
|
pre-commit = ">=3,<5"
|
|
115
|
-
pytest = "<
|
|
115
|
+
pytest = "<10"
|
|
116
116
|
pytest-cov = ">=5,<8"
|
|
117
117
|
pytest-xdist = "^3"
|
|
118
118
|
ruff = "^0"
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_catalog.py
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import warnings
|
|
3
|
-
from typing import TYPE_CHECKING, List, Union
|
|
3
|
+
from typing import TYPE_CHECKING, List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
@@ -50,6 +50,7 @@ class DbtBouncerCatalogNode(BaseModel):
|
|
|
50
50
|
def parse_catalog(
|
|
51
51
|
artifact_dir: "Path",
|
|
52
52
|
manifest_obj: "DbtBouncerManifest",
|
|
53
|
+
package_name: Optional[str] = None,
|
|
53
54
|
) -> tuple[List[DbtBouncerCatalogNode], List[DbtBouncerCatalogNode]]:
|
|
54
55
|
"""Parse the catalog.json artifact.
|
|
55
56
|
|
|
@@ -73,7 +74,8 @@ def parse_catalog(
|
|
|
73
74
|
},
|
|
74
75
|
)
|
|
75
76
|
for k, v in catalog_obj.catalog.nodes.items()
|
|
76
|
-
if k.split(".")[-2]
|
|
77
|
+
if k.split(".")[-2]
|
|
78
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
77
79
|
]
|
|
78
80
|
project_catalog_sources = [
|
|
79
81
|
DbtBouncerCatalogNode(
|
|
@@ -86,7 +88,8 @@ def parse_catalog(
|
|
|
86
88
|
},
|
|
87
89
|
)
|
|
88
90
|
for k, v in catalog_obj.catalog.sources.items()
|
|
89
|
-
if k.split(".")[1]
|
|
91
|
+
if k.split(".")[1]
|
|
92
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
90
93
|
]
|
|
91
94
|
logging.info(
|
|
92
95
|
f"Parsed `catalog.json`: {len(project_catalog_nodes)} nodes, {len(project_catalog_sources)} sources.",
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_common.py
RENAMED
|
@@ -145,7 +145,7 @@ def parse_dbt_artifacts(
|
|
|
145
145
|
project_tests,
|
|
146
146
|
project_unit_tests,
|
|
147
147
|
) = parse_manifest_artifact(
|
|
148
|
-
manifest_obj=manifest_obj,
|
|
148
|
+
manifest_obj=manifest_obj, package_name=bouncer_config.package_name
|
|
149
149
|
)
|
|
150
150
|
|
|
151
151
|
# Catalog, must come after manifest is parsed
|
|
@@ -158,6 +158,7 @@ def parse_dbt_artifacts(
|
|
|
158
158
|
project_catalog_nodes, project_catalog_sources = parse_catalog(
|
|
159
159
|
artifact_dir=dbt_artifacts_dir,
|
|
160
160
|
manifest_obj=manifest_obj,
|
|
161
|
+
package_name=bouncer_config.package_name,
|
|
161
162
|
)
|
|
162
163
|
else:
|
|
163
164
|
project_catalog_nodes = []
|
|
@@ -175,6 +176,7 @@ def parse_dbt_artifacts(
|
|
|
175
176
|
project_run_results = parse_run_results_artifact(
|
|
176
177
|
artifact_dir=dbt_artifacts_dir,
|
|
177
178
|
manifest_obj=manifest_obj,
|
|
179
|
+
package_name=bouncer_config.package_name,
|
|
178
180
|
)
|
|
179
181
|
else:
|
|
180
182
|
project_run_results = []
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_manifest.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import warnings
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import Any, Dict, List, Union
|
|
4
|
+
from typing import Any, Dict, List, Optional, Union
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
@@ -173,7 +173,7 @@ def parse_manifest(
|
|
|
173
173
|
|
|
174
174
|
|
|
175
175
|
def parse_manifest_artifact(
|
|
176
|
-
manifest_obj: DbtBouncerManifest,
|
|
176
|
+
manifest_obj: DbtBouncerManifest, package_name: Optional[str] = None
|
|
177
177
|
) -> tuple[
|
|
178
178
|
List[Exposures],
|
|
179
179
|
List[Macros],
|
|
@@ -200,12 +200,14 @@ def parse_manifest_artifact(
|
|
|
200
200
|
project_exposures = [
|
|
201
201
|
v
|
|
202
202
|
for _, v in manifest_obj.manifest.exposures.items()
|
|
203
|
-
if v.package_name
|
|
203
|
+
if v.package_name
|
|
204
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
204
205
|
]
|
|
205
206
|
project_macros = [
|
|
206
207
|
v
|
|
207
208
|
for _, v in manifest_obj.manifest.macros.items()
|
|
208
|
-
if v.package_name
|
|
209
|
+
if v.package_name
|
|
210
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
209
211
|
]
|
|
210
212
|
project_models = []
|
|
211
213
|
project_snapshots = []
|
|
@@ -214,7 +216,9 @@ def parse_manifest_artifact(
|
|
|
214
216
|
if (
|
|
215
217
|
isinstance(v.resource_type, Enum) and v.resource_type.value == "model"
|
|
216
218
|
) or v.resource_type == "model":
|
|
217
|
-
if v.package_name ==
|
|
219
|
+
if v.package_name == (
|
|
220
|
+
package_name or manifest_obj.manifest.metadata.project_name
|
|
221
|
+
):
|
|
218
222
|
project_models.append(
|
|
219
223
|
DbtBouncerModel(
|
|
220
224
|
**{
|
|
@@ -228,7 +232,9 @@ def parse_manifest_artifact(
|
|
|
228
232
|
elif (
|
|
229
233
|
(isinstance(v.resource_type, Enum) and v.resource_type.value == "snapshot")
|
|
230
234
|
or v.resource_type == "snapshot"
|
|
231
|
-
) and v.package_name ==
|
|
235
|
+
) and v.package_name == (
|
|
236
|
+
package_name or manifest_obj.manifest.metadata.project_name
|
|
237
|
+
):
|
|
232
238
|
project_snapshots.append(
|
|
233
239
|
DbtBouncerSnapshot(
|
|
234
240
|
**{
|
|
@@ -241,7 +247,9 @@ def parse_manifest_artifact(
|
|
|
241
247
|
elif (
|
|
242
248
|
(isinstance(v.resource_type, Enum) and v.resource_type.value == "test")
|
|
243
249
|
or v.resource_type == "test"
|
|
244
|
-
) and v.package_name ==
|
|
250
|
+
) and v.package_name == (
|
|
251
|
+
package_name or manifest_obj.manifest.metadata.project_name
|
|
252
|
+
):
|
|
245
253
|
project_tests.append(
|
|
246
254
|
DbtBouncerTest(
|
|
247
255
|
**{
|
|
@@ -258,7 +266,8 @@ def parse_manifest_artifact(
|
|
|
258
266
|
project_unit_tests = [
|
|
259
267
|
v
|
|
260
268
|
for _, v in manifest_obj.manifest.unit_tests.items()
|
|
261
|
-
if v.package_name
|
|
269
|
+
if v.package_name
|
|
270
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
262
271
|
]
|
|
263
272
|
else:
|
|
264
273
|
project_unit_tests = []
|
|
@@ -272,7 +281,8 @@ def parse_manifest_artifact(
|
|
|
272
281
|
},
|
|
273
282
|
)
|
|
274
283
|
for _, v in manifest_obj.manifest.semantic_models.items()
|
|
275
|
-
if v.package_name
|
|
284
|
+
if v.package_name
|
|
285
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
276
286
|
]
|
|
277
287
|
|
|
278
288
|
project_sources = [
|
|
@@ -284,11 +294,12 @@ def parse_manifest_artifact(
|
|
|
284
294
|
},
|
|
285
295
|
)
|
|
286
296
|
for _, v in manifest_obj.manifest.sources.items()
|
|
287
|
-
if v.package_name
|
|
297
|
+
if v.package_name
|
|
298
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
288
299
|
]
|
|
289
300
|
|
|
290
301
|
logging.info(
|
|
291
|
-
f"Parsed `manifest.json`, found `{manifest_obj.manifest.metadata.project_name}` project: {len(project_exposures)} exposures, {len(project_macros)} macros, {len(project_models)} nodes, {len(project_semantic_models)} semantic models, {len(project_snapshots)} snapshots, {len(project_sources)} sources, {len(project_tests)} tests, {len(project_unit_tests)} unit tests.",
|
|
302
|
+
f"Parsed `manifest.json`, found `{(package_name or manifest_obj.manifest.metadata.project_name)}` project: {len(project_exposures)} exposures, {len(project_macros)} macros, {len(project_models)} nodes, {len(project_semantic_models)} semantic models, {len(project_snapshots)} snapshots, {len(project_sources)} sources, {len(project_tests)} tests, {len(project_unit_tests)} unit tests.",
|
|
292
303
|
)
|
|
293
304
|
return (
|
|
294
305
|
project_exposures,
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/parsers_run_results.py
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import warnings
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Union
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
@@ -64,6 +64,7 @@ def parse_run_results(
|
|
|
64
64
|
def parse_run_results_artifact(
|
|
65
65
|
artifact_dir: "Path",
|
|
66
66
|
manifest_obj: "DbtBouncerManifest",
|
|
67
|
+
package_name: Optional[str] = None,
|
|
67
68
|
) -> List[DbtBouncerRunResult]:
|
|
68
69
|
"""Parse the run_results.json artifact.
|
|
69
70
|
|
|
@@ -112,7 +113,8 @@ def parse_run_results_artifact(
|
|
|
112
113
|
},
|
|
113
114
|
)
|
|
114
115
|
for r in run_results_obj.results
|
|
115
|
-
if r.unique_id.split(".")[1]
|
|
116
|
+
if r.unique_id.split(".")[1]
|
|
117
|
+
== (package_name or manifest_obj.manifest.metadata.project_name)
|
|
116
118
|
]
|
|
117
119
|
logging.info(
|
|
118
120
|
f"Parsed `run_results.json`: {len(project_run_results)} results.",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# mypy: disable-error-code="union-attr"
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from typing import TYPE_CHECKING, List, Literal
|
|
4
|
+
from typing import TYPE_CHECKING, List, Literal, Optional
|
|
5
5
|
|
|
6
6
|
from dbt_bouncer.check_base import BaseCheck
|
|
7
7
|
|
|
@@ -53,6 +53,7 @@ class CheckLineagePermittedUpstreamModels(BaseCheck):
|
|
|
53
53
|
model: "DbtBouncerModelBase" = Field(default=None)
|
|
54
54
|
models: List["DbtBouncerModelBase"] = Field(default=[])
|
|
55
55
|
name: Literal["check_lineage_permitted_upstream_models"]
|
|
56
|
+
package_name: Optional[str] = Field(default=None)
|
|
56
57
|
upstream_path_pattern: str
|
|
57
58
|
|
|
58
59
|
def execute(self) -> None:
|
|
@@ -61,7 +62,8 @@ class CheckLineagePermittedUpstreamModels(BaseCheck):
|
|
|
61
62
|
x
|
|
62
63
|
for x in self.model.depends_on.nodes
|
|
63
64
|
if x.split(".")[0] == "model"
|
|
64
|
-
and x.split(".")[1]
|
|
65
|
+
and x.split(".")[1]
|
|
66
|
+
== (self.package_name or self.manifest_obj.manifest.metadata.project_name)
|
|
65
67
|
]
|
|
66
68
|
not_permitted_upstream_models = [
|
|
67
69
|
upstream_model
|
|
@@ -43,6 +43,7 @@ class CheckProjectName(BaseModel):
|
|
|
43
43
|
)
|
|
44
44
|
manifest_obj: "DbtBouncerManifest" = Field(default=None)
|
|
45
45
|
name: Literal["check_project_name"]
|
|
46
|
+
package_name: Optional[str] = Field(default=None)
|
|
46
47
|
project_name_pattern: str
|
|
47
48
|
severity: Optional[Literal["error", "warn"]] = Field(
|
|
48
49
|
default="error",
|
|
@@ -51,11 +52,14 @@ class CheckProjectName(BaseModel):
|
|
|
51
52
|
|
|
52
53
|
def execute(self) -> None:
|
|
53
54
|
"""Execute the check."""
|
|
55
|
+
package_name = (
|
|
56
|
+
self.package_name or self.manifest_obj.manifest.metadata.project_name
|
|
57
|
+
)
|
|
54
58
|
assert (
|
|
55
59
|
re.compile(self.project_name_pattern.strip()).match(
|
|
56
|
-
|
|
60
|
+
package_name,
|
|
57
61
|
)
|
|
58
62
|
is not None
|
|
59
63
|
), (
|
|
60
|
-
f"Project name (`{
|
|
64
|
+
f"Project name (`{package_name}`) does not conform to the supplied regex `({self.project_name_pattern.strip()})`."
|
|
61
65
|
)
|
|
@@ -924,6 +924,7 @@ class CheckModelMaxChainedViews(BaseCheck):
|
|
|
924
924
|
model: "DbtBouncerModelBase" = Field(default=None)
|
|
925
925
|
models: List["DbtBouncerModelBase"] = Field(default=[])
|
|
926
926
|
name: Literal["check_model_max_chained_views"]
|
|
927
|
+
package_name: Optional[str] = Field(default=None)
|
|
927
928
|
|
|
928
929
|
def execute(self) -> None:
|
|
929
930
|
"""Execute the check."""
|
|
@@ -984,7 +985,10 @@ class CheckModelMaxChainedViews(BaseCheck):
|
|
|
984
985
|
max_chained_views=self.max_chained_views,
|
|
985
986
|
models=self.models,
|
|
986
987
|
model_unique_ids_to_check=[self.model.unique_id],
|
|
987
|
-
package_name=
|
|
988
|
+
package_name=(
|
|
989
|
+
self.package_name
|
|
990
|
+
or self.manifest_obj.manifest.metadata.project_name
|
|
991
|
+
),
|
|
988
992
|
),
|
|
989
993
|
)
|
|
990
994
|
== 0
|
|
@@ -72,6 +72,9 @@ class DbtBouncerConfBase(BaseModel):
|
|
|
72
72
|
default=None,
|
|
73
73
|
description="Regexp to match which paths to include.",
|
|
74
74
|
)
|
|
75
|
+
package_name: Optional[str] = Field(
|
|
76
|
+
default=None, description="If you want to run `dbt-bouncer` against a package."
|
|
77
|
+
)
|
|
75
78
|
severity: Union[Literal["error", "warn"], None] = Field(
|
|
76
79
|
default=None,
|
|
77
80
|
description="Severity of the check, one of 'error' or 'warn'.",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/artifact_parsers/dbt_cloud/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/catalog/check_catalog_sources.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_exposures.py
RENAMED
|
File without changes
|
|
File without changes
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_semantic_models.py
RENAMED
|
File without changes
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_snapshots.py
RENAMED
|
File without changes
|
|
File without changes
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/manifest/check_unit_tests.py
RENAMED
|
File without changes
|
{dbt_bouncer-1.29.0 → dbt_bouncer-1.30.0}/src/dbt_bouncer/checks/run_results/check_run_results.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|