google-pso-data-validator 7.2.0__tar.gz → 7.4.0__tar.gz
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.
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/PKG-INFO +3 -1
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/README.md +2 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/__main__.py +8 -6
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/cli_tools.py +17 -7
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/combiner.py +135 -48
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/config_manager.py +19 -11
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/consts.py +33 -15
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/data_validation.py +6 -3
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/partition_builder.py +6 -4
- google_pso_data_validator-7.4.0/data_validation/raw_query.py +74 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/result_handlers/bigquery.py +4 -4
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/result_handlers/text.py +6 -4
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/secret_manager.py +6 -2
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/util.py +18 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/PKG-INFO +3 -1
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/setup.py +1 -1
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/__init__.py +16 -1
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/registry.py +8 -2
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_snowflake/api.py +4 -1
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/__init__.py +3 -10
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/api.py +5 -0
- google_pso_data_validator-7.2.0/data_validation/raw_query.py +0 -47
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/LICENSE +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/app.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/client_info.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/clients.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/exceptions.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/find_tables.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/gcs_helper.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/jellyfish_distance.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/metadata.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/partition_row_builder.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/query_builder.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/random_row_builder.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/result_handlers/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/schema_validation.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/state_manager.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/validation_builder.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/SOURCES.txt +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/requires.txt +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/setup.cfg +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_addon/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_addon/operations.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_biquery/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_biquery/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/compiler.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/datatypes.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/registry.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_impala/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_impala/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/registry.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mysql/base_sql_compiler/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mysql/base_sql_compiler/select_builder.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/datatypes.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/registry.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/client.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/datatypes.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_redshift/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_redshift/api.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_snowflake/__init__.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/datatypes.py +0 -0
- {google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/registry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: google-pso-data-validator
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.4.0
|
|
4
4
|
Summary: A package to enable easy data validation
|
|
5
5
|
Author: PSO DVT Engineering team
|
|
6
6
|
Author-email: data-validator-eng@google.com
|
|
@@ -651,6 +651,8 @@ data-validation query
|
|
|
651
651
|
The connection name to be queried
|
|
652
652
|
--query or -q QUERY
|
|
653
653
|
The raw query to run against the supplied connection
|
|
654
|
+
[--format or -f {minimal,python}]
|
|
655
|
+
Format for query output (default: python)
|
|
654
656
|
```
|
|
655
657
|
|
|
656
658
|
### Building Matched Table Lists
|
|
@@ -593,6 +593,8 @@ data-validation query
|
|
|
593
593
|
The connection name to be queried
|
|
594
594
|
--query or -q QUERY
|
|
595
595
|
The raw query to run against the supplied connection
|
|
596
|
+
[--format or -f {minimal,python}]
|
|
597
|
+
Format for query output (default: python)
|
|
596
598
|
```
|
|
597
599
|
|
|
598
600
|
### Building Matched Table Lists
|
{google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/__main__.py
RENAMED
|
@@ -16,9 +16,9 @@ import json
|
|
|
16
16
|
import logging
|
|
17
17
|
import os
|
|
18
18
|
import sys
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
19
20
|
|
|
20
21
|
from yaml import Dumper, dump
|
|
21
|
-
from argparse import Namespace
|
|
22
22
|
from typing import List
|
|
23
23
|
from data_validation import (
|
|
24
24
|
cli_tools,
|
|
@@ -34,6 +34,9 @@ from data_validation.data_validation import DataValidation
|
|
|
34
34
|
from data_validation.find_tables import find_tables_using_string_matching
|
|
35
35
|
from data_validation.partition_builder import PartitionBuilder
|
|
36
36
|
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from argparse import Namespace
|
|
39
|
+
|
|
37
40
|
# by default yaml dumps lists as pointers. This disables that feature
|
|
38
41
|
Dumper.ignore_aliases = lambda *args: True
|
|
39
42
|
|
|
@@ -246,7 +249,7 @@ def _get_comparison_config(
|
|
|
246
249
|
return config_manager.build_config_comparison_fields(comparison_fields)
|
|
247
250
|
|
|
248
251
|
|
|
249
|
-
def build_config_from_args(args: Namespace, config_manager: ConfigManager):
|
|
252
|
+
def build_config_from_args(args: "Namespace", config_manager: ConfigManager):
|
|
250
253
|
"""This function is used to append build configs to the config manager for all validation commands and generate-table-partitions.
|
|
251
254
|
Instead of having two separate commands, e.g. validate row and validate custom-query row, generate-table-partitions
|
|
252
255
|
uses implicit choice of table or custom-query. A user can specify either tables or source/target query/file,
|
|
@@ -337,7 +340,7 @@ def build_config_from_args(args: Namespace, config_manager: ConfigManager):
|
|
|
337
340
|
|
|
338
341
|
|
|
339
342
|
def build_config_managers_from_args(
|
|
340
|
-
args: Namespace, validate_cmd: str = None
|
|
343
|
+
args: "Namespace", validate_cmd: str = None
|
|
341
344
|
) -> List[ConfigManager]:
|
|
342
345
|
"""Return a list of config managers ready to execute."""
|
|
343
346
|
|
|
@@ -570,7 +573,6 @@ def run_validations(args, config_managers):
|
|
|
570
573
|
Args:
|
|
571
574
|
config_managers (list[ConfigManager]): List of config manager instances.
|
|
572
575
|
"""
|
|
573
|
-
# TODO(issue/31): Add parallel execution logic
|
|
574
576
|
for config_manager in config_managers:
|
|
575
577
|
run_validation(config_manager, dry_run=args.dry_run, verbose=args.verbose)
|
|
576
578
|
|
|
@@ -597,7 +599,7 @@ def store_json_config_file(args, config_managers):
|
|
|
597
599
|
cli_tools.store_validation(config_file_path, json_config)
|
|
598
600
|
|
|
599
601
|
|
|
600
|
-
def partition_and_store_config_files(args: Namespace) -> None:
|
|
602
|
+
def partition_and_store_config_files(args: "Namespace") -> None:
|
|
601
603
|
"""Build multiple YAML Config files using user specified partition logic
|
|
602
604
|
|
|
603
605
|
Args:
|
|
@@ -692,7 +694,7 @@ def main():
|
|
|
692
694
|
print(find_tables_using_string_matching(args))
|
|
693
695
|
elif args.command == "query":
|
|
694
696
|
raw_query.print_raw_query_output(
|
|
695
|
-
raw_query.run_raw_query_against_connection(args)
|
|
697
|
+
raw_query.run_raw_query_against_connection(args), format=args.output_format
|
|
696
698
|
)
|
|
697
699
|
elif args.command == "validate":
|
|
698
700
|
validate(args)
|
{google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/cli_tools.py
RENAMED
|
@@ -52,8 +52,7 @@ import sys
|
|
|
52
52
|
import uuid
|
|
53
53
|
import os
|
|
54
54
|
import math
|
|
55
|
-
from
|
|
56
|
-
from typing import Dict, List, Optional
|
|
55
|
+
from typing import Dict, List, Optional, TYPE_CHECKING
|
|
57
56
|
from yaml import Dumper, Loader, dump, load
|
|
58
57
|
|
|
59
58
|
from data_validation import (
|
|
@@ -66,6 +65,9 @@ from data_validation import (
|
|
|
66
65
|
)
|
|
67
66
|
from data_validation.validation_builder import list_to_sublists
|
|
68
67
|
|
|
68
|
+
if TYPE_CHECKING:
|
|
69
|
+
from argparse import Namespace
|
|
70
|
+
|
|
69
71
|
|
|
70
72
|
CONNECTION_SOURCE_FIELDS = {
|
|
71
73
|
"BigQuery": [
|
|
@@ -191,7 +193,7 @@ VALIDATE_SCHEMA_HELP_TEXT = "Run a schema validation"
|
|
|
191
193
|
VALIDATE_CUSTOM_QUERY_HELP_TEXT = "Run a custom query validation"
|
|
192
194
|
|
|
193
195
|
|
|
194
|
-
def _check_custom_query_args(parser: argparse.ArgumentParser, parsed_args: Namespace):
|
|
196
|
+
def _check_custom_query_args(parser: argparse.ArgumentParser, parsed_args: "Namespace"):
|
|
195
197
|
# This is where we make additional checks if the arguments provided are what we expect
|
|
196
198
|
# For example, only one of -tbls and custom query options can be provided
|
|
197
199
|
if hasattr(parsed_args, "tables_list") and hasattr(
|
|
@@ -223,7 +225,7 @@ def _check_custom_query_args(parser: argparse.ArgumentParser, parsed_args: Names
|
|
|
223
225
|
return # old format - only one of them is present
|
|
224
226
|
|
|
225
227
|
|
|
226
|
-
def get_parsed_args() -> Namespace:
|
|
228
|
+
def get_parsed_args() -> "Namespace":
|
|
227
229
|
"""Return ArgParser with configured CLI arguments."""
|
|
228
230
|
parser = configure_arg_parser()
|
|
229
231
|
args = ["--help"] if len(sys.argv) == 1 else None
|
|
@@ -393,6 +395,14 @@ def _configure_raw_query(subparsers):
|
|
|
393
395
|
)
|
|
394
396
|
query_parser.add_argument("--conn", "-c", help="Connection name to query")
|
|
395
397
|
query_parser.add_argument("--query", "-q", help="Raw query to execute")
|
|
398
|
+
query_parser.add_argument(
|
|
399
|
+
"--format",
|
|
400
|
+
"-f",
|
|
401
|
+
dest="output_format",
|
|
402
|
+
choices=consts.RAW_QUERY_FORMAT_TYPES,
|
|
403
|
+
default=consts.FORMAT_TYPE_PYTHON,
|
|
404
|
+
help=f"Format for query output (default: {consts.FORMAT_TYPE_PYTHON})",
|
|
405
|
+
)
|
|
396
406
|
|
|
397
407
|
|
|
398
408
|
def _configure_validation_config_parser(subparsers):
|
|
@@ -1027,7 +1037,7 @@ def _add_common_arguments(
|
|
|
1027
1037
|
optional_arguments.add_argument(
|
|
1028
1038
|
"--format",
|
|
1029
1039
|
"-fmt",
|
|
1030
|
-
default=
|
|
1040
|
+
default=consts.FORMAT_TYPE_TABLE,
|
|
1031
1041
|
help="Set the format for printing command output, Supported formats are (text, csv, json, table). Defaults "
|
|
1032
1042
|
"to table",
|
|
1033
1043
|
)
|
|
@@ -1443,7 +1453,7 @@ def _concat_column_count_configs(
|
|
|
1443
1453
|
return return_list
|
|
1444
1454
|
|
|
1445
1455
|
|
|
1446
|
-
def get_pre_build_configs(args: Namespace, validate_cmd: str) -> List[Dict]:
|
|
1456
|
+
def get_pre_build_configs(args: "Namespace", validate_cmd: str) -> List[Dict]:
|
|
1447
1457
|
"""Return a dict of configurations to build ConfigManager object"""
|
|
1448
1458
|
|
|
1449
1459
|
def cols_from_arg(concat_arg: str, client, table_obj: dict, query_str: str) -> list:
|
|
@@ -1503,7 +1513,7 @@ def get_pre_build_configs(args: Namespace, validate_cmd: str) -> List[Dict]:
|
|
|
1503
1513
|
target_client = clients.get_data_client(mgr.get_connection_config(args.target_conn))
|
|
1504
1514
|
|
|
1505
1515
|
# Get format: text, csv, json, table. Default is table
|
|
1506
|
-
format = args.format if args.format else
|
|
1516
|
+
format = args.format if args.format else consts.FORMAT_TYPE_TABLE
|
|
1507
1517
|
|
|
1508
1518
|
# Get random row arguments. Only in row validations these attributes can be present.
|
|
1509
1519
|
# Bad coding here, but keeping it so as not to introduce a breaking change. See
|
{google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/combiner.py
RENAMED
|
@@ -25,17 +25,20 @@ import logging
|
|
|
25
25
|
import ibis
|
|
26
26
|
import ibis.expr.datatypes as dt
|
|
27
27
|
|
|
28
|
+
from typing import TYPE_CHECKING
|
|
28
29
|
from data_validation import consts
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from pandas import DataFrame
|
|
33
|
+
import ibis.expr.types.relations.table as IbisTable
|
|
34
|
+
from data_validation.metadata import RunMetadata, ValidationMetadata
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
def generate_report(
|
|
35
38
|
client,
|
|
36
|
-
run_metadata,
|
|
37
|
-
source,
|
|
38
|
-
target,
|
|
39
|
+
run_metadata: "RunMetadata",
|
|
40
|
+
source: "IbisTable",
|
|
41
|
+
target: "IbisTable",
|
|
39
42
|
join_on_fields=(),
|
|
40
43
|
is_value_comparison=False,
|
|
41
44
|
verbose=False,
|
|
@@ -44,8 +47,7 @@ def generate_report(
|
|
|
44
47
|
|
|
45
48
|
Args:
|
|
46
49
|
client (ibis.client.Client): Ibis client used to combine results.
|
|
47
|
-
run_metadata
|
|
48
|
-
Metadata about the run and validations.
|
|
50
|
+
run_metadata: Metadata about the run and validations.
|
|
49
51
|
source (ibis.QUERY): Ibis query / table object.
|
|
50
52
|
target (ibis.QUERY): Ibis query / table object.
|
|
51
53
|
join_on_fields (Sequence[str]):
|
|
@@ -69,7 +71,7 @@ def generate_report(
|
|
|
69
71
|
if source_names != target_names:
|
|
70
72
|
raise ValueError(
|
|
71
73
|
"Expected source and target to have same schema, got "
|
|
72
|
-
f"
|
|
74
|
+
f"{consts.RESULT_TYPE_SOURCE}: {source_names}; {consts.RESULT_TYPE_TARGET}: {target_names}"
|
|
73
75
|
)
|
|
74
76
|
differences_pivot = _calculate_differences(
|
|
75
77
|
source, target, join_on_fields, run_metadata.validations, is_value_comparison
|
|
@@ -87,13 +89,17 @@ def generate_report(
|
|
|
87
89
|
target_df = client.execute(target_pivot)
|
|
88
90
|
|
|
89
91
|
con = ibis.pandas.connect(
|
|
90
|
-
{
|
|
92
|
+
{
|
|
93
|
+
consts.RESULT_TYPE_SOURCE: source_df,
|
|
94
|
+
"differences": differences_df,
|
|
95
|
+
consts.RESULT_TYPE_TARGET: target_df,
|
|
96
|
+
}
|
|
91
97
|
)
|
|
92
98
|
joined = _join_pivots(
|
|
93
99
|
con.tables.source, con.tables.target, con.tables.differences, join_on_fields
|
|
94
100
|
)
|
|
95
101
|
|
|
96
|
-
documented = _add_metadata(joined, run_metadata)
|
|
102
|
+
documented, run_metadata = _add_metadata(joined, run_metadata)
|
|
97
103
|
|
|
98
104
|
if verbose:
|
|
99
105
|
logging.debug("-- ** Combiner Query ** --")
|
|
@@ -112,15 +118,17 @@ def generate_report(
|
|
|
112
118
|
first.get_table_name(consts.RESULT_TYPE_TARGET), inplace=True
|
|
113
119
|
)
|
|
114
120
|
|
|
121
|
+
_get_summary(run_metadata, result_df, source_df, target_df)
|
|
122
|
+
|
|
115
123
|
return result_df
|
|
116
124
|
|
|
117
125
|
|
|
118
126
|
def _calculate_difference(
|
|
119
|
-
field_differences,
|
|
127
|
+
field_differences: "IbisTable",
|
|
120
128
|
datatype: dt.DataType,
|
|
121
129
|
target_type: dt.DataType,
|
|
122
|
-
validation,
|
|
123
|
-
is_value_comparison,
|
|
130
|
+
validation: "ValidationMetadata",
|
|
131
|
+
is_value_comparison: bool,
|
|
124
132
|
):
|
|
125
133
|
pct_threshold = ibis.literal(validation.threshold)
|
|
126
134
|
if datatype.is_timestamp() or datatype.is_date():
|
|
@@ -210,12 +218,16 @@ def _calculate_difference(
|
|
|
210
218
|
difference.name("difference"),
|
|
211
219
|
pct_difference.name("pct_difference"),
|
|
212
220
|
pct_threshold.name("pct_threshold"),
|
|
213
|
-
validation_status.name(
|
|
221
|
+
validation_status.name(consts.VALIDATION_STATUS),
|
|
214
222
|
)
|
|
215
223
|
|
|
216
224
|
|
|
217
225
|
def _calculate_differences(
|
|
218
|
-
source
|
|
226
|
+
source: "IbisTable",
|
|
227
|
+
target: "IbisTable",
|
|
228
|
+
join_on_fields: tuple,
|
|
229
|
+
validations: "dict[ValidationMetadata]",
|
|
230
|
+
is_value_comparison: bool,
|
|
219
231
|
):
|
|
220
232
|
"""Calculate differences between source and target fields.
|
|
221
233
|
|
|
@@ -267,7 +279,12 @@ def _calculate_differences(
|
|
|
267
279
|
return differences_pivot
|
|
268
280
|
|
|
269
281
|
|
|
270
|
-
def _pivot_result(
|
|
282
|
+
def _pivot_result(
|
|
283
|
+
result: "IbisTable",
|
|
284
|
+
join_on_fields: tuple,
|
|
285
|
+
validations: "dict[ValidationMetadata]",
|
|
286
|
+
result_type: str,
|
|
287
|
+
):
|
|
271
288
|
all_fields = frozenset(result.schema().names)
|
|
272
289
|
validation_fields = (
|
|
273
290
|
all_fields - frozenset(join_on_fields)
|
|
@@ -285,19 +302,21 @@ def _pivot_result(result, join_on_fields, validations, result_type):
|
|
|
285
302
|
ibis.literal("{")
|
|
286
303
|
+ ibis.literal(", ").join(validation.primary_keys)
|
|
287
304
|
+ ibis.literal("}")
|
|
288
|
-
).name(
|
|
305
|
+
).name(consts.CONFIG_PRIMARY_KEYS)
|
|
289
306
|
else:
|
|
290
|
-
primary_keys =
|
|
307
|
+
primary_keys = (
|
|
308
|
+
ibis.literal(None).cast("string").name(consts.CONFIG_PRIMARY_KEYS)
|
|
309
|
+
)
|
|
291
310
|
|
|
292
311
|
pivots.append(
|
|
293
312
|
result.projection(
|
|
294
313
|
(
|
|
295
314
|
ibis.literal(field).name("validation_name"),
|
|
296
315
|
ibis.literal(validation.validation_type).name(
|
|
297
|
-
|
|
316
|
+
consts.VALIDATION_TYPE
|
|
298
317
|
),
|
|
299
318
|
ibis.literal(validation.aggregation_type).name(
|
|
300
|
-
|
|
319
|
+
consts.AGGREGATION_TYPE
|
|
301
320
|
),
|
|
302
321
|
ibis.literal(validation.get_table_name(result_type)).name(
|
|
303
322
|
"table_name"
|
|
@@ -333,7 +352,12 @@ def _as_json(expr):
|
|
|
333
352
|
)
|
|
334
353
|
|
|
335
354
|
|
|
336
|
-
def _join_pivots(
|
|
355
|
+
def _join_pivots(
|
|
356
|
+
source: "IbisTable",
|
|
357
|
+
target: "IbisTable",
|
|
358
|
+
differences: "IbisTable",
|
|
359
|
+
join_on_fields: tuple,
|
|
360
|
+
):
|
|
337
361
|
if join_on_fields:
|
|
338
362
|
join_values = []
|
|
339
363
|
for field in join_on_fields:
|
|
@@ -346,62 +370,125 @@ def _join_pivots(source, target, differences, join_on_fields):
|
|
|
346
370
|
|
|
347
371
|
group_by_columns = (
|
|
348
372
|
ibis.literal("{") + ibis.literal(", ").join(join_values) + ibis.literal("}")
|
|
349
|
-
).name(
|
|
373
|
+
).name(consts.GROUP_BY_COLUMNS)
|
|
350
374
|
else:
|
|
351
|
-
group_by_columns =
|
|
375
|
+
group_by_columns = (
|
|
376
|
+
ibis.literal(None).cast("string").name(consts.GROUP_BY_COLUMNS)
|
|
377
|
+
)
|
|
352
378
|
|
|
353
379
|
join_keys = ("validation_name",) + join_on_fields
|
|
354
380
|
source_difference = source.join(differences, join_keys, how="outer")[
|
|
355
381
|
[source[field] for field in join_keys]
|
|
356
382
|
+ [
|
|
357
|
-
source[
|
|
358
|
-
source[
|
|
359
|
-
source[
|
|
383
|
+
source[consts.VALIDATION_TYPE],
|
|
384
|
+
source[consts.AGGREGATION_TYPE],
|
|
385
|
+
source[consts.CONFIG_TABLE_NAME],
|
|
360
386
|
source["column_name"],
|
|
361
|
-
source[
|
|
387
|
+
source[consts.CONFIG_PRIMARY_KEYS],
|
|
362
388
|
source["num_random_rows"],
|
|
363
389
|
source["agg_value"],
|
|
364
390
|
differences["difference"],
|
|
365
391
|
differences["pct_difference"],
|
|
366
392
|
differences["pct_threshold"],
|
|
367
|
-
differences[
|
|
393
|
+
differences[consts.VALIDATION_STATUS],
|
|
368
394
|
]
|
|
369
395
|
]
|
|
370
396
|
joined = source_difference.join(target, join_keys, how="outer")[
|
|
371
397
|
source_difference["validation_name"],
|
|
372
|
-
source_difference[
|
|
373
|
-
.fillna(target[
|
|
374
|
-
.name(
|
|
375
|
-
source_difference[
|
|
376
|
-
.fillna(target[
|
|
377
|
-
.name(
|
|
378
|
-
source_difference["table_name"].name(
|
|
379
|
-
source_difference["column_name"].name(
|
|
380
|
-
source_difference["agg_value"].name(
|
|
381
|
-
target["table_name"].name(
|
|
382
|
-
target["column_name"].name(
|
|
383
|
-
target["agg_value"].name(
|
|
398
|
+
source_difference[consts.VALIDATION_TYPE]
|
|
399
|
+
.fillna(target[consts.VALIDATION_TYPE])
|
|
400
|
+
.name(consts.VALIDATION_TYPE),
|
|
401
|
+
source_difference[consts.AGGREGATION_TYPE]
|
|
402
|
+
.fillna(target[consts.AGGREGATION_TYPE])
|
|
403
|
+
.name(consts.AGGREGATION_TYPE),
|
|
404
|
+
source_difference["table_name"].name(consts.SOURCE_TABLE_NAME),
|
|
405
|
+
source_difference["column_name"].name(consts.SOURCE_COLUMN_NAME),
|
|
406
|
+
source_difference["agg_value"].name(consts.SOURCE_AGG_VALUE),
|
|
407
|
+
target["table_name"].name(consts.TARGET_TABLE_NAME),
|
|
408
|
+
target["column_name"].name(consts.TARGET_COLUMN_NAME),
|
|
409
|
+
target["agg_value"].name(consts.TARGET_AGG_VALUE),
|
|
384
410
|
group_by_columns,
|
|
385
|
-
source_difference[
|
|
411
|
+
source_difference[consts.CONFIG_PRIMARY_KEYS],
|
|
386
412
|
source_difference["num_random_rows"],
|
|
387
413
|
source_difference["difference"],
|
|
388
414
|
source_difference["pct_difference"],
|
|
389
415
|
source_difference["pct_threshold"],
|
|
390
|
-
source_difference[
|
|
416
|
+
source_difference[consts.VALIDATION_STATUS],
|
|
391
417
|
]
|
|
392
418
|
return joined
|
|
393
419
|
|
|
394
420
|
|
|
395
|
-
def _add_metadata(joined, run_metadata):
|
|
421
|
+
def _add_metadata(joined: "IbisTable", run_metadata: "RunMetadata"):
|
|
396
422
|
# TODO: Add source and target queries to metadata
|
|
397
423
|
run_metadata.end_time = datetime.datetime.now(datetime.timezone.utc)
|
|
398
424
|
|
|
399
425
|
joined = joined[
|
|
400
426
|
joined,
|
|
401
|
-
ibis.literal(run_metadata.run_id).name(
|
|
402
|
-
ibis.literal(run_metadata.labels).name(
|
|
403
|
-
ibis.literal(run_metadata.start_time).name(
|
|
404
|
-
ibis.literal(run_metadata.end_time).name(
|
|
427
|
+
ibis.literal(run_metadata.run_id).name(consts.CONFIG_RUN_ID),
|
|
428
|
+
ibis.literal(run_metadata.labels).name(consts.CONFIG_LABELS),
|
|
429
|
+
ibis.literal(run_metadata.start_time).name(consts.CONFIG_START_TIME),
|
|
430
|
+
ibis.literal(run_metadata.end_time).name(consts.CONFIG_END_TIME),
|
|
405
431
|
]
|
|
406
432
|
|
|
407
|
-
return joined
|
|
433
|
+
return (joined, run_metadata)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def _get_summary(
|
|
437
|
+
run_metadata: "RunMetadata",
|
|
438
|
+
result_df: "DataFrame",
|
|
439
|
+
source_df: "DataFrame",
|
|
440
|
+
target_df: "DataFrame",
|
|
441
|
+
):
|
|
442
|
+
"""Logs a summary report/stats of row validation results."""
|
|
443
|
+
try:
|
|
444
|
+
if result_df.loc[0, consts.VALIDATION_TYPE] == consts.ROW_VALIDATION:
|
|
445
|
+
# Vectorized calculations for all counts
|
|
446
|
+
success_condition = (
|
|
447
|
+
result_df[consts.VALIDATION_STATUS] == consts.VALIDATION_STATUS_SUCCESS
|
|
448
|
+
)
|
|
449
|
+
fail_condition = ~success_condition # Invert success for fail condition
|
|
450
|
+
|
|
451
|
+
source_not_in_target = (
|
|
452
|
+
result_df[consts.SOURCE_AGG_VALUE].notnull()
|
|
453
|
+
& result_df[consts.TARGET_AGG_VALUE].isnull()
|
|
454
|
+
)
|
|
455
|
+
target_not_in_source = (
|
|
456
|
+
result_df[consts.SOURCE_AGG_VALUE].isnull()
|
|
457
|
+
& result_df[consts.TARGET_AGG_VALUE].notnull()
|
|
458
|
+
)
|
|
459
|
+
present_in_both_tables = (
|
|
460
|
+
result_df[consts.SOURCE_AGG_VALUE].notnull()
|
|
461
|
+
& result_df[consts.TARGET_AGG_VALUE].notnull()
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
logging.info(
|
|
465
|
+
{
|
|
466
|
+
consts.CONFIG_RUN_ID: run_metadata.run_id,
|
|
467
|
+
consts.CONFIG_START_TIME: run_metadata.start_time.strftime(
|
|
468
|
+
"%Y-%m-%d %H:%M:%S %Z"
|
|
469
|
+
),
|
|
470
|
+
consts.CONFIG_END_TIME: run_metadata.end_time.strftime(
|
|
471
|
+
"%Y-%m-%d %H:%M:%S %Z"
|
|
472
|
+
),
|
|
473
|
+
consts.TOTAL_SOURCE_ROWS: source_df.shape[0],
|
|
474
|
+
consts.TOTAL_TARGET_ROWS: target_df.shape[0],
|
|
475
|
+
consts.TOTAL_ROWS_VALIDATED: result_df.shape[0],
|
|
476
|
+
# Using .sum() on boolean Series for much faster counting
|
|
477
|
+
consts.TOTAL_ROWS_SUCCESS: success_condition.sum(),
|
|
478
|
+
consts.TOTAL_ROWS_FAIL: fail_condition.sum(),
|
|
479
|
+
consts.FAILED_SOURCE_NOT_IN_TARGET: (
|
|
480
|
+
fail_condition & source_not_in_target
|
|
481
|
+
).sum(),
|
|
482
|
+
consts.FAILED_TARGET_NOT_IN_SOURCE: (
|
|
483
|
+
fail_condition & target_not_in_source
|
|
484
|
+
).sum(),
|
|
485
|
+
consts.FAILED_PRESENT_IN_BOTH_TABLES: (
|
|
486
|
+
fail_condition & present_in_both_tables
|
|
487
|
+
).sum(),
|
|
488
|
+
}
|
|
489
|
+
)
|
|
490
|
+
except Exception as e:
|
|
491
|
+
logging.warning(
|
|
492
|
+
f"Error while generating summary report of row validation results: {e}",
|
|
493
|
+
exc_info=True,
|
|
494
|
+
)
|
|
@@ -459,7 +459,7 @@ class ConfigManager(object):
|
|
|
459
459
|
cols_filter_list = consts.COLUMN_FILTER_LIST
|
|
460
460
|
# handler that display results either to output or in a file
|
|
461
461
|
return TextResultHandler(
|
|
462
|
-
self._config.get(consts.CONFIG_FORMAT,
|
|
462
|
+
self._config.get(consts.CONFIG_FORMAT, consts.FORMAT_TYPE_TABLE),
|
|
463
463
|
self.filter_status,
|
|
464
464
|
cols_filter_list,
|
|
465
465
|
)
|
|
@@ -486,7 +486,9 @@ class ConfigManager(object):
|
|
|
486
486
|
table_id=table_id,
|
|
487
487
|
credentials=credentials,
|
|
488
488
|
api_endpoint=api_endpoint,
|
|
489
|
-
text_format=self._config.get(
|
|
489
|
+
text_format=self._config.get(
|
|
490
|
+
consts.CONFIG_FORMAT, consts.FORMAT_TYPE_TABLE
|
|
491
|
+
),
|
|
490
492
|
)
|
|
491
493
|
else:
|
|
492
494
|
raise ValueError(f"Unknown ResultHandler Class: {result_type}")
|
|
@@ -874,7 +876,7 @@ class ConfigManager(object):
|
|
|
874
876
|
target_column_ibis_type: dt.DataType,
|
|
875
877
|
margin: int = 0,
|
|
876
878
|
) -> bool:
|
|
877
|
-
"""Identifies
|
|
879
|
+
"""Identifies numeric columns that will cause problems in a Pandas Dataframe.
|
|
878
880
|
|
|
879
881
|
i.e. are of greater precision than a 64bit int/real can hold.
|
|
880
882
|
|
|
@@ -883,17 +885,23 @@ class ConfigManager(object):
|
|
|
883
885
|
"""
|
|
884
886
|
return bool(
|
|
885
887
|
(
|
|
886
|
-
isinstance(source_column_ibis_type, dt.
|
|
887
|
-
|
|
888
|
-
source_column_ibis_type.
|
|
889
|
-
|
|
888
|
+
(isinstance(source_column_ibis_type, dt.Int64) and margin > 0)
|
|
889
|
+
or (
|
|
890
|
+
isinstance(source_column_ibis_type, dt.Decimal)
|
|
891
|
+
and (
|
|
892
|
+
source_column_ibis_type.precision is None
|
|
893
|
+
or source_column_ibis_type.precision > (18 - margin)
|
|
894
|
+
)
|
|
890
895
|
)
|
|
891
896
|
)
|
|
892
897
|
and (
|
|
893
|
-
isinstance(target_column_ibis_type, dt.
|
|
894
|
-
|
|
895
|
-
target_column_ibis_type.
|
|
896
|
-
|
|
898
|
+
(isinstance(target_column_ibis_type, dt.Int64) and margin > 0)
|
|
899
|
+
or (
|
|
900
|
+
isinstance(target_column_ibis_type, dt.Decimal)
|
|
901
|
+
and (
|
|
902
|
+
target_column_ibis_type.precision is None
|
|
903
|
+
or target_column_ibis_type.precision > (18 - margin)
|
|
904
|
+
)
|
|
897
905
|
)
|
|
898
906
|
)
|
|
899
907
|
)
|
{google_pso_data_validator-7.2.0 → google_pso_data_validator-7.4.0}/data_validation/consts.py
RENAMED
|
@@ -56,6 +56,8 @@ CONFIG_CASE_INSENSITIVE_MATCH = "case_insensitive_match"
|
|
|
56
56
|
CONFIG_ROW_CONCAT = "concat"
|
|
57
57
|
CONFIG_ROW_HASH = "hash"
|
|
58
58
|
CONFIG_RUN_ID = "run_id"
|
|
59
|
+
CONFIG_START_TIME = "start_time"
|
|
60
|
+
CONFIG_END_TIME = "end_time"
|
|
59
61
|
CONFIG_SOURCE_COLUMN = "source_column"
|
|
60
62
|
CONFIG_TARGET_COLUMN = "target_column"
|
|
61
63
|
CONFIG_THRESHOLD = "threshold"
|
|
@@ -142,12 +144,21 @@ TARGET_AGG_VALUE = "target_agg_value"
|
|
|
142
144
|
VALIDATION_STATUS = "validation_status"
|
|
143
145
|
VALIDATION_STATUS_SUCCESS = "success"
|
|
144
146
|
VALIDATION_STATUS_FAIL = "fail"
|
|
145
|
-
# TODO: update if we start to support other statuses
|
|
146
147
|
VALIDATION_STATUSES = [
|
|
147
148
|
VALIDATION_STATUS_SUCCESS,
|
|
148
149
|
VALIDATION_STATUS_FAIL,
|
|
149
150
|
]
|
|
150
151
|
|
|
152
|
+
# Summary stats of Row Validation results
|
|
153
|
+
TOTAL_SOURCE_ROWS = "total_source_rows"
|
|
154
|
+
TOTAL_TARGET_ROWS = "total_target_rows"
|
|
155
|
+
TOTAL_ROWS_VALIDATED = "total_rows_validated"
|
|
156
|
+
TOTAL_ROWS_SUCCESS = "total_rows_success_validation_status"
|
|
157
|
+
TOTAL_ROWS_FAIL = "total_rows_fail_validation_status"
|
|
158
|
+
FAILED_SOURCE_NOT_IN_TARGET = "failed_rows_present_in_source_not_in_target"
|
|
159
|
+
FAILED_TARGET_NOT_IN_SOURCE = "failed_rows_present_in_target_not_in_source"
|
|
160
|
+
FAILED_PRESENT_IN_BOTH_TABLES = "failed_rows_present_in_both_source_and_target"
|
|
161
|
+
|
|
151
162
|
# SQL Template Formatting
|
|
152
163
|
# TODO: should this be managed in query_builder if that is the only place its used?
|
|
153
164
|
COUNT_STAR = "{count_star}"
|
|
@@ -156,29 +167,36 @@ COUNT_STAR = "{count_star}"
|
|
|
156
167
|
RESULT_TYPE_SOURCE = "source"
|
|
157
168
|
RESULT_TYPE_TARGET = "target"
|
|
158
169
|
|
|
159
|
-
|
|
170
|
+
FORMAT_TYPE_CSV = "csv"
|
|
171
|
+
FORMAT_TYPE_JSON = "json"
|
|
172
|
+
FORMAT_TYPE_MINIMAL = "minimal"
|
|
173
|
+
FORMAT_TYPE_PYTHON = "python"
|
|
174
|
+
FORMAT_TYPE_TABLE = "table"
|
|
175
|
+
FORMAT_TYPE_TEXT = "text"
|
|
176
|
+
FORMAT_TYPES = [FORMAT_TYPE_CSV, FORMAT_TYPE_JSON, FORMAT_TYPE_TABLE, FORMAT_TYPE_TEXT]
|
|
177
|
+
RAW_QUERY_FORMAT_TYPES = [FORMAT_TYPE_MINIMAL, FORMAT_TYPE_PYTHON]
|
|
160
178
|
|
|
161
179
|
# Text Result Handler column filter list
|
|
162
180
|
COLUMN_FILTER_LIST = [
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
181
|
+
AGGREGATION_TYPE,
|
|
182
|
+
CONFIG_END_TIME,
|
|
183
|
+
CONFIG_LABELS,
|
|
166
184
|
"pct_threshold",
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
185
|
+
CONFIG_START_TIME,
|
|
186
|
+
TARGET_TABLE_NAME,
|
|
187
|
+
TARGET_COLUMN_NAME,
|
|
170
188
|
"difference",
|
|
171
|
-
|
|
172
|
-
|
|
189
|
+
CONFIG_PRIMARY_KEYS,
|
|
190
|
+
GROUP_BY_COLUMNS,
|
|
173
191
|
"num_random_rows",
|
|
174
192
|
]
|
|
175
193
|
SCHEMA_VALIDATION_COLUMN_FILTER_LIST = [
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
194
|
+
CONFIG_START_TIME,
|
|
195
|
+
CONFIG_END_TIME,
|
|
196
|
+
AGGREGATION_TYPE,
|
|
179
197
|
"difference",
|
|
180
|
-
|
|
181
|
-
|
|
198
|
+
CONFIG_PRIMARY_KEYS,
|
|
199
|
+
GROUP_BY_COLUMNS,
|
|
182
200
|
"num_random_rows",
|
|
183
201
|
"pct_threshold",
|
|
184
202
|
]
|
|
@@ -353,7 +353,10 @@ class DataValidation(object):
|
|
|
353
353
|
target_df = futures[1].result()
|
|
354
354
|
|
|
355
355
|
pandas_client = ibis.pandas.connect(
|
|
356
|
-
{
|
|
356
|
+
{
|
|
357
|
+
consts.RESULT_TYPE_SOURCE: source_df,
|
|
358
|
+
consts.RESULT_TYPE_TARGET: target_df,
|
|
359
|
+
}
|
|
357
360
|
)
|
|
358
361
|
|
|
359
362
|
try:
|
|
@@ -362,8 +365,8 @@ class DataValidation(object):
|
|
|
362
365
|
combiner.generate_report,
|
|
363
366
|
pandas_client,
|
|
364
367
|
self.run_metadata,
|
|
365
|
-
pandas_client.table(
|
|
366
|
-
pandas_client.table(
|
|
368
|
+
pandas_client.table(consts.RESULT_TYPE_SOURCE),
|
|
369
|
+
pandas_client.table(consts.RESULT_TYPE_TARGET),
|
|
367
370
|
join_on_fields=join_on_fields,
|
|
368
371
|
is_value_comparison=is_value_comparison,
|
|
369
372
|
verbose=self.verbose,
|