dvt-core 1.11.0b4__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.
Potentially problematic release.
This version of dvt-core might be problematic. Click here for more details.
- dvt/__init__.py +7 -0
- dvt/_pydantic_shim.py +26 -0
- dvt/adapters/__init__.py +16 -0
- dvt/adapters/multi_adapter_manager.py +268 -0
- dvt/artifacts/__init__.py +0 -0
- dvt/artifacts/exceptions/__init__.py +1 -0
- dvt/artifacts/exceptions/schemas.py +31 -0
- dvt/artifacts/resources/__init__.py +116 -0
- dvt/artifacts/resources/base.py +68 -0
- dvt/artifacts/resources/types.py +93 -0
- dvt/artifacts/resources/v1/analysis.py +10 -0
- dvt/artifacts/resources/v1/catalog.py +23 -0
- dvt/artifacts/resources/v1/components.py +275 -0
- dvt/artifacts/resources/v1/config.py +282 -0
- dvt/artifacts/resources/v1/documentation.py +11 -0
- dvt/artifacts/resources/v1/exposure.py +52 -0
- dvt/artifacts/resources/v1/function.py +53 -0
- dvt/artifacts/resources/v1/generic_test.py +32 -0
- dvt/artifacts/resources/v1/group.py +22 -0
- dvt/artifacts/resources/v1/hook.py +11 -0
- dvt/artifacts/resources/v1/macro.py +30 -0
- dvt/artifacts/resources/v1/metric.py +173 -0
- dvt/artifacts/resources/v1/model.py +146 -0
- dvt/artifacts/resources/v1/owner.py +10 -0
- dvt/artifacts/resources/v1/saved_query.py +112 -0
- dvt/artifacts/resources/v1/seed.py +42 -0
- dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
- dvt/artifacts/resources/v1/semantic_model.py +315 -0
- dvt/artifacts/resources/v1/singular_test.py +14 -0
- dvt/artifacts/resources/v1/snapshot.py +92 -0
- dvt/artifacts/resources/v1/source_definition.py +85 -0
- dvt/artifacts/resources/v1/sql_operation.py +10 -0
- dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
- dvt/artifacts/schemas/__init__.py +0 -0
- dvt/artifacts/schemas/base.py +191 -0
- dvt/artifacts/schemas/batch_results.py +24 -0
- dvt/artifacts/schemas/catalog/__init__.py +12 -0
- dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
- dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
- dvt/artifacts/schemas/freshness/__init__.py +1 -0
- dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
- dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
- dvt/artifacts/schemas/manifest/__init__.py +2 -0
- dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
- dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
- dvt/artifacts/schemas/results.py +148 -0
- dvt/artifacts/schemas/run/__init__.py +2 -0
- dvt/artifacts/schemas/run/v5/__init__.py +0 -0
- dvt/artifacts/schemas/run/v5/run.py +184 -0
- dvt/artifacts/schemas/upgrades/__init__.py +4 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
- dvt/artifacts/utils/validation.py +153 -0
- dvt/cli/__init__.py +1 -0
- dvt/cli/context.py +16 -0
- dvt/cli/exceptions.py +56 -0
- dvt/cli/flags.py +558 -0
- dvt/cli/main.py +971 -0
- dvt/cli/option_types.py +121 -0
- dvt/cli/options.py +79 -0
- dvt/cli/params.py +803 -0
- dvt/cli/requires.py +478 -0
- dvt/cli/resolvers.py +32 -0
- dvt/cli/types.py +40 -0
- dvt/clients/__init__.py +0 -0
- dvt/clients/checked_load.py +82 -0
- dvt/clients/git.py +164 -0
- dvt/clients/jinja.py +206 -0
- dvt/clients/jinja_static.py +245 -0
- dvt/clients/registry.py +192 -0
- dvt/clients/yaml_helper.py +68 -0
- dvt/compilation.py +833 -0
- dvt/compute/__init__.py +26 -0
- dvt/compute/base.py +288 -0
- dvt/compute/engines/__init__.py +13 -0
- dvt/compute/engines/duckdb_engine.py +368 -0
- dvt/compute/engines/spark_engine.py +273 -0
- dvt/compute/query_analyzer.py +212 -0
- dvt/compute/router.py +483 -0
- dvt/config/__init__.py +4 -0
- dvt/config/catalogs.py +95 -0
- dvt/config/compute_config.py +406 -0
- dvt/config/profile.py +411 -0
- dvt/config/profiles_v2.py +464 -0
- dvt/config/project.py +893 -0
- dvt/config/renderer.py +232 -0
- dvt/config/runtime.py +491 -0
- dvt/config/selectors.py +209 -0
- dvt/config/utils.py +78 -0
- dvt/connectors/.gitignore +6 -0
- dvt/connectors/README.md +306 -0
- dvt/connectors/catalog.yml +217 -0
- dvt/connectors/download_connectors.py +300 -0
- dvt/constants.py +29 -0
- dvt/context/__init__.py +0 -0
- dvt/context/base.py +746 -0
- dvt/context/configured.py +136 -0
- dvt/context/context_config.py +350 -0
- dvt/context/docs.py +82 -0
- dvt/context/exceptions_jinja.py +179 -0
- dvt/context/macro_resolver.py +195 -0
- dvt/context/macros.py +171 -0
- dvt/context/manifest.py +73 -0
- dvt/context/providers.py +2198 -0
- dvt/context/query_header.py +14 -0
- dvt/context/secret.py +59 -0
- dvt/context/target.py +74 -0
- dvt/contracts/__init__.py +0 -0
- dvt/contracts/files.py +413 -0
- dvt/contracts/graph/__init__.py +0 -0
- dvt/contracts/graph/manifest.py +1904 -0
- dvt/contracts/graph/metrics.py +98 -0
- dvt/contracts/graph/model_config.py +71 -0
- dvt/contracts/graph/node_args.py +42 -0
- dvt/contracts/graph/nodes.py +1806 -0
- dvt/contracts/graph/semantic_manifest.py +233 -0
- dvt/contracts/graph/unparsed.py +812 -0
- dvt/contracts/project.py +417 -0
- dvt/contracts/results.py +53 -0
- dvt/contracts/selection.py +23 -0
- dvt/contracts/sql.py +86 -0
- dvt/contracts/state.py +69 -0
- dvt/contracts/util.py +46 -0
- dvt/deprecations.py +347 -0
- dvt/deps/__init__.py +0 -0
- dvt/deps/base.py +153 -0
- dvt/deps/git.py +196 -0
- dvt/deps/local.py +80 -0
- dvt/deps/registry.py +131 -0
- dvt/deps/resolver.py +149 -0
- dvt/deps/tarball.py +121 -0
- dvt/docs/source/_ext/dbt_click.py +118 -0
- dvt/docs/source/conf.py +32 -0
- dvt/env_vars.py +64 -0
- dvt/event_time/event_time.py +40 -0
- dvt/event_time/sample_window.py +60 -0
- dvt/events/__init__.py +16 -0
- dvt/events/base_types.py +37 -0
- dvt/events/core_types_pb2.py +2 -0
- dvt/events/logging.py +109 -0
- dvt/events/types.py +2534 -0
- dvt/exceptions.py +1487 -0
- dvt/flags.py +89 -0
- dvt/graph/__init__.py +11 -0
- dvt/graph/cli.py +248 -0
- dvt/graph/graph.py +172 -0
- dvt/graph/queue.py +213 -0
- dvt/graph/selector.py +375 -0
- dvt/graph/selector_methods.py +976 -0
- dvt/graph/selector_spec.py +223 -0
- dvt/graph/thread_pool.py +18 -0
- dvt/hooks.py +21 -0
- dvt/include/README.md +49 -0
- dvt/include/__init__.py +3 -0
- dvt/include/global_project.py +4 -0
- dvt/include/starter_project/.gitignore +4 -0
- dvt/include/starter_project/README.md +15 -0
- dvt/include/starter_project/__init__.py +3 -0
- dvt/include/starter_project/analyses/.gitkeep +0 -0
- dvt/include/starter_project/dvt_project.yml +36 -0
- dvt/include/starter_project/macros/.gitkeep +0 -0
- dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
- dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
- dvt/include/starter_project/models/example/schema.yml +21 -0
- dvt/include/starter_project/seeds/.gitkeep +0 -0
- dvt/include/starter_project/snapshots/.gitkeep +0 -0
- dvt/include/starter_project/tests/.gitkeep +0 -0
- dvt/internal_deprecations.py +27 -0
- dvt/jsonschemas/__init__.py +3 -0
- dvt/jsonschemas/jsonschemas.py +309 -0
- dvt/jsonschemas/project/0.0.110.json +4717 -0
- dvt/jsonschemas/project/0.0.85.json +2015 -0
- dvt/jsonschemas/resources/0.0.110.json +2636 -0
- dvt/jsonschemas/resources/0.0.85.json +2536 -0
- dvt/jsonschemas/resources/latest.json +6773 -0
- dvt/links.py +4 -0
- dvt/materializations/__init__.py +0 -0
- dvt/materializations/incremental/__init__.py +0 -0
- dvt/materializations/incremental/microbatch.py +235 -0
- dvt/mp_context.py +8 -0
- dvt/node_types.py +37 -0
- dvt/parser/__init__.py +23 -0
- dvt/parser/analysis.py +21 -0
- dvt/parser/base.py +549 -0
- dvt/parser/common.py +267 -0
- dvt/parser/docs.py +52 -0
- dvt/parser/fixtures.py +51 -0
- dvt/parser/functions.py +30 -0
- dvt/parser/generic_test.py +100 -0
- dvt/parser/generic_test_builders.py +334 -0
- dvt/parser/hooks.py +119 -0
- dvt/parser/macros.py +137 -0
- dvt/parser/manifest.py +2204 -0
- dvt/parser/models.py +574 -0
- dvt/parser/partial.py +1179 -0
- dvt/parser/read_files.py +445 -0
- dvt/parser/schema_generic_tests.py +423 -0
- dvt/parser/schema_renderer.py +111 -0
- dvt/parser/schema_yaml_readers.py +936 -0
- dvt/parser/schemas.py +1467 -0
- dvt/parser/search.py +149 -0
- dvt/parser/seeds.py +28 -0
- dvt/parser/singular_test.py +20 -0
- dvt/parser/snapshots.py +44 -0
- dvt/parser/sources.py +557 -0
- dvt/parser/sql.py +63 -0
- dvt/parser/unit_tests.py +622 -0
- dvt/plugins/__init__.py +20 -0
- dvt/plugins/contracts.py +10 -0
- dvt/plugins/exceptions.py +2 -0
- dvt/plugins/manager.py +164 -0
- dvt/plugins/manifest.py +21 -0
- dvt/profiler.py +20 -0
- dvt/py.typed +1 -0
- dvt/runners/__init__.py +2 -0
- dvt/runners/exposure_runner.py +7 -0
- dvt/runners/no_op_runner.py +46 -0
- dvt/runners/saved_query_runner.py +7 -0
- dvt/selected_resources.py +8 -0
- dvt/task/__init__.py +0 -0
- dvt/task/base.py +504 -0
- dvt/task/build.py +197 -0
- dvt/task/clean.py +57 -0
- dvt/task/clone.py +162 -0
- dvt/task/compile.py +151 -0
- dvt/task/compute.py +366 -0
- dvt/task/debug.py +650 -0
- dvt/task/deps.py +280 -0
- dvt/task/docs/__init__.py +3 -0
- dvt/task/docs/generate.py +408 -0
- dvt/task/docs/index.html +250 -0
- dvt/task/docs/serve.py +28 -0
- dvt/task/freshness.py +323 -0
- dvt/task/function.py +122 -0
- dvt/task/group_lookup.py +46 -0
- dvt/task/init.py +374 -0
- dvt/task/list.py +237 -0
- dvt/task/printer.py +176 -0
- dvt/task/profiles.py +256 -0
- dvt/task/retry.py +175 -0
- dvt/task/run.py +1146 -0
- dvt/task/run_operation.py +142 -0
- dvt/task/runnable.py +802 -0
- dvt/task/seed.py +104 -0
- dvt/task/show.py +150 -0
- dvt/task/snapshot.py +57 -0
- dvt/task/sql.py +111 -0
- dvt/task/test.py +464 -0
- dvt/tests/fixtures/__init__.py +1 -0
- dvt/tests/fixtures/project.py +620 -0
- dvt/tests/util.py +651 -0
- dvt/tracking.py +529 -0
- dvt/utils/__init__.py +3 -0
- dvt/utils/artifact_upload.py +151 -0
- dvt/utils/utils.py +408 -0
- dvt/version.py +249 -0
- dvt_core-1.11.0b4.dist-info/METADATA +252 -0
- dvt_core-1.11.0b4.dist-info/RECORD +261 -0
- dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
- dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
- dvt_core-1.11.0b4.dist-info/top_level.txt +1 -0
dvt/links.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
ProfileConfigDocs = "https://docs.getdbt.com/docs/configure-your-profile"
|
|
2
|
+
SnowflakeQuotingDocs = "https://docs.getdbt.com/v0.10/docs/configuring-quoting"
|
|
3
|
+
IncrementalDocs = "https://docs.getdbt.com/docs/configuring-incremental-models"
|
|
4
|
+
BigQueryNewPartitionBy = "https://docs.getdbt.com/docs/upgrading-to-0-16-0"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
from typing import Any, Dict, List, Optional
|
|
3
|
+
|
|
4
|
+
import pytz
|
|
5
|
+
from dvt.artifacts.resources.types import BatchSize
|
|
6
|
+
from dvt.artifacts.schemas.batch_results import BatchType
|
|
7
|
+
from dvt.contracts.graph.nodes import ModelNode, NodeConfig
|
|
8
|
+
from dvt.exceptions import DbtInternalError, DbtRuntimeError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MicrobatchBuilder:
|
|
12
|
+
"""A utility class for building microbatch definitions associated with a specific model"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
model: ModelNode,
|
|
17
|
+
is_incremental: bool,
|
|
18
|
+
event_time_start: Optional[datetime],
|
|
19
|
+
event_time_end: Optional[datetime],
|
|
20
|
+
default_end_time: Optional[datetime] = None,
|
|
21
|
+
):
|
|
22
|
+
if model.config.incremental_strategy != "microbatch":
|
|
23
|
+
raise DbtInternalError(
|
|
24
|
+
f"Model '{model.name}' does not use 'microbatch' incremental_strategy."
|
|
25
|
+
)
|
|
26
|
+
self.model = model
|
|
27
|
+
|
|
28
|
+
if self.model.config.batch_size is None:
|
|
29
|
+
raise DbtRuntimeError(
|
|
30
|
+
f"Microbatch model '{self.model.name}' does not have a 'batch_size' config (one of {[batch_size.value for batch_size in BatchSize]}) specificed."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
self.is_incremental = is_incremental
|
|
34
|
+
self.event_time_start = (
|
|
35
|
+
event_time_start.replace(tzinfo=pytz.UTC) if event_time_start else None
|
|
36
|
+
)
|
|
37
|
+
self.event_time_end = event_time_end.replace(tzinfo=pytz.UTC) if event_time_end else None
|
|
38
|
+
self.default_end_time = default_end_time or datetime.now(pytz.UTC)
|
|
39
|
+
|
|
40
|
+
def build_end_time(self):
|
|
41
|
+
"""Defaults the end_time to the current time in UTC unless a non `None` event_time_end was provided"""
|
|
42
|
+
end_time = self.event_time_end or self.default_end_time
|
|
43
|
+
return MicrobatchBuilder.ceiling_timestamp(end_time, self.model.config.batch_size)
|
|
44
|
+
|
|
45
|
+
def build_start_time(self, checkpoint: Optional[datetime]):
|
|
46
|
+
"""Create a start time based off the passed in checkpoint.
|
|
47
|
+
|
|
48
|
+
If the checkpoint is `None`, or this is the first run of a microbatch model, then the
|
|
49
|
+
model's configured `begin` value will be returned as a checkpoint is necessary
|
|
50
|
+
to build a start time. This is because we build the start time relative to the checkpoint
|
|
51
|
+
via the batchsize and offset, and we cannot offset a checkpoint if there is no checkpoint.
|
|
52
|
+
"""
|
|
53
|
+
assert isinstance(self.model.config, NodeConfig)
|
|
54
|
+
batch_size = self.model.config.batch_size
|
|
55
|
+
|
|
56
|
+
# Use event_time_start if it is provided.
|
|
57
|
+
if self.event_time_start:
|
|
58
|
+
return MicrobatchBuilder.truncate_timestamp(self.event_time_start, batch_size)
|
|
59
|
+
|
|
60
|
+
# First run, use model's configured 'begin' as start.
|
|
61
|
+
if not self.is_incremental or checkpoint is None:
|
|
62
|
+
if not self.model.config.begin:
|
|
63
|
+
raise DbtRuntimeError(
|
|
64
|
+
f"Microbatch model '{self.model.name}' requires a 'begin' configuration."
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return MicrobatchBuilder.truncate_timestamp(self.model.config.begin, batch_size)
|
|
68
|
+
|
|
69
|
+
lookback = self.model.config.lookback
|
|
70
|
+
|
|
71
|
+
# If the checkpoint is equivalent to itself truncated then the checkpoint stradles
|
|
72
|
+
# the batch line. In this case the last batch will end with the checkpoint, but start
|
|
73
|
+
# should be the previous hour/day/month/year. Thus we need to increase the lookback by
|
|
74
|
+
# 1 to get this affect properly.
|
|
75
|
+
if checkpoint == MicrobatchBuilder.truncate_timestamp(checkpoint, batch_size):
|
|
76
|
+
lookback += 1
|
|
77
|
+
|
|
78
|
+
return MicrobatchBuilder.offset_timestamp(checkpoint, batch_size, -1 * lookback)
|
|
79
|
+
|
|
80
|
+
def build_batches(self, start: datetime, end: datetime) -> List[BatchType]:
|
|
81
|
+
"""
|
|
82
|
+
Given a start and end datetime, builds a list of batches where each batch is
|
|
83
|
+
the size of the model's batch_size.
|
|
84
|
+
"""
|
|
85
|
+
batch_size = self.model.config.batch_size
|
|
86
|
+
curr_batch_start: datetime = start
|
|
87
|
+
curr_batch_end: datetime = MicrobatchBuilder.offset_timestamp(
|
|
88
|
+
curr_batch_start, batch_size, 1
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
batches: List[BatchType] = [(curr_batch_start, curr_batch_end)]
|
|
92
|
+
while curr_batch_end < end:
|
|
93
|
+
curr_batch_start = curr_batch_end
|
|
94
|
+
curr_batch_end = MicrobatchBuilder.offset_timestamp(curr_batch_start, batch_size, 1)
|
|
95
|
+
batches.append((curr_batch_start, curr_batch_end))
|
|
96
|
+
|
|
97
|
+
# use exact end value as stop
|
|
98
|
+
batches[-1] = (batches[-1][0], end)
|
|
99
|
+
|
|
100
|
+
return batches
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def build_jinja_context_for_batch(model: ModelNode, incremental_batch: bool) -> Dict[str, Any]:
|
|
104
|
+
"""
|
|
105
|
+
Create context with entries that reflect microbatch model + incremental execution state
|
|
106
|
+
|
|
107
|
+
Assumes self.model has been (re)-compiled with necessary batch filters applied.
|
|
108
|
+
"""
|
|
109
|
+
jinja_context: Dict[str, Any] = {}
|
|
110
|
+
|
|
111
|
+
# Microbatch model properties
|
|
112
|
+
jinja_context["model"] = model.to_dict()
|
|
113
|
+
jinja_context["sql"] = model.compiled_code
|
|
114
|
+
jinja_context["compiled_code"] = model.compiled_code
|
|
115
|
+
|
|
116
|
+
# Add incremental context variables for batches running incrementally
|
|
117
|
+
if incremental_batch:
|
|
118
|
+
jinja_context["is_incremental"] = lambda: True
|
|
119
|
+
jinja_context["should_full_refresh"] = lambda: False
|
|
120
|
+
|
|
121
|
+
return jinja_context
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def offset_timestamp(timestamp: datetime, batch_size: BatchSize, offset: int) -> datetime:
|
|
125
|
+
"""Truncates the passed in timestamp based on the batch_size and then applies the offset by the batch_size.
|
|
126
|
+
|
|
127
|
+
Note: It's important to understand that the offset applies to the truncated timestamp, not
|
|
128
|
+
the origin timestamp. Thus being offset by a day isn't relative to the any given hour that day,
|
|
129
|
+
but relative to the start of the day. So if the timestamp is the very end of a day, 2024-09-17 23:59:59,
|
|
130
|
+
you have a batch size of a day, and an offset of +1, then the returned value ends up being only one
|
|
131
|
+
second later, 2024-09-18 00:00:00.
|
|
132
|
+
|
|
133
|
+
2024-09-17 16:06:00 + Batchsize.hour -1 -> 2024-09-17 15:00:00
|
|
134
|
+
2024-09-17 16:06:00 + Batchsize.hour +1 -> 2024-09-17 17:00:00
|
|
135
|
+
2024-09-17 16:06:00 + Batchsize.day -1 -> 2024-09-16 00:00:00
|
|
136
|
+
2024-09-17 16:06:00 + Batchsize.day +1 -> 2024-09-18 00:00:00
|
|
137
|
+
2024-09-17 16:06:00 + Batchsize.month -1 -> 2024-08-01 00:00:00
|
|
138
|
+
2024-09-17 16:06:00 + Batchsize.month +1 -> 2024-10-01 00:00:00
|
|
139
|
+
2024-09-17 16:06:00 + Batchsize.year -1 -> 2023-01-01 00:00:00
|
|
140
|
+
2024-09-17 16:06:00 + Batchsize.year +1 -> 2025-01-01 00:00:00
|
|
141
|
+
"""
|
|
142
|
+
truncated = MicrobatchBuilder.truncate_timestamp(timestamp, batch_size)
|
|
143
|
+
|
|
144
|
+
offset_timestamp: datetime
|
|
145
|
+
if batch_size == BatchSize.hour:
|
|
146
|
+
offset_timestamp = truncated + timedelta(hours=offset)
|
|
147
|
+
elif batch_size == BatchSize.day:
|
|
148
|
+
offset_timestamp = truncated + timedelta(days=offset)
|
|
149
|
+
elif batch_size == BatchSize.month:
|
|
150
|
+
offset_timestamp = truncated
|
|
151
|
+
for _ in range(abs(offset)):
|
|
152
|
+
if offset < 0:
|
|
153
|
+
offset_timestamp = offset_timestamp - timedelta(days=1)
|
|
154
|
+
else:
|
|
155
|
+
offset_timestamp = offset_timestamp + timedelta(days=31)
|
|
156
|
+
offset_timestamp = MicrobatchBuilder.truncate_timestamp(
|
|
157
|
+
offset_timestamp, batch_size
|
|
158
|
+
)
|
|
159
|
+
elif batch_size == BatchSize.year:
|
|
160
|
+
offset_timestamp = truncated.replace(year=truncated.year + offset)
|
|
161
|
+
|
|
162
|
+
return offset_timestamp
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def truncate_timestamp(timestamp: datetime, batch_size: BatchSize) -> datetime:
|
|
166
|
+
"""Truncates the passed in timestamp based on the batch_size.
|
|
167
|
+
|
|
168
|
+
2024-09-17 16:06:00 + Batchsize.hour -> 2024-09-17 16:00:00
|
|
169
|
+
2024-09-17 16:06:00 + Batchsize.day -> 2024-09-17 00:00:00
|
|
170
|
+
2024-09-17 16:06:00 + Batchsize.month -> 2024-09-01 00:00:00
|
|
171
|
+
2024-09-17 16:06:00 + Batchsize.year -> 2024-01-01 00:00:00
|
|
172
|
+
"""
|
|
173
|
+
if batch_size == BatchSize.hour:
|
|
174
|
+
truncated = datetime(
|
|
175
|
+
timestamp.year,
|
|
176
|
+
timestamp.month,
|
|
177
|
+
timestamp.day,
|
|
178
|
+
timestamp.hour,
|
|
179
|
+
0,
|
|
180
|
+
0,
|
|
181
|
+
0,
|
|
182
|
+
pytz.utc,
|
|
183
|
+
)
|
|
184
|
+
elif batch_size == BatchSize.day:
|
|
185
|
+
truncated = datetime(
|
|
186
|
+
timestamp.year, timestamp.month, timestamp.day, 0, 0, 0, 0, pytz.utc
|
|
187
|
+
)
|
|
188
|
+
elif batch_size == BatchSize.month:
|
|
189
|
+
truncated = datetime(timestamp.year, timestamp.month, 1, 0, 0, 0, 0, pytz.utc)
|
|
190
|
+
elif batch_size == BatchSize.year:
|
|
191
|
+
truncated = datetime(timestamp.year, 1, 1, 0, 0, 0, 0, pytz.utc)
|
|
192
|
+
|
|
193
|
+
return truncated
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def batch_id(start_time: datetime, batch_size: BatchSize) -> str:
|
|
197
|
+
return MicrobatchBuilder.format_batch_start(start_time, batch_size).replace("-", "")
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
def format_batch_start(batch_start: datetime, batch_size: BatchSize) -> str:
|
|
201
|
+
"""Format the passed in datetime based on the batch_size.
|
|
202
|
+
|
|
203
|
+
2024-09-17 16:06:00 + Batchsize.hour -> 2024-09-17T16
|
|
204
|
+
2024-09-17 16:06:00 + Batchsize.day -> 2024-09-17
|
|
205
|
+
2024-09-17 16:06:00 + Batchsize.month -> 2024-09
|
|
206
|
+
2024-09-17 16:06:00 + Batchsize.year -> 2024
|
|
207
|
+
"""
|
|
208
|
+
if batch_size == BatchSize.year:
|
|
209
|
+
return batch_start.strftime("%Y")
|
|
210
|
+
elif batch_size == BatchSize.month:
|
|
211
|
+
return batch_start.strftime("%Y-%m")
|
|
212
|
+
elif batch_size == BatchSize.day:
|
|
213
|
+
return batch_start.strftime("%Y-%m-%d")
|
|
214
|
+
else: # batch_size == BatchSize.hour
|
|
215
|
+
return batch_start.strftime("%Y-%m-%dT%H")
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
def ceiling_timestamp(timestamp: datetime, batch_size: BatchSize) -> datetime:
|
|
219
|
+
"""Takes the given timestamp and moves it to the ceiling for the given batch size
|
|
220
|
+
|
|
221
|
+
Note, if the timestamp is already the batch size ceiling, that is returned
|
|
222
|
+
2024-09-17 16:06:00 + BatchSize.hour -> 2024-09-17 17:00:00
|
|
223
|
+
2024-09-17 16:00:00 + BatchSize.hour -> 2024-09-17 16:00:00
|
|
224
|
+
2024-09-17 16:06:00 + BatchSize.day -> 2024-09-18 00:00:00
|
|
225
|
+
2024-09-17 00:00:00 + BatchSize.day -> 2024-09-17 00:00:00
|
|
226
|
+
2024-09-17 16:06:00 + BatchSize.month -> 2024-10-01 00:00:00
|
|
227
|
+
2024-09-01 00:00:00 + BatchSize.month -> 2024-09-01 00:00:00
|
|
228
|
+
2024-09-17 16:06:00 + BatchSize.year -> 2025-01-01 00:00:00
|
|
229
|
+
2024-01-01 00:00:00 + BatchSize.year -> 2024-01-01 00:00:00
|
|
230
|
+
|
|
231
|
+
"""
|
|
232
|
+
ceiling = truncated = MicrobatchBuilder.truncate_timestamp(timestamp, batch_size)
|
|
233
|
+
if truncated != timestamp:
|
|
234
|
+
ceiling = MicrobatchBuilder.offset_timestamp(truncated, batch_size, 1)
|
|
235
|
+
return ceiling
|
dvt/mp_context.py
ADDED
dvt/node_types.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
# preserving import path during dbt/artifacts refactor
|
|
4
|
+
from dvt.artifacts.resources.types import ( # noqa
|
|
5
|
+
AccessType,
|
|
6
|
+
ModelLanguage,
|
|
7
|
+
NodeType,
|
|
8
|
+
RunHookType,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
EXECUTABLE_NODE_TYPES: List["NodeType"] = [
|
|
12
|
+
NodeType.Model,
|
|
13
|
+
NodeType.Test,
|
|
14
|
+
NodeType.Snapshot,
|
|
15
|
+
NodeType.Analysis,
|
|
16
|
+
NodeType.Operation,
|
|
17
|
+
NodeType.Seed,
|
|
18
|
+
NodeType.Documentation,
|
|
19
|
+
NodeType.RPCCall,
|
|
20
|
+
NodeType.SqlOperation,
|
|
21
|
+
NodeType.Function,
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
REFABLE_NODE_TYPES: List["NodeType"] = [
|
|
25
|
+
NodeType.Model,
|
|
26
|
+
NodeType.Seed,
|
|
27
|
+
NodeType.Snapshot,
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
TEST_NODE_TYPES: List["NodeType"] = [
|
|
31
|
+
NodeType.Test,
|
|
32
|
+
NodeType.Unit,
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
VERSIONED_NODE_TYPES: List["NodeType"] = [
|
|
36
|
+
NodeType.Model,
|
|
37
|
+
]
|
dvt/parser/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from . import ( # noqa
|
|
2
|
+
analysis,
|
|
3
|
+
base,
|
|
4
|
+
docs,
|
|
5
|
+
generic_test,
|
|
6
|
+
hooks,
|
|
7
|
+
macros,
|
|
8
|
+
models,
|
|
9
|
+
schemas,
|
|
10
|
+
singular_test,
|
|
11
|
+
snapshots,
|
|
12
|
+
)
|
|
13
|
+
from .analysis import AnalysisParser # noqa
|
|
14
|
+
from .base import ConfiguredParser, Parser # noqa
|
|
15
|
+
from .docs import DocumentationParser # noqa
|
|
16
|
+
from .generic_test import GenericTestParser # noqa
|
|
17
|
+
from .hooks import HookParser # noqa
|
|
18
|
+
from .macros import MacroParser # noqa
|
|
19
|
+
from .models import ModelParser # noqa
|
|
20
|
+
from .schemas import SchemaParser # noqa
|
|
21
|
+
from .seeds import SeedParser # noqa
|
|
22
|
+
from .singular_test import SingularTestParser # noqa
|
|
23
|
+
from .snapshots import SnapshotParser # noqa
|
dvt/parser/analysis.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from dvt.contracts.graph.nodes import AnalysisNode
|
|
4
|
+
from dvt.node_types import NodeType
|
|
5
|
+
from dvt.parser.base import SimpleSQLParser
|
|
6
|
+
from dvt.parser.search import FileBlock
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AnalysisParser(SimpleSQLParser[AnalysisNode]):
|
|
10
|
+
def parse_from_dict(self, dct, validate=True) -> AnalysisNode:
|
|
11
|
+
if validate:
|
|
12
|
+
AnalysisNode.validate(dct)
|
|
13
|
+
return AnalysisNode.from_dict(dct)
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def resource_type(self) -> NodeType:
|
|
17
|
+
return NodeType.Analysis
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def get_compiled_path(cls, block: FileBlock):
|
|
21
|
+
return os.path.join("analysis", block.path.relative_path)
|