google-pso-data-validator 7.3.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.3.0 → google_pso_data_validator-7.4.0}/PKG-INFO +3 -1
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/README.md +2 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/__main__.py +8 -5
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/cli_tools.py +17 -7
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/config_manager.py +19 -11
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/consts.py +8 -1
- {google_pso_data_validator-7.3.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.3.0 → google_pso_data_validator-7.4.0}/data_validation/result_handlers/bigquery.py +3 -3
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/result_handlers/text.py +6 -4
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/PKG-INFO +3 -1
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/setup.py +1 -1
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/registry.py +8 -2
- google_pso_data_validator-7.3.0/data_validation/raw_query.py +0 -47
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/LICENSE +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/app.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/client_info.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/clients.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/combiner.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/data_validation.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/exceptions.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/find_tables.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/gcs_helper.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/jellyfish_distance.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/metadata.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/partition_row_builder.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/query_builder.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/query_builder/random_row_builder.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/result_handlers/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/schema_validation.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/secret_manager.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/state_manager.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/util.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/validation_builder.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/SOURCES.txt +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/requires.txt +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/setup.cfg +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_addon/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_addon/operations.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_biquery/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_biquery/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/compiler.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/datatypes.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/registry.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_impala/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_impala/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mssql/registry.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
- {google_pso_data_validator-7.3.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.3.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.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/datatypes.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_oracle/registry.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/client.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_postgres/datatypes.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_redshift/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_redshift/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_snowflake/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_snowflake/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/__init__.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/api.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
- {google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_teradata/datatypes.py +0 -0
- {google_pso_data_validator-7.3.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.3.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
|
|
|
@@ -596,7 +599,7 @@ def store_json_config_file(args, config_managers):
|
|
|
596
599
|
cli_tools.store_validation(config_file_path, json_config)
|
|
597
600
|
|
|
598
601
|
|
|
599
|
-
def partition_and_store_config_files(args: Namespace) -> None:
|
|
602
|
+
def partition_and_store_config_files(args: "Namespace") -> None:
|
|
600
603
|
"""Build multiple YAML Config files using user specified partition logic
|
|
601
604
|
|
|
602
605
|
Args:
|
|
@@ -691,7 +694,7 @@ def main():
|
|
|
691
694
|
print(find_tables_using_string_matching(args))
|
|
692
695
|
elif args.command == "query":
|
|
693
696
|
raw_query.print_raw_query_output(
|
|
694
|
-
raw_query.run_raw_query_against_connection(args)
|
|
697
|
+
raw_query.run_raw_query_against_connection(args), format=args.output_format
|
|
695
698
|
)
|
|
696
699
|
elif args.command == "validate":
|
|
697
700
|
validate(args)
|
{google_pso_data_validator-7.3.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
|
|
@@ -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.3.0 → google_pso_data_validator-7.4.0}/data_validation/consts.py
RENAMED
|
@@ -167,7 +167,14 @@ COUNT_STAR = "{count_star}"
|
|
|
167
167
|
RESULT_TYPE_SOURCE = "source"
|
|
168
168
|
RESULT_TYPE_TARGET = "target"
|
|
169
169
|
|
|
170
|
-
|
|
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]
|
|
171
178
|
|
|
172
179
|
# Text Result Handler column filter list
|
|
173
180
|
COLUMN_FILTER_LIST = [
|
|
@@ -17,8 +17,7 @@ import ibis
|
|
|
17
17
|
import pandas
|
|
18
18
|
import logging
|
|
19
19
|
import re
|
|
20
|
-
from typing import List, Dict
|
|
21
|
-
from argparse import Namespace
|
|
20
|
+
from typing import List, Dict, TYPE_CHECKING
|
|
22
21
|
|
|
23
22
|
from data_validation import cli_tools, consts
|
|
24
23
|
from data_validation.config_manager import ConfigManager
|
|
@@ -26,9 +25,12 @@ from data_validation.query_builder.partition_row_builder import PartitionRowBuil
|
|
|
26
25
|
from data_validation.validation_builder import ValidationBuilder
|
|
27
26
|
from data_validation.validation_builder import list_to_sublists
|
|
28
27
|
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from argparse import Namespace
|
|
30
|
+
|
|
29
31
|
|
|
30
32
|
class PartitionBuilder:
|
|
31
|
-
def __init__(self, config_managers: List[ConfigManager], args: Namespace) -> None:
|
|
33
|
+
def __init__(self, config_managers: List[ConfigManager], args: "Namespace") -> None:
|
|
32
34
|
self.config_managers = config_managers
|
|
33
35
|
self.table_count = len(config_managers)
|
|
34
36
|
self.args = args
|
|
@@ -62,7 +64,7 @@ class PartitionBuilder:
|
|
|
62
64
|
"""
|
|
63
65
|
# Create multiple yaml validation blocks corresponding to the filters provided
|
|
64
66
|
yaml_validations = []
|
|
65
|
-
for
|
|
67
|
+
for source_filter, target_filter in zip(source_filters, target_filters):
|
|
66
68
|
filter_dict = {
|
|
67
69
|
"type": "custom",
|
|
68
70
|
"source": source_filter,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Copyright 2024 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from sqlalchemy.engine.row import Row
|
|
18
|
+
|
|
19
|
+
from data_validation import clients, consts, state_manager
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from argparse import Namespace
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def run_raw_query_against_connection(args: "Namespace") -> list:
|
|
26
|
+
"""Return results of raw query for ad hoc usage."""
|
|
27
|
+
mgr = state_manager.StateManager()
|
|
28
|
+
with clients.get_data_client_ctx(mgr.get_connection_config(args.conn)) as client:
|
|
29
|
+
cursor = client.raw_sql(args.query)
|
|
30
|
+
res = cursor.fetchall()
|
|
31
|
+
try:
|
|
32
|
+
cursor.close()
|
|
33
|
+
except Exception:
|
|
34
|
+
pass
|
|
35
|
+
return res
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _minimize_raw_query_output(query_output: list) -> list:
|
|
39
|
+
"""Reduce single column output from list(tuple(_)) to list(_)"""
|
|
40
|
+
if not query_output:
|
|
41
|
+
return query_output
|
|
42
|
+
if isinstance(query_output[0], (list, tuple)) and len(query_output[0]) == 1:
|
|
43
|
+
return [_[0] for _ in query_output]
|
|
44
|
+
else:
|
|
45
|
+
return query_output
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def print_raw_query_output(query_output: list, format: str = consts.FORMAT_TYPE_PYTHON):
|
|
49
|
+
"""Print a query resultset avoiding SQLAlchemy "... (nn characters truncated) ..." behaviour.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
query_output (list): A set of rows from a SQLAlchemy query.
|
|
53
|
+
format (str): Output format:
|
|
54
|
+
FORMAT_TYPE_PYTHON: Legacy format matching previous behaviour, simple print the Python object.
|
|
55
|
+
FORMAT_TYPE_MINIMAL: Attempt to minimize additional noise for bare minimum output.
|
|
56
|
+
This is useful for a specific customer who are using DVT raw queries to
|
|
57
|
+
generate other DVT commands and don't want any escaping or extra parentheses
|
|
58
|
+
in the output.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def row_to_tuple(row) -> tuple:
|
|
62
|
+
"""This prevents SQLAlchemy string truncation inside Row() objects by first converting them to a tuple."""
|
|
63
|
+
if isinstance(row, (Row, list)):
|
|
64
|
+
return tuple(row)
|
|
65
|
+
else:
|
|
66
|
+
return row
|
|
67
|
+
|
|
68
|
+
sanitized_output = [row_to_tuple(_) for _ in query_output or []]
|
|
69
|
+
|
|
70
|
+
if format == consts.FORMAT_TYPE_MINIMAL:
|
|
71
|
+
for row in _minimize_raw_query_output(sanitized_output):
|
|
72
|
+
print(row)
|
|
73
|
+
else:
|
|
74
|
+
print(sanitized_output)
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import logging
|
|
18
18
|
|
|
19
|
-
from data_validation import clients
|
|
19
|
+
from data_validation import clients, consts
|
|
20
20
|
from data_validation.result_handlers import text as text_handler
|
|
21
21
|
|
|
22
22
|
|
|
@@ -39,7 +39,7 @@ class BigQueryResultHandler(object):
|
|
|
39
39
|
bigquery_client,
|
|
40
40
|
status_list: list = None,
|
|
41
41
|
table_id: str = "pso_data_validator.results",
|
|
42
|
-
text_format: str =
|
|
42
|
+
text_format: str = consts.FORMAT_TYPE_TABLE,
|
|
43
43
|
):
|
|
44
44
|
self._bigquery_client = bigquery_client
|
|
45
45
|
self._table_id = table_id
|
|
@@ -53,7 +53,7 @@ class BigQueryResultHandler(object):
|
|
|
53
53
|
table_id: str = "pso_data_validator.results",
|
|
54
54
|
credentials=None,
|
|
55
55
|
api_endpoint: str = None,
|
|
56
|
-
text_format: str =
|
|
56
|
+
text_format: str = consts.FORMAT_TYPE_TABLE,
|
|
57
57
|
):
|
|
58
58
|
"""Return BigQueryResultHandler instance for given project.
|
|
59
59
|
|
|
@@ -35,15 +35,17 @@ def filter_validation_status(status_list, result_df: "DataFrame"):
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def get_formatted(
|
|
38
|
-
result_df: "DataFrame",
|
|
38
|
+
result_df: "DataFrame",
|
|
39
|
+
format: str = consts.FORMAT_TYPE_TABLE,
|
|
40
|
+
cols_filter_list: list = None,
|
|
39
41
|
) -> str:
|
|
40
42
|
"""Expose formatting logic so it can be used in BigQuery handler."""
|
|
41
43
|
cols_filter_list = cols_filter_list or consts.COLUMN_FILTER_LIST
|
|
42
|
-
if format ==
|
|
44
|
+
if format == consts.FORMAT_TYPE_TEXT:
|
|
43
45
|
return result_df.drop(cols_filter_list, axis=1).to_string(index=False)
|
|
44
|
-
elif format ==
|
|
46
|
+
elif format == consts.FORMAT_TYPE_CSV:
|
|
45
47
|
return result_df.to_csv(index=False, lineterminator="\n")
|
|
46
|
-
elif format ==
|
|
48
|
+
elif format == consts.FORMAT_TYPE_JSON:
|
|
47
49
|
return result_df.to_json(orient="index")
|
|
48
50
|
else:
|
|
49
51
|
return result_df.drop(cols_filter_list, axis=1).to_markdown(
|
|
@@ -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
|
|
@@ -23,6 +23,12 @@ def sa_format_hashbytes(translator, op):
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def sa_epoch_seconds(translator, op):
|
|
26
|
-
"""Override for standard ExtractEpochSeconds but catering for larger second values.
|
|
26
|
+
"""Override for standard ExtractEpochSeconds but catering for larger second values.
|
|
27
|
+
|
|
28
|
+
This expression also truncates fractional seconds from the incoming datetime.
|
|
29
|
+
This matches behaviour on other SQL engines' epoch seconds expressions."""
|
|
27
30
|
arg = translator.translate(op.arg)
|
|
28
|
-
return sa.cast(
|
|
31
|
+
return sa.cast(
|
|
32
|
+
sa.extract("epoch", sa.func.date_trunc(sa.sql.literal_column("'second'"), arg)),
|
|
33
|
+
sa.BIGINT,
|
|
34
|
+
)
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Copyright 2024 Google LLC
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from sqlalchemy.engine.row import Row
|
|
16
|
-
|
|
17
|
-
from data_validation import clients, state_manager
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def run_raw_query_against_connection(args) -> list:
|
|
21
|
-
"""Return results of raw query for ad hoc usage."""
|
|
22
|
-
mgr = state_manager.StateManager()
|
|
23
|
-
with clients.get_data_client_ctx(mgr.get_connection_config(args.conn)) as client:
|
|
24
|
-
cursor = client.raw_sql(args.query)
|
|
25
|
-
res = cursor.fetchall()
|
|
26
|
-
try:
|
|
27
|
-
cursor.close()
|
|
28
|
-
except Exception:
|
|
29
|
-
pass
|
|
30
|
-
return res
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def print_raw_query_output(query_output: list):
|
|
34
|
-
"""Print a query resultset avoiding SQLAlchemy "... (nn characters truncated) ..." behaviour.
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
query_output (list): A set of rows from a SQLAlchemy query.
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
def row_to_str(row) -> str:
|
|
41
|
-
"""This prevents SQLAlchemy string truncation inside Row() objects by first converting them to a tuple."""
|
|
42
|
-
if isinstance(row, Row):
|
|
43
|
-
return str(tuple(row))
|
|
44
|
-
else:
|
|
45
|
-
return str(row)
|
|
46
|
-
|
|
47
|
-
print([row_to_str(_) for _ in query_output or []])
|
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/client_info.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/clients.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/combiner.py
RENAMED
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/exceptions.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/find_tables.py
RENAMED
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/gcs_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/data_validation/state_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-7.3.0 → google_pso_data_validator-7.4.0}/third_party/ibis/ibis_db2/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|