dagster-dbt 0.28.5__tar.gz → 0.28.6__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.
- {dagster_dbt-0.28.5/dagster_dbt.egg-info → dagster_dbt-0.28.6}/PKG-INFO +2 -2
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/cli_invocation.py +7 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/client.py +91 -18
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/run_handler.py +17 -0
- dagster_dbt-0.28.6/dagster_dbt/version.py +1 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6/dagster_dbt.egg-info}/PKG-INFO +2 -2
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt.egg-info/requires.txt +1 -1
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/setup.py +1 -1
- dagster_dbt-0.28.5/dagster_dbt/version.py +0 -1
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/LICENSE +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/MANIFEST.in +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/README.md +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/asset_decorator.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/asset_specs.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/asset_utils.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cli/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cli/app.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud/asset_defs.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud/cli.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud/ops.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud/resources.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud/types.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud/utils.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/asset_decorator.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/resources.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/sensor_builder.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/cloud_v2/types.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/compat.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/components/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/components/dbt_project/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/components/dbt_project/component.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/components/dbt_project/scaffolder.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/core/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/core/dbt_cli_event.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/core/dbt_cli_invocation.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/core/dbt_event_iterator.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/core/resource.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/core/utils.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/dagster_dbt_translator.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/dbt_core_version.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/dbt_manifest.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/dbt_manifest_asset_selection.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/dbt_project.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/dbt_project_manager.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/dbt_version.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/errors.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/freshness_builder.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/__init__.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/pyproject.toml.jinja +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/scaffold/__init__.py.jinja +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/scaffold/assets.py.jinja +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/scaffold/definitions.py.jinja +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/scaffold/project.py.jinja +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/scaffold/schedules.py.jinja +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/include/setup.py.jinja +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/metadata_set.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/py.typed +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt/utils.py +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt.egg-info/SOURCES.txt +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt.egg-info/dependency_links.txt +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt.egg-info/entry_points.txt +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt.egg-info/not-zip-safe +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/dagster_dbt.egg-info/top_level.txt +0 -0
- {dagster_dbt-0.28.5 → dagster_dbt-0.28.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dagster-dbt
|
|
3
|
-
Version: 0.28.
|
|
3
|
+
Version: 0.28.6
|
|
4
4
|
Summary: A Dagster integration for dbt
|
|
5
5
|
Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-dbt
|
|
6
6
|
Author: Dagster Labs
|
|
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Requires-Python: >=3.10,<3.14
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: dagster==1.12.
|
|
17
|
+
Requires-Dist: dagster==1.12.6
|
|
18
18
|
Requires-Dist: dbt-core<1.11,>=1.7
|
|
19
19
|
Requires-Dist: gitpython
|
|
20
20
|
Requires-Dist: Jinja2
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
from collections.abc import Iterator, Mapping, Sequence
|
|
2
3
|
from typing import Any, Optional, Union
|
|
3
4
|
|
|
@@ -54,6 +55,12 @@ class DbtCloudCliInvocation:
|
|
|
54
55
|
self, timeout: Optional[float] = None
|
|
55
56
|
) -> Iterator[Union[AssetCheckEvaluation, AssetCheckResult, AssetMaterialization, Output]]:
|
|
56
57
|
run = self.run_handler.wait(timeout=timeout)
|
|
58
|
+
|
|
59
|
+
# Write dbt Cloud run logs to stdout
|
|
60
|
+
logs = self.run_handler.get_run_logs()
|
|
61
|
+
if logs:
|
|
62
|
+
sys.stdout.write(logs)
|
|
63
|
+
|
|
57
64
|
if "run_results.json" in self.run_handler.list_run_artifacts():
|
|
58
65
|
run_results = DbtCloudJobRunResults.from_run_results_json(
|
|
59
66
|
run_results_json=self.run_handler.get_run_results()
|
|
@@ -92,7 +92,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
92
92
|
data: Optional[Mapping[str, Any]] = None,
|
|
93
93
|
params: Optional[Mapping[str, Any]] = None,
|
|
94
94
|
session_attr: str = "_get_session",
|
|
95
|
-
) ->
|
|
95
|
+
) -> requests.Response:
|
|
96
96
|
url = f"{base_url}/{endpoint}" if endpoint else base_url
|
|
97
97
|
|
|
98
98
|
num_retries = 0
|
|
@@ -107,7 +107,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
107
107
|
timeout=self.request_timeout,
|
|
108
108
|
)
|
|
109
109
|
response.raise_for_status()
|
|
110
|
-
return response
|
|
110
|
+
return response
|
|
111
111
|
except RequestException as e:
|
|
112
112
|
self._log.error(
|
|
113
113
|
f"Request to dbt Cloud API failed for url {url} with method {method} : {e}"
|
|
@@ -143,7 +143,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
143
143
|
"""
|
|
144
144
|
if not description:
|
|
145
145
|
description = "A job that runs dbt models, sources, and tests."
|
|
146
|
-
|
|
146
|
+
response = self._make_request(
|
|
147
147
|
method="post",
|
|
148
148
|
endpoint="jobs",
|
|
149
149
|
base_url=self.api_v2_url,
|
|
@@ -155,7 +155,8 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
155
155
|
"description": description,
|
|
156
156
|
"job_type": "other",
|
|
157
157
|
},
|
|
158
|
-
)
|
|
158
|
+
)
|
|
159
|
+
return response.json()["data"]
|
|
159
160
|
|
|
160
161
|
def list_jobs(
|
|
161
162
|
self,
|
|
@@ -185,7 +186,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
185
186
|
"limit": DAGSTER_DBT_CLOUD_LIST_JOBS_INDIVIDUAL_REQUEST_LIMIT,
|
|
186
187
|
"offset": len(results),
|
|
187
188
|
},
|
|
188
|
-
)["data"]:
|
|
189
|
+
).json()["data"]:
|
|
189
190
|
results.extend(jobs)
|
|
190
191
|
if len(jobs) < DAGSTER_DBT_CLOUD_LIST_JOBS_INDIVIDUAL_REQUEST_LIMIT:
|
|
191
192
|
break
|
|
@@ -201,7 +202,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
201
202
|
method="get",
|
|
202
203
|
endpoint=f"jobs/{job_id}",
|
|
203
204
|
base_url=self.api_v2_url,
|
|
204
|
-
)["data"]
|
|
205
|
+
).json()["data"]
|
|
205
206
|
|
|
206
207
|
def destroy_job(self, job_id: int) -> Mapping[str, Any]:
|
|
207
208
|
"""Destroys a given dbt Cloud job.
|
|
@@ -213,7 +214,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
213
214
|
method="delete",
|
|
214
215
|
endpoint=f"jobs/{job_id}",
|
|
215
216
|
base_url=self.api_v2_url,
|
|
216
|
-
)["data"]
|
|
217
|
+
).json()["data"]
|
|
217
218
|
|
|
218
219
|
def trigger_job_run(
|
|
219
220
|
self, job_id: int, steps_override: Optional[Sequence[str]] = None
|
|
@@ -237,7 +238,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
237
238
|
data={"steps_override": steps_override, "cause": DAGSTER_ADHOC_TRIGGER_CAUSE}
|
|
238
239
|
if steps_override
|
|
239
240
|
else {"cause": DAGSTER_ADHOC_TRIGGER_CAUSE},
|
|
240
|
-
)["data"]
|
|
241
|
+
).json()["data"]
|
|
241
242
|
|
|
242
243
|
def get_runs_batch(
|
|
243
244
|
self,
|
|
@@ -278,26 +279,35 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
278
279
|
"finished_at__range": f"""["{finished_at_lower_bound.isoformat()}", "{finished_at_upper_bound.isoformat()}"]""",
|
|
279
280
|
"order_by": "finished_at",
|
|
280
281
|
},
|
|
281
|
-
)
|
|
282
|
+
).json()
|
|
282
283
|
data = cast("Sequence[Mapping[str, Any]]", resp["data"])
|
|
283
284
|
total_count = resp["extra"]["pagination"]["total_count"]
|
|
284
285
|
return data, total_count
|
|
285
286
|
|
|
286
|
-
def get_run_details(
|
|
287
|
+
def get_run_details(
|
|
288
|
+
self, run_id: int, include_related: Optional[Sequence[str]] = None
|
|
289
|
+
) -> Mapping[str, Any]:
|
|
287
290
|
"""Retrieves the details of a given dbt Cloud Run.
|
|
288
291
|
|
|
289
292
|
Args:
|
|
290
|
-
run_id (
|
|
293
|
+
run_id (int): The dbt Cloud Run ID. You can retrieve this value from the
|
|
291
294
|
URL of the given run in the dbt Cloud UI.
|
|
295
|
+
include_related (Optional[Sequence[str]]): List of related fields to pull with the run.
|
|
296
|
+
Valid values are "trigger", "job", "debug_logs", and "run_steps".
|
|
292
297
|
|
|
293
298
|
Returns:
|
|
294
299
|
Dict[str, Any]: Parsed json data representing the API response.
|
|
295
300
|
"""
|
|
301
|
+
params = {}
|
|
302
|
+
if include_related:
|
|
303
|
+
params["include_related"] = ",".join(include_related)
|
|
304
|
+
|
|
296
305
|
return self._make_request(
|
|
297
306
|
method="get",
|
|
298
307
|
endpoint=f"runs/{run_id}",
|
|
299
308
|
base_url=self.api_v2_url,
|
|
300
|
-
|
|
309
|
+
params=params,
|
|
310
|
+
).json()["data"]
|
|
301
311
|
|
|
302
312
|
def poll_run(
|
|
303
313
|
self,
|
|
@@ -352,21 +362,25 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
352
362
|
endpoint=f"runs/{run_id}/artifacts",
|
|
353
363
|
base_url=self.api_v2_url,
|
|
354
364
|
session_attr="_get_artifact_session",
|
|
355
|
-
)["data"],
|
|
365
|
+
).json()["data"],
|
|
356
366
|
)
|
|
357
367
|
|
|
358
368
|
def get_run_artifact(self, run_id: int, path: str) -> Mapping[str, Any]:
|
|
359
369
|
"""Retrieves an artifact at the given path for a given dbt Cloud Run.
|
|
360
370
|
|
|
371
|
+
Args:
|
|
372
|
+
run_id (int): The dbt Cloud Run ID.
|
|
373
|
+
path (str): The path to the artifact (e.g., "run_results.json", "manifest.json").
|
|
374
|
+
|
|
361
375
|
Returns:
|
|
362
|
-
Dict[str, Any]: Parsed json data representing the
|
|
376
|
+
Dict[str, Any]: Parsed json data representing the artifact.
|
|
363
377
|
"""
|
|
364
378
|
return self._make_request(
|
|
365
379
|
method="get",
|
|
366
380
|
endpoint=f"runs/{run_id}/artifacts/{path}",
|
|
367
381
|
base_url=self.api_v2_url,
|
|
368
382
|
session_attr="_get_artifact_session",
|
|
369
|
-
)
|
|
383
|
+
).json()
|
|
370
384
|
|
|
371
385
|
def get_run_results_json(self, run_id: int) -> Mapping[str, Any]:
|
|
372
386
|
"""Retrieves the run_results.json artifact of a given dbt Cloud Run.
|
|
@@ -384,6 +398,65 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
384
398
|
"""
|
|
385
399
|
return self.get_run_artifact(run_id=run_id, path="manifest.json")
|
|
386
400
|
|
|
401
|
+
def get_run_logs(self, run_id: int, max_retries: int = 3, retry_delay: float = 2.0) -> str:
|
|
402
|
+
"""Retrieves the stdout/stderr logs from a given dbt Cloud Run.
|
|
403
|
+
|
|
404
|
+
This method fetches logs from the run_steps field by calling get_run_details
|
|
405
|
+
with include_related=["run_steps"]. Each step contains a logs field with
|
|
406
|
+
the stdout/stderr output for that step.
|
|
407
|
+
|
|
408
|
+
Note: There can be a slight delay between when a run completes and when the logs
|
|
409
|
+
are fully populated in the API. This method will retry a few times if it detects
|
|
410
|
+
completed steps with empty logs.
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
run_id (int): The dbt Cloud Run ID.
|
|
414
|
+
max_retries (int): Maximum number of times to retry fetching logs if empty. Defaults to 3.
|
|
415
|
+
retry_delay (float): Time in seconds to wait between retries. Defaults to 2.0.
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
str: The concatenated log text content from all run steps.
|
|
419
|
+
"""
|
|
420
|
+
for attempt in range(max_retries):
|
|
421
|
+
run_details = self.get_run_details(run_id=run_id, include_related=["run_steps"])
|
|
422
|
+
|
|
423
|
+
logs_parts = []
|
|
424
|
+
run_steps = run_details.get("run_steps", [])
|
|
425
|
+
completed_steps_with_empty_logs = 0
|
|
426
|
+
|
|
427
|
+
for step in run_steps:
|
|
428
|
+
step_name = step.get("name", "Unknown Step")
|
|
429
|
+
step_logs = step.get("logs", "")
|
|
430
|
+
step_status = step.get("status_humanized", "unknown")
|
|
431
|
+
|
|
432
|
+
# Track completed steps with empty logs
|
|
433
|
+
if step_status == "Success" and not step_logs:
|
|
434
|
+
completed_steps_with_empty_logs += 1
|
|
435
|
+
|
|
436
|
+
if step_logs:
|
|
437
|
+
logs_parts.append(f"=== Step: {step_name} ===")
|
|
438
|
+
logs_parts.append(step_logs)
|
|
439
|
+
logs_parts.append("") # Empty line between steps
|
|
440
|
+
|
|
441
|
+
# If we have completed steps with empty logs and retries left, wait and try again
|
|
442
|
+
if completed_steps_with_empty_logs > 0 and attempt < max_retries - 1:
|
|
443
|
+
self._log.warning(
|
|
444
|
+
f"Found {completed_steps_with_empty_logs} completed steps with empty logs for run {run_id}. "
|
|
445
|
+
f"Retrying in {retry_delay} seconds..."
|
|
446
|
+
)
|
|
447
|
+
time.sleep(retry_delay)
|
|
448
|
+
continue
|
|
449
|
+
|
|
450
|
+
# Either we got all logs or we're out of retries
|
|
451
|
+
if completed_steps_with_empty_logs > 0:
|
|
452
|
+
self._log.warning(
|
|
453
|
+
f"Still missing logs for {completed_steps_with_empty_logs} completed steps after {max_retries} attempts"
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
return "\n".join(logs_parts) if logs_parts else ""
|
|
457
|
+
|
|
458
|
+
return ""
|
|
459
|
+
|
|
387
460
|
def get_project_details(self, project_id: int) -> Mapping[str, Any]:
|
|
388
461
|
"""Retrieves the details of a given dbt Cloud Project.
|
|
389
462
|
|
|
@@ -398,7 +471,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
398
471
|
method="get",
|
|
399
472
|
endpoint=f"projects/{project_id}",
|
|
400
473
|
base_url=self.api_v2_url,
|
|
401
|
-
)["data"]
|
|
474
|
+
).json()["data"]
|
|
402
475
|
|
|
403
476
|
def get_environment_details(self, environment_id: int) -> Mapping[str, Any]:
|
|
404
477
|
"""Retrieves the details of a given dbt Cloud Environment.
|
|
@@ -414,7 +487,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
414
487
|
method="get",
|
|
415
488
|
endpoint=f"environments/{environment_id}",
|
|
416
489
|
base_url=self.api_v2_url,
|
|
417
|
-
)["data"]
|
|
490
|
+
).json()["data"]
|
|
418
491
|
|
|
419
492
|
def get_account_details(self) -> Mapping[str, Any]:
|
|
420
493
|
"""Retrieves the details of the account associated to the dbt Cloud workspace.
|
|
@@ -426,7 +499,7 @@ class DbtCloudWorkspaceClient(DagsterModel):
|
|
|
426
499
|
method="get",
|
|
427
500
|
endpoint=None,
|
|
428
501
|
base_url=self.api_v2_url,
|
|
429
|
-
)["data"]
|
|
502
|
+
).json()["data"]
|
|
430
503
|
|
|
431
504
|
def verify_connection(self) -> None:
|
|
432
505
|
"""Verifies the connection to the dbt Cloud REST API."""
|
|
@@ -13,6 +13,7 @@ from dagster import (
|
|
|
13
13
|
)
|
|
14
14
|
from dagster._record import record
|
|
15
15
|
from dateutil import parser
|
|
16
|
+
from requests.exceptions import RequestException
|
|
16
17
|
|
|
17
18
|
from dagster_dbt.asset_utils import build_dbt_specs, get_asset_check_key_for_test
|
|
18
19
|
from dagster_dbt.cloud_v2.client import DbtCloudWorkspaceClient
|
|
@@ -61,6 +62,22 @@ class DbtCloudJobRunHandler:
|
|
|
61
62
|
def list_run_artifacts(self) -> Sequence[str]:
|
|
62
63
|
return self.client.list_run_artifacts(run_id=self.run_id)
|
|
63
64
|
|
|
65
|
+
def get_run_logs(self) -> Optional[str]:
|
|
66
|
+
"""Retrieves the stdout/stderr logs from the completed dbt Cloud run.
|
|
67
|
+
|
|
68
|
+
This method fetches logs from the run_steps by calling get_run_details
|
|
69
|
+
with include_related=["run_steps"].
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Optional[str]: The concatenated log text content from all run steps,
|
|
73
|
+
or None if logs are not available.
|
|
74
|
+
"""
|
|
75
|
+
try:
|
|
76
|
+
return self.client.get_run_logs(run_id=self.run_id)
|
|
77
|
+
except RequestException as e:
|
|
78
|
+
logger.warning(f"Failed to retrieve logs for run {self.run_id}: {e}")
|
|
79
|
+
return None
|
|
80
|
+
|
|
64
81
|
|
|
65
82
|
def get_completed_at_timestamp(result: Mapping[str, Any]) -> float:
|
|
66
83
|
# result["timing"] is a list of events in run_results.json
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.28.6"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dagster-dbt
|
|
3
|
-
Version: 0.28.
|
|
3
|
+
Version: 0.28.6
|
|
4
4
|
Summary: A Dagster integration for dbt
|
|
5
5
|
Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-dbt
|
|
6
6
|
Author: Dagster Labs
|
|
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Requires-Python: >=3.10,<3.14
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: dagster==1.12.
|
|
17
|
+
Requires-Dist: dagster==1.12.6
|
|
18
18
|
Requires-Dist: dbt-core<1.11,>=1.7
|
|
19
19
|
Requires-Dist: gitpython
|
|
20
20
|
Requires-Dist: Jinja2
|
|
@@ -39,7 +39,7 @@ setup(
|
|
|
39
39
|
include_package_data=True,
|
|
40
40
|
python_requires=">=3.10,<3.14",
|
|
41
41
|
install_requires=[
|
|
42
|
-
"dagster==1.12.
|
|
42
|
+
"dagster==1.12.6",
|
|
43
43
|
# Follow the version support constraints for dbt Core: https://docs.getdbt.com/docs/dbt-versions/core
|
|
44
44
|
f"dbt-core>=1.7,<{DBT_CORE_VERSION_UPPER_BOUND}",
|
|
45
45
|
"gitpython",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.28.5"
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|