dbt-common 1.15.0__py3-none-any.whl → 1.17.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 CHANGED
@@ -1 +1 @@
1
- version = "1.15.0"
1
+ version = "1.17.0"
dbt_common/context.py CHANGED
@@ -43,6 +43,12 @@ class InvocationContext:
43
43
  self._env_secrets: Optional[List[str]] = None
44
44
  self._env_private = env_private
45
45
  self.recorder: Optional[Recorder] = None
46
+
47
+ # If set to True later, this flag will prevent dbt from creating a new
48
+ # invocation context for every invocation, which is useful for testing
49
+ # scenarios.
50
+ self.do_not_reset = False
51
+
46
52
  # This class will also eventually manage the invocation_id, flags, event manager, etc.
47
53
 
48
54
  @property
@@ -85,3 +91,10 @@ def get_invocation_context() -> InvocationContext:
85
91
  invocation_var = reliably_get_invocation_var()
86
92
  ctx = invocation_var.get()
87
93
  return ctx
94
+
95
+
96
+ def try_get_invocation_context() -> Optional[InvocationContext]:
97
+ try:
98
+ return get_invocation_context()
99
+ except Exception:
100
+ return None
@@ -1,19 +1,66 @@
1
1
  import os
2
2
  import traceback
3
- from typing import List, Optional, Protocol, Tuple
3
+ from typing import Any, List, Optional, Protocol, Tuple
4
4
 
5
5
  from dbt_common.events.base_types import BaseEvent, EventLevel, msg_from_base_event, TCallback
6
6
  from dbt_common.events.logger import LoggerConfig, _Logger, _TextLogger, _JsonLogger, LineFormat
7
+ from dbt_common.exceptions.events import EventCompilationError
8
+ from dbt_common.helper_types import WarnErrorOptions
7
9
 
8
10
 
9
11
  class EventManager:
10
12
  def __init__(self) -> None:
11
13
  self.loggers: List[_Logger] = []
12
14
  self.callbacks: List[TCallback] = []
13
-
14
- def fire_event(self, e: BaseEvent, level: Optional[EventLevel] = None) -> None:
15
+ self._warn_error: Optional[bool] = None
16
+ self._warn_error_options: Optional[WarnErrorOptions] = None
17
+ self.require_warn_or_error_handling: bool = False
18
+
19
+ @property
20
+ def warn_error(self) -> bool:
21
+ if self._warn_error is None:
22
+ from dbt_common.events.functions import WARN_ERROR
23
+
24
+ return WARN_ERROR
25
+ return self._warn_error
26
+
27
+ @warn_error.setter
28
+ def warn_error(self, warn_error: bool) -> None:
29
+ self._warn_error = warn_error
30
+
31
+ @property
32
+ def warn_error_options(self) -> WarnErrorOptions:
33
+ if self._warn_error_options is None:
34
+ from dbt_common.events.functions import WARN_ERROR_OPTIONS
35
+
36
+ return WARN_ERROR_OPTIONS
37
+ return self._warn_error_options
38
+
39
+ @warn_error_options.setter
40
+ def warn_error_options(self, warn_error_options: WarnErrorOptions) -> None:
41
+ self._warn_error_options = warn_error_options
42
+
43
+ def fire_event(
44
+ self,
45
+ e: BaseEvent,
46
+ level: Optional[EventLevel] = None,
47
+ node: Any = None,
48
+ force_warn_or_error_handling: bool = False,
49
+ ) -> None:
15
50
  msg = msg_from_base_event(e, level=level)
16
51
 
52
+ if force_warn_or_error_handling or (
53
+ self.require_warn_or_error_handling and msg.info.level == "warn"
54
+ ):
55
+ event_name = type(e).__name__
56
+ if self.warn_error or self.warn_error_options.includes(event_name):
57
+ # This has the potential to create an infinite loop if the handling of the raised
58
+ # EventCompilationError fires an event as a warning instead of an error.
59
+ raise EventCompilationError(e.message(), node)
60
+ elif self.warn_error_options.silenced(event_name):
61
+ # Return early if the event is silenced
62
+ return
63
+
17
64
  if os.environ.get("DBT_TEST_BINARY_SERIALIZATION"):
18
65
  print(f"--- {msg.info.name}")
19
66
  try:
@@ -48,8 +95,17 @@ class EventManager:
48
95
  class IEventManager(Protocol):
49
96
  callbacks: List[TCallback]
50
97
  loggers: List[_Logger]
51
-
52
- def fire_event(self, e: BaseEvent, level: Optional[EventLevel] = None) -> None:
98
+ warn_error: bool
99
+ warn_error_options: WarnErrorOptions
100
+ require_warn_or_error_handling: bool
101
+
102
+ def fire_event(
103
+ self,
104
+ e: BaseEvent,
105
+ level: Optional[EventLevel] = None,
106
+ node: Any = None,
107
+ force_warn_or_error_handling: bool = False,
108
+ ) -> None:
53
109
  ...
54
110
 
55
111
  def add_logger(self, config: LoggerConfig) -> None:
@@ -65,8 +121,17 @@ class TestEventManager(IEventManager):
65
121
  def __init__(self) -> None:
66
122
  self.event_history: List[Tuple[BaseEvent, Optional[EventLevel]]] = []
67
123
  self.loggers = []
68
-
69
- def fire_event(self, e: BaseEvent, level: Optional[EventLevel] = None) -> None:
124
+ self.warn_error = False
125
+ self.warn_error_options = WarnErrorOptions(include=[], exclude=[])
126
+ self.require_warn_or_error_handling = False
127
+
128
+ def fire_event(
129
+ self,
130
+ e: BaseEvent,
131
+ level: Optional[EventLevel] = None,
132
+ node: Any = None,
133
+ force_warn_or_error_handling: bool = False,
134
+ ) -> None:
70
135
  self.event_history.append((e, level))
71
136
 
72
137
  def add_logger(self, config: LoggerConfig) -> None:
@@ -1,9 +1,8 @@
1
1
  from pathlib import Path
2
2
 
3
3
  from dbt_common.events.event_manager_client import get_event_manager
4
- from dbt_common.exceptions import EventCompilationError
5
- from dbt_common.invocation import get_invocation_id
6
4
  from dbt_common.helper_types import WarnErrorOptions
5
+ from dbt_common.invocation import get_invocation_id
7
6
  from dbt_common.utils.encoding import ForgivingJSONEncoder
8
7
  from dbt_common.events.base_types import BaseEvent, EventLevel, EventMsg
9
8
  from dbt_common.events.logger import LoggerConfig, LineFormat
@@ -13,7 +12,7 @@ from functools import partial
13
12
  import json
14
13
  import os
15
14
  import sys
16
- from typing import Callable, Dict, Optional, TextIO, Union
15
+ from typing import Any, Callable, Dict, Optional, TextIO, Union
17
16
  from google.protobuf.json_format import MessageToDict
18
17
 
19
18
  LOG_VERSION = 3
@@ -114,12 +113,9 @@ def msg_to_dict(msg: EventMsg) -> dict:
114
113
  return msg_dict
115
114
 
116
115
 
116
+ # This function continues to exist to provide backwards compatibility
117
117
  def warn_or_error(event, node=None) -> None:
118
- event_name = type(event).__name__
119
- if WARN_ERROR or WARN_ERROR_OPTIONS.includes(event_name):
120
- raise EventCompilationError(event.message(), node)
121
- elif not WARN_ERROR_OPTIONS.silenced(event_name):
122
- fire_event(event)
118
+ fire_event(e=event, node=node, force_warn_or_error_handling=True)
123
119
 
124
120
 
125
121
  # an alternative to fire_event which only creates and logs the event value
@@ -135,8 +131,15 @@ def fire_event_if(
135
131
  # this is where all the side effects happen branched by event type
136
132
  # (i.e. - mutating the event history, printing to stdout, logging
137
133
  # to files, etc.)
138
- def fire_event(e: BaseEvent, level: Optional[EventLevel] = None) -> None:
139
- get_event_manager().fire_event(e, level=level)
134
+ def fire_event(
135
+ e: BaseEvent,
136
+ level: Optional[EventLevel] = None,
137
+ node: Any = None,
138
+ force_warn_or_error_handling: bool = False,
139
+ ) -> None:
140
+ get_event_manager().fire_event(
141
+ e, level=level, node=node, force_warn_or_error_handling=force_warn_or_error_handling
142
+ )
140
143
 
141
144
 
142
145
  def get_metadata_vars() -> Dict[str, str]:
dbt_common/record.py CHANGED
@@ -12,13 +12,16 @@ import json
12
12
  import os
13
13
 
14
14
  from enum import Enum
15
+ from threading import Lock
15
16
  from typing import Any, Callable, Dict, List, Mapping, Optional, TextIO, Tuple, Type
16
- import contextvars
17
17
 
18
18
  from mashumaro import field_options
19
19
  from mashumaro.mixins.json import DataClassJSONMixin
20
20
  from mashumaro.types import SerializationStrategy
21
21
 
22
+ import contextvars
23
+
24
+
22
25
  RECORDED_BY_HIGHER_FUNCTION = contextvars.ContextVar("RECORDED_BY_HIGHER_FUNCTION", default=False)
23
26
 
24
27
 
@@ -31,9 +34,10 @@ class Record:
31
34
  result_cls: Optional[type] = None
32
35
  group: Optional[str] = None
33
36
 
34
- def __init__(self, params, result) -> None:
37
+ def __init__(self, params, result, seq=None) -> None:
35
38
  self.params = params
36
39
  self.result = result
40
+ self.seq = seq
37
41
 
38
42
  def to_dict(self) -> Dict[str, Any]:
39
43
  return {
@@ -45,6 +49,7 @@ class Record:
45
49
  else dataclasses.asdict(self.result)
46
50
  if self.result is not None
47
51
  else None,
52
+ "seq": self.seq,
48
53
  }
49
54
 
50
55
  @classmethod
@@ -61,7 +66,8 @@ class Record:
61
66
  if cls.result_cls is not None
62
67
  else None
63
68
  )
64
- return cls(params=p, result=r)
69
+ s = dct.get("seq", None)
70
+ return cls(params=p, result=r, seq=s)
65
71
 
66
72
 
67
73
  class Diff:
@@ -145,6 +151,7 @@ class Recorder:
145
151
  types: Optional[List],
146
152
  current_recording_path: str = "recording.json",
147
153
  previous_recording_path: Optional[str] = None,
154
+ in_memory: bool = False,
148
155
  ) -> None:
149
156
  self.mode = mode
150
157
  self.recorded_types = types
@@ -167,6 +174,18 @@ class Recorder:
167
174
  if self.mode == RecorderMode.REPLAY:
168
175
  self._unprocessed_records_by_type = self.load(self.previous_recording_path)
169
176
 
177
+ self._counter = 0
178
+ self._counter_lock = Lock()
179
+
180
+ self._record_added = False
181
+ self._recording_file: Optional[TextIO] = None
182
+ if mode == RecorderMode.RECORD and not in_memory:
183
+ self._recording_file = open(current_recording_path, "w")
184
+ self._recording_file.write("[")
185
+
186
+ def __del__(self):
187
+ self.clean_up_stream()
188
+
170
189
  @classmethod
171
190
  def register_record_type(cls, rec_type) -> Any:
172
191
  cls._record_cls_by_name[rec_type.__name__] = rec_type
@@ -175,9 +194,26 @@ class Recorder:
175
194
 
176
195
  def add_record(self, record: Record) -> None:
177
196
  rec_cls_name = record.__class__.__name__ # type: ignore
178
- if rec_cls_name not in self._records_by_type:
179
- self._records_by_type[rec_cls_name] = []
180
- self._records_by_type[rec_cls_name].append(record)
197
+
198
+ with self._counter_lock:
199
+ record.seq = self._counter
200
+ self._counter += 1
201
+
202
+ if self._recording_file is not None:
203
+ if self._record_added:
204
+ self._recording_file.write(",")
205
+ try:
206
+ dct = Recorder._get_tagged_dict(record, rec_cls_name)
207
+ json.dump(dct, self._recording_file)
208
+ self._record_added = True
209
+ except Exception:
210
+ json.dump(
211
+ {"type": "RecordingError", "record_type": rec_cls_name}, self._recording_file
212
+ )
213
+ else:
214
+ if rec_cls_name not in self._records_by_type:
215
+ self._records_by_type[rec_cls_name] = []
216
+ self._records_by_type[rec_cls_name].append(record)
181
217
 
182
218
  def pop_matching_record(self, params: Any) -> Optional[Record]:
183
219
  rec_type_name = self._record_name_by_params_name.get(type(params).__name__)
@@ -199,21 +235,39 @@ class Recorder:
199
235
  return match
200
236
 
201
237
  def write_json(self, out_stream: TextIO):
202
- d = self._to_dict()
238
+ d = self._to_list()
203
239
  json.dump(d, out_stream)
204
240
 
205
241
  def write(self) -> None:
206
- with open(self.current_recording_path, "w") as file:
207
- self.write_json(file)
208
-
209
- def _to_dict(self) -> Dict:
210
- dct: Dict[str, Any] = {}
211
-
242
+ if self._recording_file is not None:
243
+ self.clean_up_stream()
244
+ else:
245
+ with open(self.current_recording_path, "w") as file:
246
+ self.write_json(file)
247
+
248
+ def clean_up_stream(self) -> None:
249
+ if self._recording_file is not None:
250
+ self._recording_file.write("]")
251
+ self._recording_file.close()
252
+ self._recording_file = None
253
+
254
+ @staticmethod
255
+ def _get_tagged_dict(record: Record, record_type: str) -> Dict:
256
+ d = record.to_dict()
257
+ d["type"] = record_type
258
+ return d
259
+
260
+ def _to_list(self) -> List[Dict]:
261
+ record_list: List[Dict] = []
212
262
  for record_type in self._records_by_type:
213
- record_list = [r.to_dict() for r in self._records_by_type[record_type]]
214
- dct[record_type] = record_list
263
+ record_list.extend(
264
+ Recorder._get_tagged_dict(r, record_type)
265
+ for r in self._records_by_type[record_type]
266
+ )
267
+
268
+ record_list.sort(key=lambda r: r["seq"])
215
269
 
216
- return dct
270
+ return record_list
217
271
 
218
272
  @classmethod
219
273
  def load(cls, file_name: str) -> Dict[str, List[Dict[str, Any]]]:
@@ -331,7 +385,6 @@ def auto_record_function(
331
385
  None,
332
386
  group,
333
387
  index_on_thread_name,
334
- False,
335
388
  )
336
389
 
337
390
 
@@ -340,6 +393,7 @@ def record_function(
340
393
  method: bool = False,
341
394
  tuple_result: bool = False,
342
395
  id_field_name: Optional[str] = None,
396
+ index_on_thread_id: bool = False,
343
397
  ) -> Callable:
344
398
  """This is the @record_function decorator, which marks functions which will
345
399
  have their function calls recorded during record mode, and mocked out with
@@ -351,8 +405,7 @@ def record_function(
351
405
  tuple_result,
352
406
  id_field_name,
353
407
  None,
354
- False,
355
- False,
408
+ index_on_thread_id,
356
409
  )
357
410
 
358
411
 
@@ -402,7 +455,6 @@ def _record_function_inner(
402
455
  id_field_name,
403
456
  group,
404
457
  index_on_thread_id,
405
- is_classmethod,
406
458
  func_to_record,
407
459
  ):
408
460
  if isinstance(record_type, str):
@@ -442,7 +494,7 @@ def _record_function_inner(
442
494
  except LookupError:
443
495
  pass
444
496
 
445
- call_args = args[1:] if is_classmethod else args
497
+ call_args = args
446
498
 
447
499
  if recorder is None:
448
500
  return func_to_record(*call_args, **kwargs)
@@ -458,9 +510,16 @@ def _record_function_inner(
458
510
  param_args = args[1:] if method else args
459
511
  if method and id_field_name is not None:
460
512
  if index_on_thread_id:
461
- from dbt_common.context import get_invocation_context
513
+ from dbt_common.events.contextvars import get_node_info
514
+
515
+ node_info = get_node_info()
516
+ if node_info and "unique_id" in node_info:
517
+ thread_name = node_info["unique_id"]
518
+ else:
519
+ from dbt_common.context import get_invocation_context
462
520
 
463
- param_args = (get_invocation_context().name,) + param_args
521
+ thread_name = get_invocation_context().name
522
+ param_args = (thread_name,) + param_args
464
523
  else:
465
524
  param_args = (getattr(args[0], id_field_name),) + param_args
466
525
 
@@ -532,21 +591,25 @@ def supports_replay(cls):
532
591
  metadata = getattr(method, "_record_metadata", None)
533
592
  if method and getattr(method, "_record_metadata", None):
534
593
  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
- )
594
+ sub_method_metadata = getattr(sub_method, "_record_metadata", None)
595
+
596
+ if not sub_method_metadata:
597
+ recorded_sub_method = _record_function_inner(
598
+ metadata["record_type"],
599
+ metadata["method"],
600
+ metadata["tuple_result"],
601
+ metadata["id_field_name"],
602
+ metadata["group"],
603
+ metadata["index_on_thread_id"],
604
+ sub_method.__func__
605
+ if _is_classmethod(method)
606
+ else sub_method, # unwrap if classmethod
607
+ )
545
608
 
546
- if _is_classmethod(method):
547
- recorded_sub_method = classmethod(recorded_sub_method)
609
+ if _is_classmethod(method):
610
+ # rewrap if submethod
611
+ recorded_sub_method = classmethod(recorded_sub_method)
548
612
 
549
- if sub_method is not None:
550
613
  setattr(
551
614
  sub_cls,
552
615
  method_name,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbt-common
3
- Version: 1.15.0
3
+ Version: 1.17.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
@@ -1,13 +1,13 @@
1
- dbt_common/__about__.py,sha256=ifS0ZWsb82NyM4xyQWKPKGKE5bG3EXlYHT1H7h1HxOY,19
1
+ dbt_common/__about__.py,sha256=uYViEABuLbLykJW0jxwSXYZEExCXp3lcdeO8uJWFORw,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=tVeXtsptvuw7d8CvdlYSBFcKLyLZ852iQNwcxNmUzYY,2577
5
+ dbt_common/context.py,sha256=-ErtKG4xfOh1-Y569fwu6u2O381nRan18HhATrYDoZE,2950
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
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=ExF8ccUpDv2kButAMnTR8zSyD9agU7nhXTKFDx7Iw7Y,19352
10
+ dbt_common/record.py,sha256=90NwLo0jZQkdQwS3QMnvEmtVrBESvIhP-1LMfXfE3rA,21620
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
@@ -30,10 +30,10 @@ dbt_common/events/__init__.py,sha256=av08vfpxo0ek7PqZNtMxY8FODJ3xwph4ehRxgInx4LA
30
30
  dbt_common/events/base_types.py,sha256=bdDMbawAV0FkxmvuxgsTev82vxTuyu6rJiSkvEQPsO8,5525
31
31
  dbt_common/events/contextvars.py,sha256=EIs1P6NrJzx_IAV17x5cVqOAS4Lqbu6oc0etHtWCJOo,3097
32
32
  dbt_common/events/event_handler.py,sha256=jfi0PyqIOGnXCG9HEa0VIVULqNvXs1RYmAg0b50ChQs,1385
33
- dbt_common/events/event_manager.py,sha256=IIUwSyt_RcBbUI_iE5mnpmZt2uW7lG49RXOWz2VlUv0,2300
33
+ dbt_common/events/event_manager.py,sha256=0CDHNh_qTjdj4blpJiJ7gq6YkP1NzjE0iIct4v_MdoA,4588
34
34
  dbt_common/events/event_manager_client.py,sha256=VKlIYJPcexmDKnidkyrs8BIuNZ1_CwDFGz-gBM2SAvo,1193
35
35
  dbt_common/events/format.py,sha256=x1RWDZ8G7ZMHmxdld6Q4VXca4kvnhiQOIaQXkC6Uo0Q,1609
36
- dbt_common/events/functions.py,sha256=_7CLApCKb9KhurOgfVRpW-yGKGE_yjYUguiAaLxVwnw,4752
36
+ dbt_common/events/functions.py,sha256=R3DuyNy2TqOwNyMACVOYtiG1NjZ9FQa6FWKkzMeMCBY,4767
37
37
  dbt_common/events/helpers.py,sha256=CfsWwNDjsLJkPIgOtAfuLEnZ3rGUKeYsH8aDtCW12OA,410
38
38
  dbt_common/events/interfaces.py,sha256=hEDeDoB0FW2RYHVZBG7gebEt_mUVBzkn1yPubpaxs-s,147
39
39
  dbt_common/events/logger.py,sha256=iBxMhFhAo8wL4NA4Z31pf644I0tsCOWIrt-k4d7EzaY,6760
@@ -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.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,,
60
+ dbt_common-1.17.0.dist-info/METADATA,sha256=CxILo-M8pIxC0v3avF2ekgOrxwBrC_BHv5bD8kXKyk8,4895
61
+ dbt_common-1.17.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
+ dbt_common-1.17.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
63
+ dbt_common-1.17.0.dist-info/RECORD,,