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.

Files changed (261) hide show
  1. dvt/__init__.py +7 -0
  2. dvt/_pydantic_shim.py +26 -0
  3. dvt/adapters/__init__.py +16 -0
  4. dvt/adapters/multi_adapter_manager.py +268 -0
  5. dvt/artifacts/__init__.py +0 -0
  6. dvt/artifacts/exceptions/__init__.py +1 -0
  7. dvt/artifacts/exceptions/schemas.py +31 -0
  8. dvt/artifacts/resources/__init__.py +116 -0
  9. dvt/artifacts/resources/base.py +68 -0
  10. dvt/artifacts/resources/types.py +93 -0
  11. dvt/artifacts/resources/v1/analysis.py +10 -0
  12. dvt/artifacts/resources/v1/catalog.py +23 -0
  13. dvt/artifacts/resources/v1/components.py +275 -0
  14. dvt/artifacts/resources/v1/config.py +282 -0
  15. dvt/artifacts/resources/v1/documentation.py +11 -0
  16. dvt/artifacts/resources/v1/exposure.py +52 -0
  17. dvt/artifacts/resources/v1/function.py +53 -0
  18. dvt/artifacts/resources/v1/generic_test.py +32 -0
  19. dvt/artifacts/resources/v1/group.py +22 -0
  20. dvt/artifacts/resources/v1/hook.py +11 -0
  21. dvt/artifacts/resources/v1/macro.py +30 -0
  22. dvt/artifacts/resources/v1/metric.py +173 -0
  23. dvt/artifacts/resources/v1/model.py +146 -0
  24. dvt/artifacts/resources/v1/owner.py +10 -0
  25. dvt/artifacts/resources/v1/saved_query.py +112 -0
  26. dvt/artifacts/resources/v1/seed.py +42 -0
  27. dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
  28. dvt/artifacts/resources/v1/semantic_model.py +315 -0
  29. dvt/artifacts/resources/v1/singular_test.py +14 -0
  30. dvt/artifacts/resources/v1/snapshot.py +92 -0
  31. dvt/artifacts/resources/v1/source_definition.py +85 -0
  32. dvt/artifacts/resources/v1/sql_operation.py +10 -0
  33. dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
  34. dvt/artifacts/schemas/__init__.py +0 -0
  35. dvt/artifacts/schemas/base.py +191 -0
  36. dvt/artifacts/schemas/batch_results.py +24 -0
  37. dvt/artifacts/schemas/catalog/__init__.py +12 -0
  38. dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  39. dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
  40. dvt/artifacts/schemas/freshness/__init__.py +1 -0
  41. dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  42. dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
  43. dvt/artifacts/schemas/manifest/__init__.py +2 -0
  44. dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  45. dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
  46. dvt/artifacts/schemas/results.py +148 -0
  47. dvt/artifacts/schemas/run/__init__.py +2 -0
  48. dvt/artifacts/schemas/run/v5/__init__.py +0 -0
  49. dvt/artifacts/schemas/run/v5/run.py +184 -0
  50. dvt/artifacts/schemas/upgrades/__init__.py +4 -0
  51. dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  52. dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
  53. dvt/artifacts/utils/validation.py +153 -0
  54. dvt/cli/__init__.py +1 -0
  55. dvt/cli/context.py +16 -0
  56. dvt/cli/exceptions.py +56 -0
  57. dvt/cli/flags.py +558 -0
  58. dvt/cli/main.py +971 -0
  59. dvt/cli/option_types.py +121 -0
  60. dvt/cli/options.py +79 -0
  61. dvt/cli/params.py +803 -0
  62. dvt/cli/requires.py +478 -0
  63. dvt/cli/resolvers.py +32 -0
  64. dvt/cli/types.py +40 -0
  65. dvt/clients/__init__.py +0 -0
  66. dvt/clients/checked_load.py +82 -0
  67. dvt/clients/git.py +164 -0
  68. dvt/clients/jinja.py +206 -0
  69. dvt/clients/jinja_static.py +245 -0
  70. dvt/clients/registry.py +192 -0
  71. dvt/clients/yaml_helper.py +68 -0
  72. dvt/compilation.py +833 -0
  73. dvt/compute/__init__.py +26 -0
  74. dvt/compute/base.py +288 -0
  75. dvt/compute/engines/__init__.py +13 -0
  76. dvt/compute/engines/duckdb_engine.py +368 -0
  77. dvt/compute/engines/spark_engine.py +273 -0
  78. dvt/compute/query_analyzer.py +212 -0
  79. dvt/compute/router.py +483 -0
  80. dvt/config/__init__.py +4 -0
  81. dvt/config/catalogs.py +95 -0
  82. dvt/config/compute_config.py +406 -0
  83. dvt/config/profile.py +411 -0
  84. dvt/config/profiles_v2.py +464 -0
  85. dvt/config/project.py +893 -0
  86. dvt/config/renderer.py +232 -0
  87. dvt/config/runtime.py +491 -0
  88. dvt/config/selectors.py +209 -0
  89. dvt/config/utils.py +78 -0
  90. dvt/connectors/.gitignore +6 -0
  91. dvt/connectors/README.md +306 -0
  92. dvt/connectors/catalog.yml +217 -0
  93. dvt/connectors/download_connectors.py +300 -0
  94. dvt/constants.py +29 -0
  95. dvt/context/__init__.py +0 -0
  96. dvt/context/base.py +746 -0
  97. dvt/context/configured.py +136 -0
  98. dvt/context/context_config.py +350 -0
  99. dvt/context/docs.py +82 -0
  100. dvt/context/exceptions_jinja.py +179 -0
  101. dvt/context/macro_resolver.py +195 -0
  102. dvt/context/macros.py +171 -0
  103. dvt/context/manifest.py +73 -0
  104. dvt/context/providers.py +2198 -0
  105. dvt/context/query_header.py +14 -0
  106. dvt/context/secret.py +59 -0
  107. dvt/context/target.py +74 -0
  108. dvt/contracts/__init__.py +0 -0
  109. dvt/contracts/files.py +413 -0
  110. dvt/contracts/graph/__init__.py +0 -0
  111. dvt/contracts/graph/manifest.py +1904 -0
  112. dvt/contracts/graph/metrics.py +98 -0
  113. dvt/contracts/graph/model_config.py +71 -0
  114. dvt/contracts/graph/node_args.py +42 -0
  115. dvt/contracts/graph/nodes.py +1806 -0
  116. dvt/contracts/graph/semantic_manifest.py +233 -0
  117. dvt/contracts/graph/unparsed.py +812 -0
  118. dvt/contracts/project.py +417 -0
  119. dvt/contracts/results.py +53 -0
  120. dvt/contracts/selection.py +23 -0
  121. dvt/contracts/sql.py +86 -0
  122. dvt/contracts/state.py +69 -0
  123. dvt/contracts/util.py +46 -0
  124. dvt/deprecations.py +347 -0
  125. dvt/deps/__init__.py +0 -0
  126. dvt/deps/base.py +153 -0
  127. dvt/deps/git.py +196 -0
  128. dvt/deps/local.py +80 -0
  129. dvt/deps/registry.py +131 -0
  130. dvt/deps/resolver.py +149 -0
  131. dvt/deps/tarball.py +121 -0
  132. dvt/docs/source/_ext/dbt_click.py +118 -0
  133. dvt/docs/source/conf.py +32 -0
  134. dvt/env_vars.py +64 -0
  135. dvt/event_time/event_time.py +40 -0
  136. dvt/event_time/sample_window.py +60 -0
  137. dvt/events/__init__.py +16 -0
  138. dvt/events/base_types.py +37 -0
  139. dvt/events/core_types_pb2.py +2 -0
  140. dvt/events/logging.py +109 -0
  141. dvt/events/types.py +2534 -0
  142. dvt/exceptions.py +1487 -0
  143. dvt/flags.py +89 -0
  144. dvt/graph/__init__.py +11 -0
  145. dvt/graph/cli.py +248 -0
  146. dvt/graph/graph.py +172 -0
  147. dvt/graph/queue.py +213 -0
  148. dvt/graph/selector.py +375 -0
  149. dvt/graph/selector_methods.py +976 -0
  150. dvt/graph/selector_spec.py +223 -0
  151. dvt/graph/thread_pool.py +18 -0
  152. dvt/hooks.py +21 -0
  153. dvt/include/README.md +49 -0
  154. dvt/include/__init__.py +3 -0
  155. dvt/include/global_project.py +4 -0
  156. dvt/include/starter_project/.gitignore +4 -0
  157. dvt/include/starter_project/README.md +15 -0
  158. dvt/include/starter_project/__init__.py +3 -0
  159. dvt/include/starter_project/analyses/.gitkeep +0 -0
  160. dvt/include/starter_project/dvt_project.yml +36 -0
  161. dvt/include/starter_project/macros/.gitkeep +0 -0
  162. dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  163. dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  164. dvt/include/starter_project/models/example/schema.yml +21 -0
  165. dvt/include/starter_project/seeds/.gitkeep +0 -0
  166. dvt/include/starter_project/snapshots/.gitkeep +0 -0
  167. dvt/include/starter_project/tests/.gitkeep +0 -0
  168. dvt/internal_deprecations.py +27 -0
  169. dvt/jsonschemas/__init__.py +3 -0
  170. dvt/jsonschemas/jsonschemas.py +309 -0
  171. dvt/jsonschemas/project/0.0.110.json +4717 -0
  172. dvt/jsonschemas/project/0.0.85.json +2015 -0
  173. dvt/jsonschemas/resources/0.0.110.json +2636 -0
  174. dvt/jsonschemas/resources/0.0.85.json +2536 -0
  175. dvt/jsonschemas/resources/latest.json +6773 -0
  176. dvt/links.py +4 -0
  177. dvt/materializations/__init__.py +0 -0
  178. dvt/materializations/incremental/__init__.py +0 -0
  179. dvt/materializations/incremental/microbatch.py +235 -0
  180. dvt/mp_context.py +8 -0
  181. dvt/node_types.py +37 -0
  182. dvt/parser/__init__.py +23 -0
  183. dvt/parser/analysis.py +21 -0
  184. dvt/parser/base.py +549 -0
  185. dvt/parser/common.py +267 -0
  186. dvt/parser/docs.py +52 -0
  187. dvt/parser/fixtures.py +51 -0
  188. dvt/parser/functions.py +30 -0
  189. dvt/parser/generic_test.py +100 -0
  190. dvt/parser/generic_test_builders.py +334 -0
  191. dvt/parser/hooks.py +119 -0
  192. dvt/parser/macros.py +137 -0
  193. dvt/parser/manifest.py +2204 -0
  194. dvt/parser/models.py +574 -0
  195. dvt/parser/partial.py +1179 -0
  196. dvt/parser/read_files.py +445 -0
  197. dvt/parser/schema_generic_tests.py +423 -0
  198. dvt/parser/schema_renderer.py +111 -0
  199. dvt/parser/schema_yaml_readers.py +936 -0
  200. dvt/parser/schemas.py +1467 -0
  201. dvt/parser/search.py +149 -0
  202. dvt/parser/seeds.py +28 -0
  203. dvt/parser/singular_test.py +20 -0
  204. dvt/parser/snapshots.py +44 -0
  205. dvt/parser/sources.py +557 -0
  206. dvt/parser/sql.py +63 -0
  207. dvt/parser/unit_tests.py +622 -0
  208. dvt/plugins/__init__.py +20 -0
  209. dvt/plugins/contracts.py +10 -0
  210. dvt/plugins/exceptions.py +2 -0
  211. dvt/plugins/manager.py +164 -0
  212. dvt/plugins/manifest.py +21 -0
  213. dvt/profiler.py +20 -0
  214. dvt/py.typed +1 -0
  215. dvt/runners/__init__.py +2 -0
  216. dvt/runners/exposure_runner.py +7 -0
  217. dvt/runners/no_op_runner.py +46 -0
  218. dvt/runners/saved_query_runner.py +7 -0
  219. dvt/selected_resources.py +8 -0
  220. dvt/task/__init__.py +0 -0
  221. dvt/task/base.py +504 -0
  222. dvt/task/build.py +197 -0
  223. dvt/task/clean.py +57 -0
  224. dvt/task/clone.py +162 -0
  225. dvt/task/compile.py +151 -0
  226. dvt/task/compute.py +366 -0
  227. dvt/task/debug.py +650 -0
  228. dvt/task/deps.py +280 -0
  229. dvt/task/docs/__init__.py +3 -0
  230. dvt/task/docs/generate.py +408 -0
  231. dvt/task/docs/index.html +250 -0
  232. dvt/task/docs/serve.py +28 -0
  233. dvt/task/freshness.py +323 -0
  234. dvt/task/function.py +122 -0
  235. dvt/task/group_lookup.py +46 -0
  236. dvt/task/init.py +374 -0
  237. dvt/task/list.py +237 -0
  238. dvt/task/printer.py +176 -0
  239. dvt/task/profiles.py +256 -0
  240. dvt/task/retry.py +175 -0
  241. dvt/task/run.py +1146 -0
  242. dvt/task/run_operation.py +142 -0
  243. dvt/task/runnable.py +802 -0
  244. dvt/task/seed.py +104 -0
  245. dvt/task/show.py +150 -0
  246. dvt/task/snapshot.py +57 -0
  247. dvt/task/sql.py +111 -0
  248. dvt/task/test.py +464 -0
  249. dvt/tests/fixtures/__init__.py +1 -0
  250. dvt/tests/fixtures/project.py +620 -0
  251. dvt/tests/util.py +651 -0
  252. dvt/tracking.py +529 -0
  253. dvt/utils/__init__.py +3 -0
  254. dvt/utils/artifact_upload.py +151 -0
  255. dvt/utils/utils.py +408 -0
  256. dvt/version.py +249 -0
  257. dvt_core-1.11.0b4.dist-info/METADATA +252 -0
  258. dvt_core-1.11.0b4.dist-info/RECORD +261 -0
  259. dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
  260. dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
  261. 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
@@ -0,0 +1,8 @@
1
+ from multiprocessing import get_context
2
+ from multiprocessing.context import SpawnContext
3
+
4
+ _MP_CONTEXT = get_context("spawn")
5
+
6
+
7
+ def get_mp_context() -> SpawnContext:
8
+ return _MP_CONTEXT
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)