dbt-common 1.13.0__py3-none-any.whl → 1.15.0__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.
- dbt_common/__about__.py +1 -1
- dbt_common/clients/jinja.py +73 -0
- dbt_common/context.py +1 -0
- dbt_common/invocation.py +8 -1
- dbt_common/record.py +259 -55
- {dbt_common-1.13.0.dist-info → dbt_common-1.15.0.dist-info}/METADATA +5 -6
- {dbt_common-1.13.0.dist-info → dbt_common-1.15.0.dist-info}/RECORD +9 -9
- {dbt_common-1.13.0.dist-info → dbt_common-1.15.0.dist-info}/WHEEL +1 -1
- {dbt_common-1.13.0.dist-info → dbt_common-1.15.0.dist-info}/licenses/LICENSE +0 -0
dbt_common/__about__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
version = "1.
|
1
|
+
version = "1.15.0"
|
dbt_common/clients/jinja.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import codecs
|
2
|
+
import dataclasses
|
2
3
|
import linecache
|
3
4
|
import os
|
4
5
|
import tempfile
|
@@ -46,6 +47,7 @@ from dbt_common.exceptions import (
|
|
46
47
|
MaterializationArgError,
|
47
48
|
JinjaRenderingError,
|
48
49
|
UndefinedCompilationError,
|
50
|
+
DbtRuntimeError,
|
49
51
|
)
|
50
52
|
from dbt_common.exceptions.macros import MacroReturn, UndefinedMacroError, CaughtMacroError
|
51
53
|
|
@@ -89,6 +91,12 @@ def _linecache_inject(source: str, write: bool) -> str:
|
|
89
91
|
return filename
|
90
92
|
|
91
93
|
|
94
|
+
@dataclasses.dataclass
|
95
|
+
class MacroType:
|
96
|
+
name: str
|
97
|
+
type_params: List["MacroType"] = dataclasses.field(default_factory=list)
|
98
|
+
|
99
|
+
|
92
100
|
class MacroFuzzParser(jinja2.parser.Parser):
|
93
101
|
def parse_macro(self) -> jinja2.nodes.Macro:
|
94
102
|
node = jinja2.nodes.Macro(lineno=next(self.stream).lineno)
|
@@ -102,6 +110,65 @@ class MacroFuzzParser(jinja2.parser.Parser):
|
|
102
110
|
node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
|
103
111
|
return node
|
104
112
|
|
113
|
+
def parse_signature(self, node: Union[jinja2.nodes.Macro, jinja2.nodes.CallBlock]) -> None:
|
114
|
+
"""Overrides the default jinja Parser.parse_signature method, modifying
|
115
|
+
the original implementation to allow macros to have typed parameters."""
|
116
|
+
|
117
|
+
# Jinja does not support extending its node types, such as Macro, so
|
118
|
+
# at least while typed macros are experimental, we will patch the
|
119
|
+
# information onto the existing types.
|
120
|
+
setattr(node, "arg_types", [])
|
121
|
+
setattr(node, "has_type_annotations", False)
|
122
|
+
|
123
|
+
args = node.args = [] # type: ignore
|
124
|
+
defaults = node.defaults = [] # type: ignore
|
125
|
+
|
126
|
+
self.stream.expect("lparen")
|
127
|
+
while self.stream.current.type != "rparen":
|
128
|
+
if args:
|
129
|
+
self.stream.expect("comma")
|
130
|
+
|
131
|
+
arg = self.parse_assign_target(name_only=True)
|
132
|
+
arg.set_ctx("param")
|
133
|
+
|
134
|
+
type_name: Optional[str]
|
135
|
+
if self.stream.skip_if("colon"):
|
136
|
+
node.has_type_annotations = True # type: ignore
|
137
|
+
type_name = self.parse_type_name()
|
138
|
+
else:
|
139
|
+
type_name = ""
|
140
|
+
|
141
|
+
node.arg_types.append(type_name) # type: ignore
|
142
|
+
|
143
|
+
if self.stream.skip_if("assign"):
|
144
|
+
defaults.append(self.parse_expression())
|
145
|
+
elif defaults:
|
146
|
+
self.fail("non-default argument follows default argument")
|
147
|
+
|
148
|
+
args.append(arg)
|
149
|
+
self.stream.expect("rparen")
|
150
|
+
|
151
|
+
def parse_type_name(self) -> MacroType:
|
152
|
+
# NOTE: Types syntax is validated here, but not whether type names
|
153
|
+
# are valid or have correct parameters.
|
154
|
+
|
155
|
+
# A type name should consist of a name (i.e. 'Dict')...
|
156
|
+
type_name = self.stream.expect("name").value
|
157
|
+
type = MacroType(type_name)
|
158
|
+
|
159
|
+
# ..and an optional comma-delimited list of type parameters
|
160
|
+
# as in the type declaration 'Dict[str, str]'
|
161
|
+
if self.stream.skip_if("lbracket"):
|
162
|
+
while self.stream.current.type != "rbracket":
|
163
|
+
if type.type_params:
|
164
|
+
self.stream.expect("comma")
|
165
|
+
param_type = self.parse_type_name()
|
166
|
+
type.type_params.append(param_type)
|
167
|
+
|
168
|
+
self.stream.expect("rbracket")
|
169
|
+
|
170
|
+
return type
|
171
|
+
|
105
172
|
|
106
173
|
class MacroFuzzEnvironment(jinja2.sandbox.SandboxedEnvironment):
|
107
174
|
def _parse(
|
@@ -534,6 +601,12 @@ def catch_jinja(node: Optional[_NodeProtocol] = None) -> Iterator[None]:
|
|
534
601
|
except CompilationError as exc:
|
535
602
|
exc.add_node(node)
|
536
603
|
raise
|
604
|
+
except DbtRuntimeError:
|
605
|
+
# Propagate dbt exception raised during jinja compilation
|
606
|
+
raise
|
607
|
+
except Exception as e:
|
608
|
+
# Raise any non-dbt exceptions as CompilationError
|
609
|
+
raise CompilationError(str(e), node) from e
|
537
610
|
|
538
611
|
|
539
612
|
_TESTING_PARSE_CACHE: Dict[str, jinja2.nodes.Template] = {}
|
dbt_common/context.py
CHANGED
dbt_common/invocation.py
CHANGED
@@ -1,12 +1,19 @@
|
|
1
1
|
import uuid
|
2
|
+
from datetime import datetime
|
2
3
|
|
3
4
|
_INVOCATION_ID = str(uuid.uuid4())
|
5
|
+
_INVOCATION_STARTED_AT = datetime.utcnow()
|
4
6
|
|
5
7
|
|
6
8
|
def get_invocation_id() -> str:
|
7
9
|
return _INVOCATION_ID
|
8
10
|
|
9
11
|
|
12
|
+
def get_invocation_started_at() -> datetime:
|
13
|
+
return _INVOCATION_STARTED_AT
|
14
|
+
|
15
|
+
|
10
16
|
def reset_invocation_id() -> None:
|
11
|
-
global _INVOCATION_ID
|
17
|
+
global _INVOCATION_ID, _INVOCATION_STARTED_AT
|
12
18
|
_INVOCATION_ID = str(uuid.uuid4())
|
19
|
+
_INVOCATION_STARTED_AT = datetime.utcnow()
|
dbt_common/record.py
CHANGED
@@ -1,17 +1,25 @@
|
|
1
|
-
"""The record module provides a mechanism for recording dbt's
|
2
|
-
external systems during a command invocation, so that the
|
3
|
-
later with the recording 'replayed' to dbt.
|
1
|
+
"""The record module provides a record/replay mechanism for recording dbt's
|
2
|
+
interactions with external systems during a command invocation, so that the
|
3
|
+
command can be re-run later with the recording 'replayed' to dbt.
|
4
4
|
|
5
5
|
The rationale for and architecture of this module are described in detail in the
|
6
6
|
docs/guides/record_replay.md document in this repository.
|
7
7
|
"""
|
8
8
|
import functools
|
9
9
|
import dataclasses
|
10
|
+
import inspect
|
10
11
|
import json
|
11
12
|
import os
|
12
13
|
|
13
14
|
from enum import Enum
|
14
|
-
from typing import Any, Callable, Dict, List, Mapping, Optional, Type
|
15
|
+
from typing import Any, Callable, Dict, List, Mapping, Optional, TextIO, Tuple, Type
|
16
|
+
import contextvars
|
17
|
+
|
18
|
+
from mashumaro import field_options
|
19
|
+
from mashumaro.mixins.json import DataClassJSONMixin
|
20
|
+
from mashumaro.types import SerializationStrategy
|
21
|
+
|
22
|
+
RECORDED_BY_HIGHER_FUNCTION = contextvars.ContextVar("RECORDED_BY_HIGHER_FUNCTION", default=False)
|
15
23
|
|
16
24
|
|
17
25
|
class Record:
|
@@ -129,6 +137,7 @@ class RecorderMode(Enum):
|
|
129
137
|
class Recorder:
|
130
138
|
_record_cls_by_name: Dict[str, Type] = {}
|
131
139
|
_record_name_by_params_name: Dict[str, str] = {}
|
140
|
+
_auto_serialization_strategies: Dict[Type, SerializationStrategy] = {}
|
132
141
|
|
133
142
|
def __init__(
|
134
143
|
self,
|
@@ -189,9 +198,13 @@ class Recorder:
|
|
189
198
|
|
190
199
|
return match
|
191
200
|
|
201
|
+
def write_json(self, out_stream: TextIO):
|
202
|
+
d = self._to_dict()
|
203
|
+
json.dump(d, out_stream)
|
204
|
+
|
192
205
|
def write(self) -> None:
|
193
206
|
with open(self.current_recording_path, "w") as file:
|
194
|
-
|
207
|
+
self.write_json(file)
|
195
208
|
|
196
209
|
def _to_dict(self) -> Dict:
|
197
210
|
dct: Dict[str, Any] = {}
|
@@ -205,7 +218,11 @@ class Recorder:
|
|
205
218
|
@classmethod
|
206
219
|
def load(cls, file_name: str) -> Dict[str, List[Dict[str, Any]]]:
|
207
220
|
with open(file_name) as file:
|
208
|
-
return
|
221
|
+
return cls.load_json(file)
|
222
|
+
|
223
|
+
@classmethod
|
224
|
+
def load_json(cls, in_stream: TextIO) -> Dict[str, List[Dict[str, Any]]]:
|
225
|
+
return json.load(in_stream)
|
209
226
|
|
210
227
|
def _ensure_records_processed(self, record_type_name: str) -> None:
|
211
228
|
if record_type_name in self._records_by_type:
|
@@ -239,6 +256,12 @@ class Recorder:
|
|
239
256
|
assert self.diff is not None
|
240
257
|
print(repr(self.diff.calculate_diff()))
|
241
258
|
|
259
|
+
@classmethod
|
260
|
+
def register_serialization_strategy(
|
261
|
+
cls, t: Type, serialization_strategy: SerializationStrategy
|
262
|
+
) -> None:
|
263
|
+
cls._auto_serialization_strategies[t] = serialization_strategy
|
264
|
+
|
242
265
|
|
243
266
|
def get_record_mode_from_env() -> Optional[RecorderMode]:
|
244
267
|
"""
|
@@ -271,7 +294,7 @@ def get_record_types_from_env() -> Optional[List]:
|
|
271
294
|
|
272
295
|
If no types are provided, there will be no filtering.
|
273
296
|
Invalid types will be ignored.
|
274
|
-
Expected format: 'DBT_RECORDER_TYPES=
|
297
|
+
Expected format: 'DBT_RECORDER_TYPES=Database,FileLoadRecord'
|
275
298
|
"""
|
276
299
|
record_types_str = os.environ.get("DBT_RECORDER_TYPES")
|
277
300
|
|
@@ -283,74 +306,255 @@ def get_record_types_from_env() -> Optional[List]:
|
|
283
306
|
|
284
307
|
|
285
308
|
def get_record_types_from_dict(fp: str) -> List:
|
286
|
-
"""
|
287
|
-
Get the record subset from the dict.
|
288
|
-
"""
|
309
|
+
"""Get the record subset from the dict."""
|
289
310
|
with open(fp) as file:
|
290
311
|
loaded_dct = json.load(file)
|
291
312
|
return list(loaded_dct.keys())
|
292
313
|
|
293
314
|
|
315
|
+
def auto_record_function(
|
316
|
+
record_name: str,
|
317
|
+
method: bool = True,
|
318
|
+
group: Optional[str] = None,
|
319
|
+
index_on_thread_name: bool = True,
|
320
|
+
) -> Callable:
|
321
|
+
"""This is the @auto_record_function decorator. It works in a similar way to
|
322
|
+
the @record_function decorator, except automatically generates boilerplate
|
323
|
+
classes for the Record, Params, and Result classes which would otherwise be
|
324
|
+
needed. That makes it suitable for quickly adding record support to simple
|
325
|
+
functions with simple parameters."""
|
326
|
+
return functools.partial(
|
327
|
+
_record_function_inner,
|
328
|
+
record_name,
|
329
|
+
method,
|
330
|
+
False,
|
331
|
+
None,
|
332
|
+
group,
|
333
|
+
index_on_thread_name,
|
334
|
+
False,
|
335
|
+
)
|
336
|
+
|
337
|
+
|
294
338
|
def record_function(
|
295
339
|
record_type,
|
296
340
|
method: bool = False,
|
297
341
|
tuple_result: bool = False,
|
298
342
|
id_field_name: Optional[str] = None,
|
299
343
|
) -> Callable:
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
344
|
+
"""This is the @record_function decorator, which marks functions which will
|
345
|
+
have their function calls recorded during record mode, and mocked out with
|
346
|
+
previously recorded replay data during replay."""
|
347
|
+
return functools.partial(
|
348
|
+
_record_function_inner,
|
349
|
+
record_type,
|
350
|
+
method,
|
351
|
+
tuple_result,
|
352
|
+
id_field_name,
|
353
|
+
None,
|
354
|
+
False,
|
355
|
+
False,
|
356
|
+
)
|
357
|
+
|
358
|
+
|
359
|
+
def _get_arg_fields(
|
360
|
+
spec: inspect.FullArgSpec,
|
361
|
+
skip_first: bool = False,
|
362
|
+
) -> List[Tuple[str, Optional[Type], dataclasses.Field]]:
|
363
|
+
arg_fields = []
|
364
|
+
defaults = len(spec.defaults) if spec.defaults else 0
|
365
|
+
for i, arg_name in enumerate(spec.args):
|
366
|
+
if skip_first and i == 0:
|
367
|
+
continue
|
368
|
+
annotation = spec.annotations.get(arg_name)
|
369
|
+
if annotation is None:
|
370
|
+
raise Exception("Recorded functions must have type annotations.")
|
371
|
+
field = _get_field(arg_name, annotation)
|
372
|
+
if i >= len(spec.args) - defaults:
|
373
|
+
field[2].default = (
|
374
|
+
spec.defaults[i - len(spec.args) + defaults] if spec.defaults else None
|
375
|
+
)
|
376
|
+
arg_fields.append(field)
|
377
|
+
return arg_fields
|
378
|
+
|
379
|
+
|
380
|
+
def _get_field(field_name: str, t: Type) -> Tuple[str, Optional[Type], dataclasses.Field]:
|
381
|
+
dc_field: dataclasses.Field = dataclasses.field()
|
382
|
+
strat = Recorder._auto_serialization_strategies.get(t)
|
383
|
+
if strat is not None:
|
384
|
+
dc_field.metadata = field_options(serialization_strategy=Recorder._auto_serialization_strategies[t]) # type: ignore
|
385
|
+
|
386
|
+
return field_name, t, dc_field
|
387
|
+
|
388
|
+
|
389
|
+
@dataclasses.dataclass
|
390
|
+
class AutoValues(DataClassJSONMixin):
|
391
|
+
def _to_dict(self):
|
392
|
+
return self.to_dict()
|
393
|
+
|
394
|
+
def _from_dict(self, data):
|
395
|
+
return self.from_dict(data)
|
396
|
+
|
397
|
+
|
398
|
+
def _record_function_inner(
|
399
|
+
record_type,
|
400
|
+
method,
|
401
|
+
tuple_result,
|
402
|
+
id_field_name,
|
403
|
+
group,
|
404
|
+
index_on_thread_id,
|
405
|
+
is_classmethod,
|
406
|
+
func_to_record,
|
407
|
+
):
|
408
|
+
if isinstance(record_type, str):
|
409
|
+
return_type = inspect.signature(func_to_record).return_annotation
|
410
|
+
fields = _get_arg_fields(inspect.getfullargspec(func_to_record), method)
|
411
|
+
if index_on_thread_id:
|
412
|
+
id_field_name = "thread_id"
|
413
|
+
fields.insert(0, _get_field("thread_id", str))
|
414
|
+
params_cls = dataclasses.make_dataclass(
|
415
|
+
f"{record_type}Params", fields, bases=(AutoValues,)
|
416
|
+
)
|
417
|
+
result_cls = (
|
418
|
+
None
|
419
|
+
if return_type is None or return_type == inspect._empty
|
420
|
+
else dataclasses.make_dataclass(
|
421
|
+
f"{record_type}Result",
|
422
|
+
[_get_field("return_val", return_type)],
|
423
|
+
bases=(AutoValues,),
|
424
|
+
)
|
425
|
+
)
|
426
|
+
|
427
|
+
record_type = type(
|
428
|
+
f"{record_type}Record",
|
429
|
+
(Record,),
|
430
|
+
{"params_cls": params_cls, "result_cls": result_cls, "group": group},
|
431
|
+
)
|
432
|
+
|
433
|
+
Recorder.register_record_type(record_type)
|
311
434
|
|
312
|
-
|
313
|
-
|
314
|
-
|
435
|
+
@functools.wraps(func_to_record)
|
436
|
+
def record_replay_wrapper(*args, **kwargs) -> Any:
|
437
|
+
recorder: Optional[Recorder] = None
|
438
|
+
try:
|
439
|
+
from dbt_common.context import get_invocation_context
|
315
440
|
|
316
|
-
|
317
|
-
|
441
|
+
recorder = get_invocation_context().recorder
|
442
|
+
except LookupError:
|
443
|
+
pass
|
318
444
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
)
|
323
|
-
|
445
|
+
call_args = args[1:] if is_classmethod else args
|
446
|
+
|
447
|
+
if recorder is None:
|
448
|
+
return func_to_record(*call_args, **kwargs)
|
449
|
+
|
450
|
+
if recorder.recorded_types is not None and not (
|
451
|
+
record_type.__name__ in recorder.recorded_types
|
452
|
+
or record_type.group in recorder.recorded_types
|
453
|
+
):
|
454
|
+
return func_to_record(*call_args, **kwargs)
|
324
455
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
456
|
+
# For methods, peel off the 'self' argument before calling the
|
457
|
+
# params constructor.
|
458
|
+
param_args = args[1:] if method else args
|
459
|
+
if method and id_field_name is not None:
|
460
|
+
if index_on_thread_id:
|
461
|
+
from dbt_common.context import get_invocation_context
|
462
|
+
|
463
|
+
param_args = (get_invocation_context().name,) + param_args
|
464
|
+
else:
|
329
465
|
param_args = (getattr(args[0], id_field_name),) + param_args
|
330
466
|
|
331
|
-
|
467
|
+
params = record_type.params_cls(*param_args, **kwargs)
|
332
468
|
|
333
|
-
|
334
|
-
|
335
|
-
|
469
|
+
include = True
|
470
|
+
if hasattr(params, "_include"):
|
471
|
+
include = params._include()
|
336
472
|
|
337
|
-
|
338
|
-
|
473
|
+
if not include:
|
474
|
+
return func_to_record(*call_args, **kwargs)
|
339
475
|
|
340
|
-
|
341
|
-
|
476
|
+
if recorder.mode == RecorderMode.REPLAY:
|
477
|
+
return recorder.expect_record(params)
|
478
|
+
if RECORDED_BY_HIGHER_FUNCTION.get():
|
479
|
+
return func_to_record(*call_args, **kwargs)
|
342
480
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
)
|
351
|
-
|
352
|
-
|
481
|
+
RECORDED_BY_HIGHER_FUNCTION.set(True)
|
482
|
+
r = func_to_record(*call_args, **kwargs)
|
483
|
+
result = (
|
484
|
+
None
|
485
|
+
if record_type.result_cls is None
|
486
|
+
else record_type.result_cls(*r)
|
487
|
+
if tuple_result
|
488
|
+
else record_type.result_cls(r)
|
489
|
+
)
|
490
|
+
RECORDED_BY_HIGHER_FUNCTION.set(False)
|
491
|
+
recorder.add_record(record_type(params=params, result=result))
|
492
|
+
return r
|
493
|
+
|
494
|
+
setattr(
|
495
|
+
record_replay_wrapper,
|
496
|
+
"_record_metadata",
|
497
|
+
{
|
498
|
+
"record_type": record_type,
|
499
|
+
"method": method,
|
500
|
+
"tuple_result": tuple_result,
|
501
|
+
"id_field_name": id_field_name,
|
502
|
+
"group": group,
|
503
|
+
"index_on_thread_id": index_on_thread_id,
|
504
|
+
},
|
505
|
+
)
|
506
|
+
|
507
|
+
return record_replay_wrapper
|
508
|
+
|
509
|
+
|
510
|
+
def _is_classmethod(method):
|
511
|
+
b = inspect.ismethod(method) and isinstance(method.__self__, type)
|
512
|
+
return b
|
513
|
+
|
514
|
+
|
515
|
+
def supports_replay(cls):
|
516
|
+
"""Class decorator which adds record/replay support for a class. In particular,
|
517
|
+
this decorator ensures that calls to overriden functions are still recorded."""
|
518
|
+
|
519
|
+
# When record/replay is inactive, do nothing.
|
520
|
+
if get_record_mode_from_env() is None:
|
521
|
+
return cls
|
522
|
+
|
523
|
+
# Replace the __init_subclass__ method of this class so that when it
|
524
|
+
# is subclassed, methods on the new subclass which override recorded
|
525
|
+
# functions are modified to be recorded as well.
|
526
|
+
original_init_subclass = cls.__init_subclass__
|
527
|
+
|
528
|
+
@classmethod
|
529
|
+
def wrapping_init_subclass(sub_cls):
|
530
|
+
for method_name in dir(cls):
|
531
|
+
method = getattr(cls, method_name)
|
532
|
+
metadata = getattr(method, "_record_metadata", None)
|
533
|
+
if method and getattr(method, "_record_metadata", None):
|
534
|
+
sub_method = getattr(sub_cls, method_name, None)
|
535
|
+
recorded_sub_method = _record_function_inner(
|
536
|
+
metadata["record_type"],
|
537
|
+
metadata["method"],
|
538
|
+
metadata["tuple_result"],
|
539
|
+
metadata["id_field_name"],
|
540
|
+
metadata["group"],
|
541
|
+
metadata["index_on_thread_id"],
|
542
|
+
_is_classmethod(method),
|
543
|
+
sub_method,
|
544
|
+
)
|
545
|
+
|
546
|
+
if _is_classmethod(method):
|
547
|
+
recorded_sub_method = classmethod(recorded_sub_method)
|
548
|
+
|
549
|
+
if sub_method is not None:
|
550
|
+
setattr(
|
551
|
+
sub_cls,
|
552
|
+
method_name,
|
553
|
+
recorded_sub_method,
|
554
|
+
)
|
555
|
+
|
556
|
+
original_init_subclass()
|
353
557
|
|
354
|
-
|
558
|
+
cls.__init_subclass__ = wrapping_init_subclass
|
355
559
|
|
356
|
-
return
|
560
|
+
return cls
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: dbt-common
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.15.0
|
4
4
|
Summary: The shared common utilities that dbt-core and adapter implementations use
|
5
5
|
Project-URL: Homepage, https://github.com/dbt-labs/dbt-common
|
6
6
|
Project-URL: Repository, https://github.com/dbt-labs/dbt-common.git
|
@@ -8,7 +8,8 @@ Project-URL: Issues, https://github.com/dbt-labs/dbt-common/issues
|
|
8
8
|
Project-URL: Changelog, https://github.com/dbt-labs/dbt-common/blob/main/CHANGELOG.md
|
9
9
|
Author-email: dbt Labs <info@dbtlabs.com>
|
10
10
|
Maintainer-email: dbt Labs <info@dbtlabs.com>
|
11
|
-
License: Apache-2.0
|
11
|
+
License-Expression: Apache-2.0
|
12
|
+
License-File: LICENSE
|
12
13
|
Classifier: Development Status :: 2 - Pre-Alpha
|
13
14
|
Classifier: License :: OSI Approved :: Apache Software License
|
14
15
|
Classifier: Operating System :: MacOS :: MacOS X
|
@@ -65,9 +66,7 @@ The shared common utilities for dbt-core and adapter implementations use
|
|
65
66
|
|
66
67
|
### Releasing dbt-common
|
67
68
|
To release a new version of dbt-common to pypi, you'll need to:
|
68
|
-
1.
|
69
|
-
2. Run the [release workflow](https://github.com/dbt-labs/dbt-common/actions/workflows/release.yml) to test pypi and confirm a successful test release in: https://test.pypi.org/project/dbt-common/
|
70
|
-
3. Run the [release workflow](https://github.com/dbt-labs/dbt-common/actions/workflows/release.yml) to prod pypi and confirm a successful release in: https://pypi.org/project/dbt-common/
|
69
|
+
1. Run the [release workflow](https://github.com/dbt-labs/dbt-common/actions/workflows/release.yml) to bump the version, generate changelogs and release to pypi
|
71
70
|
4. Bump the version of `dbt-common` in `dbt-core` and `dbt-adapters` if you're releasing a new major version or a pre-release:
|
72
71
|
* `dbt-core`: [setup.py](https://github.com/dbt-labs/dbt-core/blob/main/core/setup.py)
|
73
72
|
* `dbt-adapters`: [pyproject.toml](https://github.com/dbt-labs/dbt-adapters/blob/main/pyproject.toml)
|
@@ -1,20 +1,20 @@
|
|
1
|
-
dbt_common/__about__.py,sha256=
|
1
|
+
dbt_common/__about__.py,sha256=ifS0ZWsb82NyM4xyQWKPKGKE5bG3EXlYHT1H7h1HxOY,19
|
2
2
|
dbt_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
dbt_common/behavior_flags.py,sha256=hQzxCqQSweJbRp_xoQqNnlUF77PBuOdCdLOSdcBlkxk,4885
|
4
4
|
dbt_common/constants.py,sha256=-Y5DIL1SDPQWtlCNizXRYxFgbx1D7LaLs1ysamvGMRk,278
|
5
|
-
dbt_common/context.py,sha256=
|
5
|
+
dbt_common/context.py,sha256=tVeXtsptvuw7d8CvdlYSBFcKLyLZ852iQNwcxNmUzYY,2577
|
6
6
|
dbt_common/dataclass_schema.py,sha256=u2S0dxwxIghv8RMqC91HlWZJVxmsC_844yZQaGyOwdY,5563
|
7
7
|
dbt_common/helper_types.py,sha256=FWJGPmp7Qp2iToHyI4uvhkBbu_d1tl2_oF-obi98_N4,3917
|
8
|
-
dbt_common/invocation.py,sha256=
|
8
|
+
dbt_common/invocation.py,sha256=xw0NBIE-6LHd135cx4non-MkGGsia0mYN0lMkmNEucE,435
|
9
9
|
dbt_common/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
dbt_common/record.py,sha256=
|
10
|
+
dbt_common/record.py,sha256=ExF8ccUpDv2kButAMnTR8zSyD9agU7nhXTKFDx7Iw7Y,19352
|
11
11
|
dbt_common/semver.py,sha256=Znewz6tc_NBpXr4mZf20bK_RayPL4ODrnxDbkUZrrRo,15034
|
12
12
|
dbt_common/tests.py,sha256=6lC_JuRtoYO6cbAF8-R5aTM4HtQiM_EH8X5m_97duGY,315
|
13
13
|
dbt_common/ui.py,sha256=rc2TEM29raBFc_LXcg901pMDD07C2ohwp9qzkE-7pBY,2567
|
14
14
|
dbt_common/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
15
|
dbt_common/clients/_jinja_blocks.py,sha256=5I_VEWkkW_54uK09ErP_8ey7wj-OOXvt1OHqr73HLOk,14879
|
16
16
|
dbt_common/clients/agate_helper.py,sha256=anKKgKV5PSnFRuFeBwRMdHK3JCaQoUqB2ZXHD0su0Wo,9123
|
17
|
-
dbt_common/clients/jinja.py,sha256=
|
17
|
+
dbt_common/clients/jinja.py,sha256=VpCYe_0seh6K4667-4TmQ2PP-T48UIcvDRT3miRyn4o,22488
|
18
18
|
dbt_common/clients/system.py,sha256=aoUBtOuXVmkOyj6IhhJ3Y4a7JFzPO2F_zKyOtz3xy44,23932
|
19
19
|
dbt_common/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
dbt_common/contracts/constraints.py,sha256=_f1q3Rkcg2UwA7zI5XBbUMXnPUg6pw17UC7l1HyhyQM,1352
|
@@ -57,7 +57,7 @@ dbt_common/utils/encoding.py,sha256=6_kSY2FvGNYMg7oX7PrbvVioieydih3Kl7Ii802LaHI,
|
|
57
57
|
dbt_common/utils/executor.py,sha256=pNY0UbPlwQmTE69Vt_Rj91YGCIOEaqeYU3CjAds0T70,2454
|
58
58
|
dbt_common/utils/formatting.py,sha256=JUn5rzJ-uajs9wPCN0-f2iRFY1pOJF5YjTD9dERuLoc,165
|
59
59
|
dbt_common/utils/jinja.py,sha256=JXgNmJArGGy0h7qkbNLA3zaEQmoF1CxsNBYTlIwFXDw,1101
|
60
|
-
dbt_common-1.
|
61
|
-
dbt_common-1.
|
62
|
-
dbt_common-1.
|
63
|
-
dbt_common-1.
|
60
|
+
dbt_common-1.15.0.dist-info/METADATA,sha256=gcyH_sfjldI5SpDsEGDig-tUAVMVANrqNEmN0jun2c0,4895
|
61
|
+
dbt_common-1.15.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
62
|
+
dbt_common-1.15.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
63
|
+
dbt_common-1.15.0.dist-info/RECORD,,
|
File without changes
|