dcs-sdk 1.5.4__py3-none-any.whl → 1.5.6__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.
@@ -326,6 +326,12 @@ class String_Alphanum(ColType_Alphanum, StringType):
326
326
  except ValueError:
327
327
  return False
328
328
 
329
+ def make_value(self, value) -> ArithAlphanumeric:
330
+ if isinstance(value, ArithAlphanumeric):
331
+ return value
332
+ # Coerce non-string primitives (e.g., integers) to string for alphanumeric representation
333
+ return ArithAlphanumeric(str(value))
334
+
329
335
 
330
336
  @attrs.define(frozen=True)
331
337
  class String_VaryingAlphanum(String_Alphanum):
data_diff/diff_tables.py CHANGED
@@ -28,7 +28,7 @@ import attrs
28
28
  # logger = getLogger(__name__)
29
29
  from loguru import logger
30
30
 
31
- from data_diff.abcs.database_types import IKey
31
+ from data_diff.abcs.database_types import IKey, Integer, StringType
32
32
  from data_diff.errors import DataDiffMismatchingKeyTypesError
33
33
  from data_diff.info_tree import InfoTree, SegmentInfo
34
34
  from data_diff.table_segment import TableSegment, create_mesh_from_points
@@ -340,13 +340,22 @@ class TableDiffer(ThreadBase, ABC):
340
340
  if not isinstance(kt, IKey):
341
341
  raise NotImplementedError(f"Cannot use a column of type {kt} as a key")
342
342
 
343
+ mismatched_key_types = False
343
344
  for i, (kt1, kt2) in enumerate(safezip(key_types1, key_types2)):
344
345
  if kt1.python_type is not kt2.python_type:
345
- k1 = table1.key_columns[i]
346
- k2 = table2.key_columns[i]
347
- raise DataDiffMismatchingKeyTypesError(
348
- f"Key columns {k1} type: {kt1.python_type} and {k2} type: {kt2.python_type} can't be compared due to different types."
349
- )
346
+ # Allow integer vs string, and string vs string variants for diffing, but mark as mismatched
347
+ if (isinstance(kt1, Integer) and isinstance(kt2, StringType)) or (
348
+ isinstance(kt2, Integer) and isinstance(kt1, StringType)
349
+ ):
350
+ mismatched_key_types = True
351
+ elif isinstance(kt1, StringType) and isinstance(kt2, StringType):
352
+ mismatched_key_types = True
353
+ else:
354
+ k1 = table1.key_columns[i]
355
+ k2 = table2.key_columns[i]
356
+ raise DataDiffMismatchingKeyTypesError(
357
+ f"Key columns {k1} type: {kt1.python_type} and {k2} type: {kt2.python_type} can't be compared due to different types."
358
+ )
350
359
 
351
360
  # Query min/max values
352
361
  key_ranges = self._threaded_call_as_completed("query_key_range", [table1, table2])
@@ -380,24 +389,27 @@ class TableDiffer(ThreadBase, ABC):
380
389
  # Overall, the max number of new regions in this 2nd pass is 3^|k| - 1
381
390
 
382
391
  # Note: python types can be the same, but the rendering parameters (e.g. casing) can differ.
383
- min_key2, max_key2 = self._parse_key_range_result(key_types2, next(key_ranges))
384
-
385
- points = [list(sorted(p)) for p in safezip(min_key1, min_key2, max_key1, max_key2)]
386
- box_mesh = create_mesh_from_points(*points)
387
-
388
- new_regions = [(p1, p2) for p1, p2 in box_mesh if p1 < p2 and not (p1 >= min_key1 and p2 <= max_key1)]
389
-
390
- for p1, p2 in new_regions:
391
- extra_table1 = table1.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types1)
392
- extra_table2 = table2.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types2)
393
- ti.submit(
394
- self._bisect_and_diff_segments,
395
- ti,
396
- extra_table1,
397
- extra_table2,
398
- info_tree,
399
- priority=999,
400
- )
392
+ # If key types mismatched (e.g., int vs string), skip the second meshing pass to avoid
393
+ # attempting to sort mixed-type tuples (e.g., ArithAlphanumeric vs int).
394
+ if not mismatched_key_types:
395
+ min_key2, max_key2 = self._parse_key_range_result(key_types2, next(key_ranges))
396
+
397
+ points = [list(sorted(p)) for p in safezip(min_key1, min_key2, max_key1, max_key2)]
398
+ box_mesh = create_mesh_from_points(*points)
399
+
400
+ new_regions = [(p1, p2) for p1, p2 in box_mesh if p1 < p2 and not (p1 >= min_key1 and p2 <= max_key1)]
401
+
402
+ for p1, p2 in new_regions:
403
+ extra_table1 = table1.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types1)
404
+ extra_table2 = table2.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types2)
405
+ ti.submit(
406
+ self._bisect_and_diff_segments,
407
+ ti,
408
+ extra_table1,
409
+ extra_table2,
410
+ info_tree,
411
+ priority=999,
412
+ )
401
413
 
402
414
  return ti
403
415
 
@@ -448,7 +448,39 @@ class HashDiffer(TableDiffer):
448
448
  ):
449
449
  # Check if level exceeds maximum allowed recursion depth
450
450
  if level > 15:
451
- raise RecursionError(f"Maximum recursion level exceeded: {level} > 15")
451
+ logger.warning(
452
+ ". " * level
453
+ + f"Maximum recursion level reached ({level}); switching to direct row comparison for segment {table1.min_key}..{table1.max_key}"
454
+ )
455
+ # Fallback: download rows and diff locally to prevent excessive recursion
456
+ rows1, rows2 = self._threaded_call("get_values", [table1, table2])
457
+ json_cols = {
458
+ i: colname
459
+ for i, colname in enumerate(table1.extra_columns)
460
+ if isinstance(table1._schema[colname], JSON)
461
+ }
462
+ diff = list(
463
+ diff_sets(
464
+ rows1,
465
+ rows2,
466
+ json_cols=json_cols,
467
+ columns1=table1.relevant_columns,
468
+ columns2=table2.relevant_columns,
469
+ key_columns1=table1.key_columns,
470
+ key_columns2=table2.key_columns,
471
+ ignored_columns1=self.ignored_columns1,
472
+ ignored_columns2=self.ignored_columns2,
473
+ diff_tracker=self._diff_tracker,
474
+ )
475
+ )
476
+ info_tree.info.set_diff(diff)
477
+ info_tree.info.rowcounts = {1: len(rows1), 2: len(rows2)}
478
+ self.stats["rows_downloaded"] = self.stats.get("rows_downloaded", 0) + max(len(rows1), len(rows2))
479
+ logger.info(
480
+ ". " * level
481
+ + f"Diff found {len(diff)} different rows, {self.stats['rows_downloaded']} total rows downloaded."
482
+ )
483
+ return diff
452
484
 
453
485
  # Initialize diff tracker if not already done
454
486
  self._initialize_diff_tracker(table1, table2)
@@ -553,7 +585,39 @@ class HashDiffer(TableDiffer):
553
585
  ):
554
586
  # Check if level exceeds maximum allowed recursion depth
555
587
  if level > 15:
556
- raise RecursionError(f"Maximum recursion level exceeded: {level} > 15")
588
+ logger.warning(
589
+ ". " * level
590
+ + f"Maximum recursion level reached ({level}); switching to direct row comparison for segment {table1.min_key}..{table1.max_key}"
591
+ )
592
+ # Fallback: download rows and diff locally to prevent excessive recursion
593
+ rows1, rows2 = self._threaded_call("get_values", [table1, table2])
594
+ json_cols = {
595
+ i: colname
596
+ for i, colname in enumerate(table1.extra_columns)
597
+ if isinstance(table1._schema[colname], JSON)
598
+ }
599
+ diff = list(
600
+ diff_sets(
601
+ rows1,
602
+ rows2,
603
+ json_cols=json_cols,
604
+ columns1=table1.relevant_columns,
605
+ columns2=table2.relevant_columns,
606
+ key_columns1=table1.key_columns,
607
+ key_columns2=table2.key_columns,
608
+ ignored_columns1=self.ignored_columns1,
609
+ ignored_columns2=self.ignored_columns2,
610
+ diff_tracker=self._diff_tracker,
611
+ )
612
+ )
613
+ info_tree.info.set_diff(diff)
614
+ info_tree.info.rowcounts = {1: len(rows1), 2: len(rows2)}
615
+ self.stats["rows_downloaded"] = self.stats.get("rows_downloaded", 0) + max(len(rows1), len(rows2))
616
+ logger.info(
617
+ ". " * level
618
+ + f"Diff found {len(diff)} different rows, {self.stats['rows_downloaded']} total rows downloaded."
619
+ )
620
+ return diff
557
621
 
558
622
  assert table1.is_bounded and table2.is_bounded
559
623
 
@@ -252,6 +252,15 @@ class TableSegment:
252
252
  def _where(self) -> Optional[str]:
253
253
  return f"({self.where})" if self.where else None
254
254
 
255
+ def _column_expr(self, column_name: str) -> Expr:
256
+ """Return expression for a column, applying configured SQL transform if present."""
257
+ quoted_column_name = self.database.quote(s=column_name)
258
+ if self.transform_columns and column_name in self.transform_columns:
259
+ transform_expr = self.transform_columns[column_name]
260
+ quoted_expr = transform_expr.format(column=quoted_column_name)
261
+ return Code(quoted_expr)
262
+ return this[column_name]
263
+
255
264
  def _with_raw_schema(self, raw_schema: Dict[str, RawColumnInfo]) -> Self:
256
265
  schema = self.database._process_table_schema(self.table_path, raw_schema, self.relevant_columns, self._where())
257
266
  # return self.new(schema=create_schema(self.database.name, self.table_path, schema, self.case_sensitive))
@@ -277,10 +286,24 @@ class TableSegment:
277
286
  def _make_key_range(self):
278
287
  if self.min_key is not None:
279
288
  for mn, k in safezip(self.min_key, self.key_columns):
280
- yield mn <= this[k]
289
+ quoted = self.database.dialect.quote(k)
290
+ base_expr_sql = (
291
+ self.transform_columns[k].format(column=quoted)
292
+ if self.transform_columns and k in self.transform_columns
293
+ else quoted
294
+ )
295
+ constant_val = self.database.dialect._constant_value(mn)
296
+ yield Code(f"{base_expr_sql} >= {constant_val}")
281
297
  if self.max_key is not None:
282
298
  for k, mx in safezip(self.key_columns, self.max_key):
283
- yield this[k] < mx
299
+ quoted = self.database.dialect.quote(k)
300
+ base_expr_sql = (
301
+ self.transform_columns[k].format(column=quoted)
302
+ if self.transform_columns and k in self.transform_columns
303
+ else quoted
304
+ )
305
+ constant_val = self.database.dialect._constant_value(mx)
306
+ yield Code(f"{base_expr_sql} < {constant_val}")
284
307
 
285
308
  def _make_update_range(self):
286
309
  if self.min_update is not None:
@@ -353,9 +376,14 @@ class TableSegment:
353
376
  and_exprs = []
354
377
  for col, val in safezip(self.key_columns, key_values):
355
378
  quoted = self.database.dialect.quote(col)
379
+ base_expr_sql = (
380
+ self.transform_columns[col].format(column=quoted)
381
+ if self.transform_columns and col in self.transform_columns
382
+ else quoted
383
+ )
356
384
  schema = self._schema[col]
357
385
  if val is None:
358
- and_exprs.append(Code(quoted + " IS NULL"))
386
+ and_exprs.append(Code(base_expr_sql + " IS NULL"))
359
387
  continue
360
388
  mk_v = schema.make_value(val)
361
389
  constant_val = self.database.dialect._constant_value(mk_v)
@@ -364,9 +392,9 @@ class TableSegment:
364
392
  if hasattr(self.database.dialect, "timestamp_equality_condition") and hasattr(
365
393
  mk_v, "_dt"
366
394
  ): # Check if it's a datetime-like object
367
- where_expr = self.database.dialect.timestamp_equality_condition(quoted, constant_val)
395
+ where_expr = self.database.dialect.timestamp_equality_condition(base_expr_sql, constant_val)
368
396
  else:
369
- where_expr = f"{quoted} = {constant_val}"
397
+ where_expr = f"{base_expr_sql} = {constant_val}"
370
398
 
371
399
  and_exprs.append(Code(where_expr))
372
400
  if and_exprs:
@@ -437,14 +465,8 @@ class TableSegment:
437
465
  # return [NormalizeAsString(this[c]) for c in self.relevant_columns]
438
466
  expressions = []
439
467
  for c in self.relevant_columns:
440
- quoted_column_name = self.database.quote(s=c)
441
468
  schema = self._schema[c]
442
- if self.transform_columns and c in self.transform_columns:
443
- transform_expr = self.transform_columns[c]
444
- quoted_expr = transform_expr.format(column=quoted_column_name)
445
- expressions.append(NormalizeAsString(Code(quoted_expr), schema))
446
- else:
447
- expressions.append(NormalizeAsString(this[c], schema))
469
+ expressions.append(NormalizeAsString(self._column_expr(c), schema))
448
470
  return expressions
449
471
 
450
472
  def count(self) -> int:
@@ -460,10 +482,13 @@ class TableSegment:
460
482
  """Count and checksum the rows in the segment, in one pass."""
461
483
 
462
484
  checked_columns = [c for c in self.relevant_columns if c not in self.ignored_columns]
463
- # cols = [NormalizeAsString(this[c]) for c in checked_columns]
485
+ # Build transformed expressions for checksum, honoring transforms and normalization
486
+ checksum_exprs: List[Expr] = []
487
+ for c in checked_columns:
488
+ schema = self._schema[c]
489
+ checksum_exprs.append(NormalizeAsString(self._column_expr(c), schema))
464
490
 
465
- # q = self.make_select().select(Count(), Checksum(cols))
466
- q = self.make_select().select(Count(), Checksum(self._relevant_columns_repr))
491
+ q = self.make_select().select(Count(), Checksum(checksum_exprs))
467
492
  start_time = time.monotonic()
468
493
  count, checksum = self.database.query(q, tuple)
469
494
  query_time_ms = (time.monotonic() - start_time) * 1000
@@ -486,7 +511,7 @@ class TableSegment:
486
511
  """Query database for minimum and maximum key. This is used for setting the initial bounds."""
487
512
  # Normalizes the result (needed for UUIDs) after the min/max computation
488
513
  select = self.make_select().select(
489
- ApplyFuncAndNormalizeAsString(this[k], f) for k in self.key_columns for f in (min_, max_)
514
+ ApplyFuncAndNormalizeAsString(self._column_expr(k), f) for k in self.key_columns for f in (min_, max_)
490
515
  )
491
516
  result = tuple(self.database.query(select, tuple))
492
517
 
data_diff/utils.py CHANGED
@@ -171,6 +171,10 @@ def _any_to_uuid(v: Union[str, int, UUID, "ArithUUID"]) -> UUID:
171
171
  return v.uuid
172
172
  elif isinstance(v, UUID):
173
173
  return v
174
+ # Accept unicode/arithmetic strings that wrap a UUID
175
+ elif "ArithUnicodeString" in globals() and isinstance(v, ArithUnicodeString):
176
+ s = getattr(v, "_str", str(v))
177
+ return UUID(s)
174
178
  elif isinstance(v, str):
175
179
  return UUID(v)
176
180
  elif isinstance(v, int):
dcs_sdk/__version__.py CHANGED
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "1.5.4"
15
+ __version__ = "1.5.6"
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: dcs-sdk
3
- Version: 1.5.4
3
+ Version: 1.5.6
4
4
  Summary: SDK for DataChecks
5
5
  Author: Waterdip Labs
6
6
  Author-email: hello@waterdip.ai
@@ -43,25 +43,25 @@ Requires-Dist: oracledb (>=2.4.1) ; extra == "oracle" or extra == "all-dbs"
43
43
  Requires-Dist: packaging (>=24.1,<25.0)
44
44
  Requires-Dist: preql (>=0.2.19) ; extra == "preql" or extra == "all-dbs"
45
45
  Requires-Dist: presto-python-client (>=0.8.4) ; extra == "presto" or extra == "all-dbs"
46
- Requires-Dist: protobuf (>=5.29.5)
46
+ Requires-Dist: protobuf (>=5.29.5,<6.0.0)
47
47
  Requires-Dist: psycopg2-binary (>=2.9.9,<3.0.0) ; extra == "postgresql" or extra == "redshift" or extra == "all-dbs"
48
48
  Requires-Dist: pydantic (>=1.10.12)
49
49
  Requires-Dist: pyodbc (>=4.0.39) ; extra == "mssql" or extra == "sybase" or extra == "all-dbs"
50
50
  Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
51
51
  Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
52
- Requires-Dist: requests (>=2.32.4)
52
+ Requires-Dist: requests (>=2.32.4,<3.0.0)
53
53
  Requires-Dist: rich (>=13.8.0)
54
- Requires-Dist: snowflake-connector-python (>=3.13.1) ; extra == "snowflake" or extra == "all-dbs"
54
+ Requires-Dist: snowflake-connector-python (>=3.17.2) ; extra == "snowflake" or extra == "all-dbs"
55
55
  Requires-Dist: tabulate (>=0.9.0)
56
56
  Requires-Dist: toml (>=0.10.2)
57
57
  Requires-Dist: trino (>=0.314.0) ; extra == "trino" or extra == "all-dbs"
58
58
  Requires-Dist: typing-extensions (>=4.0.1)
59
- Requires-Dist: urllib3 (>=2.5.0)
59
+ Requires-Dist: urllib3 (>=2.5.0,<3.0.0)
60
60
  Requires-Dist: vertica-python (>=1.4.0) ; extra == "vertica" or extra == "all-dbs"
61
61
  Description-Content-Type: text/markdown
62
62
 
63
63
  <h1 align="center">
64
- DCS SDK v1.5.4
64
+ DCS SDK v1.5.6
65
65
  </h1>
66
66
 
67
67
  > SDK for DataChecks
@@ -2,7 +2,7 @@ data_diff/__init__.py,sha256=TGNvifF-dIbitACA6PS4sORtHEcTUukcrZz2NEIsL9U,10336
2
2
  data_diff/__main__.py,sha256=UvFvBKU74202bfRcIO_Wk-SU8WmnNuDK_1YVJpueMlc,16969
3
3
  data_diff/abcs/__init__.py,sha256=RkfhRKLXEForLCs4rZkTf0qc_b0TokSggSAcKI4yfZg,610
4
4
  data_diff/abcs/compiler.py,sha256=RuGhGlLTQuCzOJfYxa4gjcADsyvbZ9yZPuDuY6XH8Rk,785
5
- data_diff/abcs/database_types.py,sha256=OTx6GSUQnuQYkRN7yN0Di8mF-Wt7rTtyzjAQPenHzzw,11054
5
+ data_diff/abcs/database_types.py,sha256=MKnWM9QBgeo-hjhgHhHWezd5i7HjozZ4ujsnzQ7ALOs,11326
6
6
  data_diff/config.py,sha256=uRcoVVhPjVZqgQNwr18v6sPq06cGXDLemTUyitU57zA,4998
7
7
  data_diff/databases/__init__.py,sha256=NrBm1Paj7jkHZ_hQCD-4-Q1eeDdh3v9_bz1DkPDOv9g,1680
8
8
  data_diff/databases/_connect.py,sha256=nGsmtzDSKN8CK8zMkdcGZz0iExzkJDYw-PGebIkmQgc,11151
@@ -21,10 +21,10 @@ data_diff/databases/snowflake.py,sha256=7G6fvVJXOtTvXmSfWCxTslF4WohoscQoiqcmJIN6
21
21
  data_diff/databases/sybase.py,sha256=QUGol1uLZ2KfvcYZIBUNfkfEJ8JxPUnvaT9QJBS70FU,31250
22
22
  data_diff/databases/trino.py,sha256=VIN3gMJvT4oSYuXCJ1QnngVL2gjjEYMFw87QTHgjs8c,2328
23
23
  data_diff/databases/vertica.py,sha256=2dSDZp6qOEvUVPldI5Tgn7Sm3dCpC3vNXJL3qb3FDvQ,5529
24
- data_diff/diff_tables.py,sha256=Ey88gUr9Wh8UVsgRlBCY3CACIYfHL52PxJSrd821aqg,20060
24
+ data_diff/diff_tables.py,sha256=AyFJF6oaam06AH4ZPI8pj63BiYojHoZTykjrdJCX2fI,20899
25
25
  data_diff/errors.py,sha256=4Yru8yOwyuDuBlTABnGCvJMSpe6-rbLJpNnVHeTTyHU,745
26
26
  data_diff/format.py,sha256=QFDjdZaBVf_N-jfKiX4ppOUdpXTPZXmv1j0pc1RiOoc,10245
27
- data_diff/hashdiff_tables.py,sha256=nbE3mfILWUYT9Z38P0lKskD_DrNOV4G_752EfmwGBxg,28339
27
+ data_diff/hashdiff_tables.py,sha256=EBhEAZz-2a-qNs3OlFArInAV1KszBdZPotZmX7Z_lwo,31315
28
28
  data_diff/info_tree.py,sha256=yHtFSoXuu6oBafLYOYQjUSKlB-DnAAd08U9HOEAdTPI,2799
29
29
  data_diff/joindiff_tables.py,sha256=fyrEYjyh2BX1vGibwVZLYM1V6JJTOY-uGXY-KInvMkw,17612
30
30
  data_diff/lexicographic_space.py,sha256=bBoCbbH1Mla9jNOq1b5RuwjAxSVU7gWkra673tPBwXQ,8305
@@ -37,13 +37,13 @@ data_diff/queries/base.py,sha256=pT-iaII7Nlu-w-Cuq9fhoNKX7-GSxkQ3Fk8K-tMkk60,964
37
37
  data_diff/queries/extras.py,sha256=aUm-ifj3BMlz4o4bbuHtmnvHZuptYAKGS5yWTHmNpvc,1270
38
38
  data_diff/query_utils.py,sha256=R7ZfRwcvv9Zf4zWXNln4tr_OxLmDI7CPmmCahYfHxlo,2101
39
39
  data_diff/schema.py,sha256=QoYSSB3k-svLXz680uRgsI4qjii8BFKOOQvheqtgEbs,2413
40
- data_diff/table_segment.py,sha256=3UYy7FkNq4FjxPbmE7KH7OJ15ZRhH7Db5N_HSOnQ-dA,22014
40
+ data_diff/table_segment.py,sha256=SdBVHLndDWMuLLM9zuUbfyTXZtNQgXarVLOmQTUWCCY,23356
41
41
  data_diff/thread_utils.py,sha256=_692ERjnWfHKaZsLdg7CNfkKiRd66y7_kpgDwzntp44,3831
42
- data_diff/utils.py,sha256=8vbVbJvBSqtRfrzvQsz79qIAF2bHn1dnufijstDxddU,31345
42
+ data_diff/utils.py,sha256=ZieHmjARw9-gwpOAlq1KWX1HGEf8oWbFMq_cOwNA308,31546
43
43
  data_diff/version.py,sha256=Wk0ovyBlLEF2UaWLWEcVBLFElREtIxi7TU1hD3CuTFI,634
44
44
  dcs_sdk/__init__.py,sha256=RkfhRKLXEForLCs4rZkTf0qc_b0TokSggSAcKI4yfZg,610
45
45
  dcs_sdk/__main__.py,sha256=Qn8stIaQGrdLjHQ-H7xO0T-brtq5RWZoWU9QvqoarV8,683
46
- dcs_sdk/__version__.py,sha256=_DZDeYH_J9poBV0fFD1k1kQKGmlR3YXp5et_7jZLRxI,633
46
+ dcs_sdk/__version__.py,sha256=w4A2kNS5X3tFX6emKhBSgCLahVomBlBGVM4ZyOge6-8,633
47
47
  dcs_sdk/cli/__init__.py,sha256=RkfhRKLXEForLCs4rZkTf0qc_b0TokSggSAcKI4yfZg,610
48
48
  dcs_sdk/cli/cli.py,sha256=LyrRk972OL9pTqrvBeXWBu5rUDAN17lQ1g8FdSRW_8M,4299
49
49
  dcs_sdk/sdk/__init__.py,sha256=skrZcgWWJBL6NXTUERywJ3qRJRemgpDXyW7lPg1FJk8,2107
@@ -65,7 +65,7 @@ dcs_sdk/sdk/utils/similarity_score/levenshtein_distance_provider.py,sha256=puAWP
65
65
  dcs_sdk/sdk/utils/table.py,sha256=X8HxdYTWyx_oVrBWPsXlmA-xJKXXDBW9RrhlWNqA1As,18224
66
66
  dcs_sdk/sdk/utils/themes.py,sha256=Meo2Yldv4uyPpEqI7qdA28Aa6sxtwUU1dLKKm4QavjM,1403
67
67
  dcs_sdk/sdk/utils/utils.py,sha256=vF2zAvgt__Y8limicWTEWRyn41SBVJN81ZCTBRy6hQg,11907
68
- dcs_sdk-1.5.4.dist-info/METADATA,sha256=hHx-XDpD7cE-Ji6ud3o-7HGCNKHoHJmdSDEp3maormU,6254
69
- dcs_sdk-1.5.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
70
- dcs_sdk-1.5.4.dist-info/entry_points.txt,sha256=zQtrZL7YuaKtt6WPwihCTV1BRXnqBkaY6zUGdYJbBSg,49
71
- dcs_sdk-1.5.4.dist-info/RECORD,,
68
+ dcs_sdk-1.5.6.dist-info/METADATA,sha256=u4KIEZPzBJJES9O_JuRsFh2Nlpy5UZ_U_0oW1lle944,6275
69
+ dcs_sdk-1.5.6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
70
+ dcs_sdk-1.5.6.dist-info/entry_points.txt,sha256=zQtrZL7YuaKtt6WPwihCTV1BRXnqBkaY6zUGdYJbBSg,49
71
+ dcs_sdk-1.5.6.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any