dcs-sdk 1.5.7__py3-none-any.whl → 1.5.9__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.
- data_diff/__init__.py +2 -0
- data_diff/databases/postgresql.py +7 -1
- data_diff/databases/sybase.py +3 -2
- data_diff/hashdiff_tables.py +313 -1
- dcs_sdk/__version__.py +1 -1
- dcs_sdk/sdk/config/config_loader.py +2 -0
- dcs_sdk/sdk/data_diff/data_differ.py +3 -0
- {dcs_sdk-1.5.7.dist-info → dcs_sdk-1.5.9.dist-info}/METADATA +2 -2
- {dcs_sdk-1.5.7.dist-info → dcs_sdk-1.5.9.dist-info}/RECORD +11 -11
- {dcs_sdk-1.5.7.dist-info → dcs_sdk-1.5.9.dist-info}/WHEEL +0 -0
- {dcs_sdk-1.5.7.dist-info → dcs_sdk-1.5.9.dist-info}/entry_points.txt +0 -0
data_diff/__init__.py
CHANGED
|
@@ -114,6 +114,7 @@ def diff_tables(
|
|
|
114
114
|
# Timeout limit in minutes
|
|
115
115
|
# (used for diffing large tables, to avoid long-running queries)
|
|
116
116
|
timeout_limit: int = DEAFULT_TIMEOUT,
|
|
117
|
+
in_memory_diff: bool = False,
|
|
117
118
|
) -> Iterator:
|
|
118
119
|
"""Finds the diff between table1 and table2.
|
|
119
120
|
|
|
@@ -198,6 +199,7 @@ def diff_tables(
|
|
|
198
199
|
per_column_diff_limit=per_column_diff_limit,
|
|
199
200
|
egress_limit=egress_limit,
|
|
200
201
|
timeout_limit=timeout_limit,
|
|
202
|
+
in_memory_diff=in_memory_diff,
|
|
201
203
|
)
|
|
202
204
|
elif algorithm == Algorithm.JOINDIFF:
|
|
203
205
|
if isinstance(materialize_to_table, str):
|
|
@@ -185,7 +185,13 @@ class PostgresqlDialect(BaseDialect):
|
|
|
185
185
|
return padded
|
|
186
186
|
|
|
187
187
|
def normalize_number(self, value: str, coltype: FractionalType) -> str:
|
|
188
|
-
|
|
188
|
+
precision = coltype.precision
|
|
189
|
+
if precision:
|
|
190
|
+
if precision >= 1000:
|
|
191
|
+
precision = 1000
|
|
192
|
+
elif precision <= -1000:
|
|
193
|
+
precision = -1000
|
|
194
|
+
return self.to_string(f"{value}::decimal(38, {precision})")
|
|
189
195
|
|
|
190
196
|
def normalize_boolean(self, value: str, _coltype: Boolean) -> str:
|
|
191
197
|
return self.to_string(f"{value}::int")
|
data_diff/databases/sybase.py
CHANGED
|
@@ -299,8 +299,9 @@ class Dialect(BaseDialect):
|
|
|
299
299
|
return timestamp_str
|
|
300
300
|
|
|
301
301
|
def normalize_number(self, value: str, coltype: FractionalType) -> str:
|
|
302
|
-
scale = getattr(coltype, "scale", 0) or 0
|
|
303
|
-
|
|
302
|
+
# scale = getattr(coltype, "scale", 0) or 0
|
|
303
|
+
precision = getattr(coltype, "precision", 0) or 0
|
|
304
|
+
return self.to_string(f"CAST({value} AS DECIMAL(38, {precision}))")
|
|
304
305
|
|
|
305
306
|
# def md5_as_int(self, s: str) -> str:
|
|
306
307
|
# """Returns an MD5 hash of the input string as an integer for Sybase IQ."""
|
data_diff/hashdiff_tables.py
CHANGED
|
@@ -18,7 +18,7 @@ import time
|
|
|
18
18
|
from collections import defaultdict
|
|
19
19
|
from numbers import Number
|
|
20
20
|
from threading import Lock
|
|
21
|
-
from typing import Any, Collection, Dict, Iterator, List, Sequence, Set, Tuple
|
|
21
|
+
from typing import Any, Collection, Dict, Iterator, List, Optional, Sequence, Set, Tuple
|
|
22
22
|
|
|
23
23
|
import attrs
|
|
24
24
|
from loguru import logger
|
|
@@ -711,3 +711,315 @@ class HashDiffer(TableDiffer):
|
|
|
711
711
|
return diff
|
|
712
712
|
|
|
713
713
|
return super()._bisect_and_diff_segments(ti, table1, table2, info_tree, level, max_rows)
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
@attrs.define(frozen=False)
|
|
717
|
+
class HashDiffer(HashDiffer):
|
|
718
|
+
"""
|
|
719
|
+
Enhanced HashDiffer with in-memory mode support.
|
|
720
|
+
|
|
721
|
+
Additional Parameters:
|
|
722
|
+
in_memory_diff (bool): If True, skip checksums and download segments directly for in-memory comparison.
|
|
723
|
+
If False, use standard checksum-based bisection (default behavior).
|
|
724
|
+
memory_segment_size (int): When in_memory_diff=True, target number of rows per segment before downloading.
|
|
725
|
+
"""
|
|
726
|
+
|
|
727
|
+
in_memory_diff: bool = False
|
|
728
|
+
memory_segment_size: int = 10000
|
|
729
|
+
|
|
730
|
+
def __attrs_post_init__(self) -> None:
|
|
731
|
+
super().__attrs_post_init__()
|
|
732
|
+
|
|
733
|
+
if self.in_memory_diff:
|
|
734
|
+
logger.info("=" * 70)
|
|
735
|
+
logger.info("IN-MEMORY DIFF MODE ENABLED")
|
|
736
|
+
logger.info(" - Checksum queries: DISABLED")
|
|
737
|
+
logger.info(f" - Segment size: {self.memory_segment_size} rows")
|
|
738
|
+
logger.info(f" - Threading: {'ENABLED' if self.threaded else 'DISABLED'}")
|
|
739
|
+
logger.info(f" - Egress limit: {self.egress_limit} rows")
|
|
740
|
+
logger.info("=" * 70)
|
|
741
|
+
|
|
742
|
+
# Adjust bisection threshold for in-memory mode
|
|
743
|
+
if self.memory_segment_size > 0:
|
|
744
|
+
self.bisection_threshold = self.memory_segment_size
|
|
745
|
+
|
|
746
|
+
def _should_skip_checksum_and_download(self, max_rows: int) -> bool:
|
|
747
|
+
"""
|
|
748
|
+
Determine if we should skip checksum and directly download segment data.
|
|
749
|
+
|
|
750
|
+
Returns True if:
|
|
751
|
+
1. in_memory_diff flag is enabled, OR
|
|
752
|
+
2. Traditional conditions: segment is below bisection threshold
|
|
753
|
+
"""
|
|
754
|
+
return self.in_memory_diff
|
|
755
|
+
# if self.in_memory_diff:
|
|
756
|
+
# # In memory mode: download if segment is at or below target size
|
|
757
|
+
# return max_rows <= self.memory_segment_size
|
|
758
|
+
# else:
|
|
759
|
+
# # Traditional mode: use bisection threshold
|
|
760
|
+
# return self.bisection_disabled or max_rows < self.bisection_threshold
|
|
761
|
+
|
|
762
|
+
def _diff_segments(
|
|
763
|
+
self,
|
|
764
|
+
ti,
|
|
765
|
+
table1: TableSegment,
|
|
766
|
+
table2: TableSegment,
|
|
767
|
+
info_tree: InfoTree,
|
|
768
|
+
max_rows: int,
|
|
769
|
+
level=0,
|
|
770
|
+
segment_index=None,
|
|
771
|
+
segment_count=None,
|
|
772
|
+
):
|
|
773
|
+
"""
|
|
774
|
+
Enhanced segment diffing with in-memory mode support.
|
|
775
|
+
"""
|
|
776
|
+
# Check recursion depth limit
|
|
777
|
+
if level > 15:
|
|
778
|
+
logger.warning(
|
|
779
|
+
". " * level + f"Maximum recursion level ({level}) reached; "
|
|
780
|
+
f"downloading segment {table1.min_key}..{table1.max_key}"
|
|
781
|
+
)
|
|
782
|
+
return self._download_and_diff_locally(table1, table2, info_tree, level)
|
|
783
|
+
|
|
784
|
+
# Initialize diff tracker
|
|
785
|
+
self._initialize_diff_tracker(table1, table2)
|
|
786
|
+
|
|
787
|
+
logger.info(
|
|
788
|
+
". " * level + f"Diffing segment {segment_index}/{segment_count}, "
|
|
789
|
+
f"key-range: {table1.min_key}..{table2.max_key}, "
|
|
790
|
+
f"size <= {max_rows}"
|
|
791
|
+
)
|
|
792
|
+
|
|
793
|
+
# Check all stop conditions
|
|
794
|
+
if not self._check_continuation_conditions(table1, info_tree, level):
|
|
795
|
+
return
|
|
796
|
+
|
|
797
|
+
# IN-MEMORY MODE: Skip checksum if flag is set or segment is small enough
|
|
798
|
+
if self._should_skip_checksum_and_download(max_rows):
|
|
799
|
+
if self.in_memory_diff:
|
|
800
|
+
logger.info(". " * level + f"[IN-MEMORY MODE] Downloading segment directly " f"(size: {max_rows} rows)")
|
|
801
|
+
|
|
802
|
+
return self._download_and_diff_locally(table1, table2, info_tree, level)
|
|
803
|
+
|
|
804
|
+
# STANDARD MODE: Perform checksum-based comparison
|
|
805
|
+
return self._checksum_and_bisect_if_needed(
|
|
806
|
+
ti, table1, table2, info_tree, level, max_rows, segment_index, segment_count
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
def _check_continuation_conditions(self, table1: TableSegment, info_tree: InfoTree, level: int) -> bool:
|
|
810
|
+
"""Check if we should continue diffing (respects limits)."""
|
|
811
|
+
|
|
812
|
+
# Check per-column diff limit
|
|
813
|
+
elapsed = time.monotonic() - self.start_time
|
|
814
|
+
if (
|
|
815
|
+
len(self._diff_tracker.get_stopped_columns()) > 0
|
|
816
|
+
and not self.stats.get("rows_downloaded", 0) >= self.egress_limit
|
|
817
|
+
and not elapsed > self.timeout_limit * 60
|
|
818
|
+
):
|
|
819
|
+
self.update_comparison_tracker(
|
|
820
|
+
reason_type="per_column_diff_limit",
|
|
821
|
+
segment=f"{table1.min_key}..{table1.max_key}",
|
|
822
|
+
)
|
|
823
|
+
|
|
824
|
+
if not self._diff_tracker.has_active_targets(len(table1.relevant_columns)):
|
|
825
|
+
logger.info(
|
|
826
|
+
"Diffing stopped because columns with potential differences "
|
|
827
|
+
"have reached their configured diff limits."
|
|
828
|
+
)
|
|
829
|
+
info_tree.info.is_diff = False
|
|
830
|
+
self.update_comparison_tracker(
|
|
831
|
+
reason_type="per_column_diff_limit",
|
|
832
|
+
segment=f"{table1.min_key}..{table1.max_key}",
|
|
833
|
+
)
|
|
834
|
+
return False
|
|
835
|
+
|
|
836
|
+
# Check egress limit
|
|
837
|
+
if self.stats.get("rows_downloaded", 0) >= self.egress_limit:
|
|
838
|
+
info_tree.info.is_diff = False
|
|
839
|
+
logger.info(
|
|
840
|
+
". " * level + f"Row download limit reached "
|
|
841
|
+
f"{self.stats.get('rows_downloaded')}, stopping bisection for "
|
|
842
|
+
f"segment {table1.min_key}..{table1.max_key}"
|
|
843
|
+
)
|
|
844
|
+
self.update_comparison_tracker(
|
|
845
|
+
reason_type="egress_limit",
|
|
846
|
+
segment=f"{table1.min_key}..{table1.max_key}",
|
|
847
|
+
)
|
|
848
|
+
return False
|
|
849
|
+
|
|
850
|
+
# Check timeout
|
|
851
|
+
elapsed = time.monotonic() - self.start_time
|
|
852
|
+
if elapsed > self.timeout_limit * 60:
|
|
853
|
+
info_tree.info.is_diff = False
|
|
854
|
+
logger.info(
|
|
855
|
+
". " * level + f"Timeout limit reached ({self.timeout_limit} min); "
|
|
856
|
+
f"stopping bisection for segment {table1.min_key}..{table1.max_key}"
|
|
857
|
+
)
|
|
858
|
+
self.update_comparison_tracker(
|
|
859
|
+
reason_type="timeout",
|
|
860
|
+
segment=f"{table1.min_key}..{table1.max_key}",
|
|
861
|
+
)
|
|
862
|
+
return False
|
|
863
|
+
|
|
864
|
+
return True
|
|
865
|
+
|
|
866
|
+
def _download_and_diff_locally(
|
|
867
|
+
self,
|
|
868
|
+
table1: TableSegment,
|
|
869
|
+
table2: TableSegment,
|
|
870
|
+
info_tree: InfoTree,
|
|
871
|
+
level: int,
|
|
872
|
+
) -> List:
|
|
873
|
+
"""Download segment rows and perform in-memory diff."""
|
|
874
|
+
|
|
875
|
+
mode_label = "[IN-MEMORY]" if self.in_memory_diff else "[STANDARD]"
|
|
876
|
+
logger.info(
|
|
877
|
+
". " * level + f"{mode_label} Downloading rows for comparison: " f"{table1.min_key}..{table1.max_key}"
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
# Download rows from both tables
|
|
881
|
+
rows1, rows2 = self._threaded_call("get_values", [table1, table2])
|
|
882
|
+
|
|
883
|
+
# Update statistics
|
|
884
|
+
downloaded = max(len(rows1), len(rows2))
|
|
885
|
+
self.stats["rows_downloaded"] = self.stats.get("rows_downloaded", 0) + downloaded
|
|
886
|
+
|
|
887
|
+
logger.info(
|
|
888
|
+
". " * level + f"{mode_label} Downloaded {len(rows1)} and {len(rows2)} rows. "
|
|
889
|
+
f"Total downloaded: {self.stats['rows_downloaded']}"
|
|
890
|
+
)
|
|
891
|
+
|
|
892
|
+
# Perform in-memory diff
|
|
893
|
+
json_cols = {
|
|
894
|
+
i: colname for i, colname in enumerate(table1.extra_columns) if isinstance(table1._schema[colname], JSON)
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
diff = list(
|
|
898
|
+
diff_sets(
|
|
899
|
+
rows1,
|
|
900
|
+
rows2,
|
|
901
|
+
json_cols=json_cols,
|
|
902
|
+
columns1=table1.relevant_columns,
|
|
903
|
+
columns2=table2.relevant_columns,
|
|
904
|
+
key_columns1=table1.key_columns,
|
|
905
|
+
key_columns2=table2.key_columns,
|
|
906
|
+
ignored_columns1=self.ignored_columns1,
|
|
907
|
+
ignored_columns2=self.ignored_columns2,
|
|
908
|
+
diff_tracker=self._diff_tracker,
|
|
909
|
+
)
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
# Update info tree
|
|
913
|
+
info_tree.info.set_diff(diff)
|
|
914
|
+
info_tree.info.rowcounts = {1: len(rows1), 2: len(rows2)}
|
|
915
|
+
|
|
916
|
+
logger.info(". " * level + f"{mode_label} Found {len(diff)} different rows in this segment")
|
|
917
|
+
|
|
918
|
+
return diff
|
|
919
|
+
|
|
920
|
+
def _checksum_and_bisect_if_needed(
|
|
921
|
+
self,
|
|
922
|
+
ti,
|
|
923
|
+
table1: TableSegment,
|
|
924
|
+
table2: TableSegment,
|
|
925
|
+
info_tree: InfoTree,
|
|
926
|
+
level: int,
|
|
927
|
+
max_rows: int,
|
|
928
|
+
segment_index: Optional[int],
|
|
929
|
+
segment_count: Optional[int],
|
|
930
|
+
):
|
|
931
|
+
"""Perform checksum comparison and bisect if differences found (standard mode)."""
|
|
932
|
+
|
|
933
|
+
logger.info(". " * level + "[CHECKSUM MODE] Comparing segment checksums")
|
|
934
|
+
|
|
935
|
+
# Get active columns for checksum (excluding stopped columns)
|
|
936
|
+
active_cols1, active_cols2 = self._get_checksum_columns(table1, table2)
|
|
937
|
+
|
|
938
|
+
# Create segments with updated columns for checksum
|
|
939
|
+
checksum_table1 = self._create_segment_with_updated_columns(table1, active_cols1)
|
|
940
|
+
checksum_table2 = self._create_segment_with_updated_columns(table2, active_cols2)
|
|
941
|
+
|
|
942
|
+
# Perform checksum
|
|
943
|
+
(count1, checksum1), (count2, checksum2) = self._threaded_call(
|
|
944
|
+
"count_and_checksum", [checksum_table1, checksum_table2]
|
|
945
|
+
)
|
|
946
|
+
|
|
947
|
+
assert not info_tree.info.rowcounts
|
|
948
|
+
info_tree.info.rowcounts = {1: count1, 2: count2}
|
|
949
|
+
|
|
950
|
+
# Handle empty segments
|
|
951
|
+
if count1 == 0 and count2 == 0:
|
|
952
|
+
logger.debug(
|
|
953
|
+
"Uneven distribution of keys detected in segment {}..{} "
|
|
954
|
+
"(big gaps in the key column). For better performance, "
|
|
955
|
+
"we recommend to increase the bisection-threshold.",
|
|
956
|
+
table1.min_key,
|
|
957
|
+
table1.max_key,
|
|
958
|
+
)
|
|
959
|
+
assert checksum1 is None and checksum2 is None
|
|
960
|
+
info_tree.info.is_diff = False
|
|
961
|
+
return
|
|
962
|
+
|
|
963
|
+
# Compare checksums
|
|
964
|
+
if checksum1 == checksum2:
|
|
965
|
+
logger.info(". " * level + "[CHECKSUM MODE] Checksums match - no differences")
|
|
966
|
+
info_tree.info.is_diff = False
|
|
967
|
+
return
|
|
968
|
+
|
|
969
|
+
logger.info(". " * level + "[CHECKSUM MODE] Checksums differ - bisecting segment")
|
|
970
|
+
info_tree.info.is_diff = True
|
|
971
|
+
|
|
972
|
+
# Bisect and continue
|
|
973
|
+
return self._bisect_and_diff_segments(ti, table1, table2, info_tree, level=level, max_rows=max(count1, count2))
|
|
974
|
+
|
|
975
|
+
def _bisect_and_diff_segments(
|
|
976
|
+
self,
|
|
977
|
+
ti,
|
|
978
|
+
table1: TableSegment,
|
|
979
|
+
table2: TableSegment,
|
|
980
|
+
info_tree: InfoTree,
|
|
981
|
+
level=0,
|
|
982
|
+
max_rows=None,
|
|
983
|
+
):
|
|
984
|
+
"""
|
|
985
|
+
Enhanced bisection with in-memory mode support.
|
|
986
|
+
"""
|
|
987
|
+
# Check recursion limit
|
|
988
|
+
if level > 15:
|
|
989
|
+
logger.warning(
|
|
990
|
+
". " * level + f"Maximum recursion level ({level}) reached; "
|
|
991
|
+
f"downloading segment {table1.min_key}..{table1.max_key}"
|
|
992
|
+
)
|
|
993
|
+
return self._download_and_diff_locally(table1, table2, info_tree, level)
|
|
994
|
+
|
|
995
|
+
assert table1.is_bounded and table2.is_bounded
|
|
996
|
+
|
|
997
|
+
# Initialize diff tracker
|
|
998
|
+
self._initialize_diff_tracker(table1, table2)
|
|
999
|
+
|
|
1000
|
+
# Check continuation conditions
|
|
1001
|
+
if not self._check_continuation_conditions(table1, info_tree, level):
|
|
1002
|
+
return
|
|
1003
|
+
|
|
1004
|
+
# Calculate max space size
|
|
1005
|
+
max_space_size = max(table1.approximate_size(self.t1_row_count), table2.approximate_size(self.t2_row_count))
|
|
1006
|
+
|
|
1007
|
+
if max_rows is None:
|
|
1008
|
+
max_rows = max_space_size
|
|
1009
|
+
|
|
1010
|
+
info_tree.info.max_rows = max_rows
|
|
1011
|
+
|
|
1012
|
+
# Check if we should download directly
|
|
1013
|
+
should_download = (
|
|
1014
|
+
self.bisection_disabled or max_rows < self.bisection_threshold or max_space_size < self.bisection_factor * 2
|
|
1015
|
+
)
|
|
1016
|
+
|
|
1017
|
+
# In-memory mode: also download if at target segment size
|
|
1018
|
+
if self.in_memory_diff and max_rows <= self.memory_segment_size:
|
|
1019
|
+
should_download = True
|
|
1020
|
+
|
|
1021
|
+
if should_download:
|
|
1022
|
+
return self._download_and_diff_locally(table1, table2, info_tree, level)
|
|
1023
|
+
|
|
1024
|
+
# Otherwise, continue with standard bisection
|
|
1025
|
+
return super()._bisect_and_diff_segments(ti, table1, table2, info_tree, level, max_rows)
|
dcs_sdk/__version__.py
CHANGED
|
@@ -81,6 +81,7 @@ class DiffAdvancedConfig(BaseModel):
|
|
|
81
81
|
egress_limit: int = 5_00_000
|
|
82
82
|
per_column_diff_limit: int = 100
|
|
83
83
|
timeout_limit: int = 60 * 5 # minutes
|
|
84
|
+
in_memory_diff: bool = False # Whether to perform diff in memory (may use more RAM)
|
|
84
85
|
|
|
85
86
|
|
|
86
87
|
class Comparison(BaseModel):
|
|
@@ -424,6 +425,7 @@ class DataDiffConfig:
|
|
|
424
425
|
egress_limit=advanced_diff_config.get("egress_limit", 5_00_000),
|
|
425
426
|
per_column_diff_limit=advanced_diff_config.get("per_column_diff_limit", 100),
|
|
426
427
|
timeout_limit=advanced_diff_config.get("timeout_limit", 60 * 5),
|
|
428
|
+
in_memory_diff=advanced_diff_config.get("in_memory_diff", False),
|
|
427
429
|
)
|
|
428
430
|
new_comparison = {
|
|
429
431
|
"comparison_name": comparison_name,
|
|
@@ -399,6 +399,8 @@ class DBTableDiffer:
|
|
|
399
399
|
table_1_sample_data = self.table1.with_schema().get_sample_data(limit=100)
|
|
400
400
|
sample_keys = [list(row[:pks_len]) for row in table_1_sample_data]
|
|
401
401
|
table_2_sample_data = self.table2.with_schema().get_sample_data(limit=100, sample_keys=sample_keys)
|
|
402
|
+
if self.config.advanced_configuration.in_memory_diff:
|
|
403
|
+
self.config.advanced_configuration.egress_limit = min(max_row_count, 50_00_000)
|
|
402
404
|
self.diff_iter = diff_tables(
|
|
403
405
|
self.table1,
|
|
404
406
|
self.table2,
|
|
@@ -410,6 +412,7 @@ class DBTableDiffer:
|
|
|
410
412
|
per_column_diff_limit=self.config.advanced_configuration.per_column_diff_limit,
|
|
411
413
|
egress_limit=self.config.advanced_configuration.egress_limit,
|
|
412
414
|
timeout_limit=self.config.advanced_configuration.timeout_limit,
|
|
415
|
+
in_memory_diff=self.config.advanced_configuration.in_memory_diff,
|
|
413
416
|
)
|
|
414
417
|
|
|
415
418
|
columns_mappings = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dcs-sdk
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.9
|
|
4
4
|
Summary: SDK for DataChecks
|
|
5
5
|
Author: Waterdip Labs
|
|
6
6
|
Author-email: hello@waterdip.ai
|
|
@@ -61,7 +61,7 @@ Requires-Dist: vertica-python (>=1.4.0) ; extra == "vertica" or extra == "all-db
|
|
|
61
61
|
Description-Content-Type: text/markdown
|
|
62
62
|
|
|
63
63
|
<h1 align="center">
|
|
64
|
-
DCS SDK v1.5.
|
|
64
|
+
DCS SDK v1.5.9
|
|
65
65
|
</h1>
|
|
66
66
|
|
|
67
67
|
> SDK for DataChecks
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
data_diff/__init__.py,sha256=
|
|
1
|
+
data_diff/__init__.py,sha256=QrrQt6GxG5gzVRlvFjJmfOzhR14fqKLrQs186KBWryY,10413
|
|
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
|
|
@@ -14,17 +14,17 @@ data_diff/databases/duckdb.py,sha256=7r1PwPUpp61QN_ZorsBTyn6NTB1LcBKQofYl_wovm1U
|
|
|
14
14
|
data_diff/databases/mssql.py,sha256=mA6myRemhad-q9yyRSt6VRj6na_i4joD0HI7IgGt8zQ,11987
|
|
15
15
|
data_diff/databases/mysql.py,sha256=LTuLTkxac16y7w5_q1nEuKy6ZefqQUBQqV_tdnzjNT4,6148
|
|
16
16
|
data_diff/databases/oracle.py,sha256=GIczARg96lOlmgUpHd-hOFl8etFJmxWMy-KkA2COG74,8031
|
|
17
|
-
data_diff/databases/postgresql.py,sha256=
|
|
17
|
+
data_diff/databases/postgresql.py,sha256=E8VtuHDGlULegb42KXzls0agEhEAJ2O9h-Mwr5ViHZU,10938
|
|
18
18
|
data_diff/databases/presto.py,sha256=1Z8iDV2pc35Bu7DuUerFuFLbrwgSHSkBYmJ72JlZSZ8,7116
|
|
19
19
|
data_diff/databases/redshift.py,sha256=-gFWs3NCcevO4s6c4zV3_LYihK24fUd5BADTKahubjw,8122
|
|
20
20
|
data_diff/databases/snowflake.py,sha256=7G6fvVJXOtTvXmSfWCxTslF4WohoscQoiqcmJIN684A,7910
|
|
21
|
-
data_diff/databases/sybase.py,sha256=
|
|
21
|
+
data_diff/databases/sybase.py,sha256=DIai691f1PrPORWb9EjdoQWFMLEKtXFoHQ9vJvEHnPU,31312
|
|
22
22
|
data_diff/databases/trino.py,sha256=VIN3gMJvT4oSYuXCJ1QnngVL2gjjEYMFw87QTHgjs8c,2328
|
|
23
23
|
data_diff/databases/vertica.py,sha256=2dSDZp6qOEvUVPldI5Tgn7Sm3dCpC3vNXJL3qb3FDvQ,5529
|
|
24
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=
|
|
27
|
+
data_diff/hashdiff_tables.py,sha256=oElu0rFAFaRGVZpiIl546yUVYQm02J6HFjVkpuHHFIQ,43134
|
|
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
|
|
@@ -43,14 +43,14 @@ data_diff/utils.py,sha256=ZSgK6utdYDWvnsYgl7sJQa6J3XK3T6xSB_BGdQVeK24,33457
|
|
|
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=
|
|
46
|
+
dcs_sdk/__version__.py,sha256=Syic9kjTewAbYYhDKKRgMcp-NZeosWsa7uGfE_JlLHs,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
|
|
50
50
|
dcs_sdk/sdk/config/__init__.py,sha256=RkfhRKLXEForLCs4rZkTf0qc_b0TokSggSAcKI4yfZg,610
|
|
51
|
-
dcs_sdk/sdk/config/config_loader.py,sha256=
|
|
51
|
+
dcs_sdk/sdk/config/config_loader.py,sha256=hVdGidcm6ibqJ0yt7fZcL_0kFcorBfM7vHGhUiBH9Ww,21587
|
|
52
52
|
dcs_sdk/sdk/data_diff/__init__.py,sha256=RkfhRKLXEForLCs4rZkTf0qc_b0TokSggSAcKI4yfZg,610
|
|
53
|
-
dcs_sdk/sdk/data_diff/data_differ.py,sha256=
|
|
53
|
+
dcs_sdk/sdk/data_diff/data_differ.py,sha256=d8hwXs0zG5AuaRjsNlpFShpTxA1_YPgH2aCRsJQfDMU,35846
|
|
54
54
|
dcs_sdk/sdk/rules/__init__.py,sha256=_BkKcE_jfdDQI_ECdOamJaefMKEXrKpYjPpnBQXl_Xs,657
|
|
55
55
|
dcs_sdk/sdk/rules/rules_mappping.py,sha256=fxakVkf7B2cVkYSO946LTim_HmMsl6lBDBqZjTTsSPI,1292
|
|
56
56
|
dcs_sdk/sdk/rules/rules_repository.py,sha256=x0Rli-wdnHAmXm5526go_qC3P-eFRt-4L7fs4hNqC-g,7564
|
|
@@ -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.
|
|
69
|
-
dcs_sdk-1.5.
|
|
70
|
-
dcs_sdk-1.5.
|
|
71
|
-
dcs_sdk-1.5.
|
|
68
|
+
dcs_sdk-1.5.9.dist-info/METADATA,sha256=sKgAYCQgujtdlWQZNWJnlY2XSKvti7YdAyrOAIOaH6o,6275
|
|
69
|
+
dcs_sdk-1.5.9.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
70
|
+
dcs_sdk-1.5.9.dist-info/entry_points.txt,sha256=zQtrZL7YuaKtt6WPwihCTV1BRXnqBkaY6zUGdYJbBSg,49
|
|
71
|
+
dcs_sdk-1.5.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|