google-pso-data-validator 8.3.0__tar.gz → 8.5.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-8.3.0/google_pso_data_validator.egg-info → google_pso_data_validator-8.5.0}/PKG-INFO +9 -3
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/README.md +6 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/__main__.py +1 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/cli_tools.py +42 -25
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/clients.py +43 -14
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/config_manager.py +79 -4
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/consts.py +7 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/exceptions.py +4 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/partition_builder.py +10 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/query_builder/query_builder.py +4 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/query_builder/random_row_builder.py +2 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0/google_pso_data_validator.egg-info}/PKG-INFO +9 -3
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/google_pso_data_validator.egg-info/SOURCES.txt +5 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/google_pso_data_validator.egg-info/requires.txt +2 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/setup.py +3 -2
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_addon/api.py +34 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_addon/operations.py +15 -16
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_bigquery/__init__.py +20 -10
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_db2/compiler.py +1 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_db2/datatypes.py +7 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_db2/registry.py +24 -42
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mssql/registry.py +1 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_oracle/datatypes.py +1 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_redshift/__init__.py +1 -1
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_snowflake/api.py +16 -7
- google_pso_data_validator-8.5.0/third_party/ibis/ibis_sybase/__init__.py +185 -0
- google_pso_data_validator-8.5.0/third_party/ibis/ibis_sybase/api.py +42 -0
- google_pso_data_validator-8.5.0/third_party/ibis/ibis_sybase/compiler.py +101 -0
- google_pso_data_validator-8.5.0/third_party/ibis/ibis_sybase/datatypes.py +95 -0
- google_pso_data_validator-8.5.0/third_party/ibis/ibis_sybase/registry.py +209 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/LICENSE +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/app.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/client_info.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/combiner.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/data_validation.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/find_tables.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/gcs_helper.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/jellyfish_distance.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/metadata.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/query_builder/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/query_builder/partition_row_builder.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/raw_query.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/result_handlers/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/result_handlers/base_backend.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/result_handlers/bigquery.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/result_handlers/factory.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/result_handlers/postgres.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/result_handlers/text.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/schema_validation.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/secret_manager.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/state_manager.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/util.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/validation_builder.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/setup.cfg +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_bigquery/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_bigquery/registry.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_db2/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_db2/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_impala/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_impala/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mssql/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mssql/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mysql/base_sql_compiler/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mysql/base_sql_compiler/select_builder.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_oracle/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_oracle/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_oracle/registry.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_postgres/client.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_postgres/datatypes.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_postgres/registry.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_redshift/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_snowflake/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_teradata/__init__.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_teradata/api.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_teradata/datatypes.py +0 -0
- {google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/third_party/ibis/ibis_teradata/registry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-pso-data-validator
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.5.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
|
|
@@ -28,7 +28,7 @@ Requires-Dist: jellyfish>=1.1.0
|
|
|
28
28
|
Requires-Dist: pandas
|
|
29
29
|
Requires-Dist: parsy>=2.1
|
|
30
30
|
Requires-Dist: psycopg2-binary>=2.9.9
|
|
31
|
-
Requires-Dist: pyarrow
|
|
31
|
+
Requires-Dist: pyarrow
|
|
32
32
|
Requires-Dist: pydata-google-auth>=1.8.2
|
|
33
33
|
Requires-Dist: PyMySQL>=1.1.1
|
|
34
34
|
Requires-Dist: PyYAML>=6.0.2
|
|
@@ -45,6 +45,7 @@ Requires-Dist: freezegun; extra == "develop"
|
|
|
45
45
|
Requires-Dist: pyfakefs; extra == "develop"
|
|
46
46
|
Requires-Dist: pytest; extra == "develop"
|
|
47
47
|
Requires-Dist: pytest-cov; extra == "develop"
|
|
48
|
+
Requires-Dist: pytest-rerunfailures; extra == "develop"
|
|
48
49
|
Requires-Dist: pytest-timeout; extra == "develop"
|
|
49
50
|
Dynamic: author
|
|
50
51
|
Dynamic: author-email
|
|
@@ -92,8 +93,9 @@ DVT supports the following connection types:
|
|
|
92
93
|
* [Postgres](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#postgres)
|
|
93
94
|
* [Redshift](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#redshift)
|
|
94
95
|
* [Spanner](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-spanner)
|
|
95
|
-
* [Teradata](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#teradata)
|
|
96
96
|
* [Snowflake](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#snowflake)
|
|
97
|
+
* [Sybase ASE](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#sybase)
|
|
98
|
+
* [Teradata](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#teradata)
|
|
97
99
|
|
|
98
100
|
The [Connections](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md) page provides details about how to create
|
|
99
101
|
and list connections for the validation tool.
|
|
@@ -552,6 +554,10 @@ data-validation
|
|
|
552
554
|
Comma-separated key value pair labels for the run.
|
|
553
555
|
[--format or -fmt FORMAT]
|
|
554
556
|
Format for stdout output. Supported formats are (text, csv, json, table). Defaults to table.
|
|
557
|
+
[--use-random-row or -rr]
|
|
558
|
+
Finds a set of random rows of the first primary key supplied.
|
|
559
|
+
[--random-row-batch-size or -rbs]
|
|
560
|
+
Row batch size used for random row filters (default 10,000).
|
|
555
561
|
[--filter-status or -fs STATUSES_LIST]
|
|
556
562
|
Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
|
|
557
563
|
[--case-insensitive-match, -cim]
|
|
@@ -33,8 +33,9 @@ DVT supports the following connection types:
|
|
|
33
33
|
* [Postgres](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#postgres)
|
|
34
34
|
* [Redshift](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#redshift)
|
|
35
35
|
* [Spanner](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-spanner)
|
|
36
|
-
* [Teradata](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#teradata)
|
|
37
36
|
* [Snowflake](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#snowflake)
|
|
37
|
+
* [Sybase ASE](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#sybase)
|
|
38
|
+
* [Teradata](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#teradata)
|
|
38
39
|
|
|
39
40
|
The [Connections](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md) page provides details about how to create
|
|
40
41
|
and list connections for the validation tool.
|
|
@@ -493,6 +494,10 @@ data-validation
|
|
|
493
494
|
Comma-separated key value pair labels for the run.
|
|
494
495
|
[--format or -fmt FORMAT]
|
|
495
496
|
Format for stdout output. Supported formats are (text, csv, json, table). Defaults to table.
|
|
497
|
+
[--use-random-row or -rr]
|
|
498
|
+
Finds a set of random rows of the first primary key supplied.
|
|
499
|
+
[--random-row-batch-size or -rbs]
|
|
500
|
+
Row batch size used for random row filters (default 10,000).
|
|
496
501
|
[--filter-status or -fs STATUSES_LIST]
|
|
497
502
|
Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
|
|
498
503
|
[--case-insensitive-match, -cim]
|
{google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/__main__.py
RENAMED
|
@@ -596,6 +596,7 @@ def partition_and_store_config_files(args: "Namespace") -> None:
|
|
|
596
596
|
setattr(args, "custom_query_type", "row")
|
|
597
597
|
config_managers = build_config_managers_from_args(args, consts.CUSTOM_QUERY)
|
|
598
598
|
partition_builder = PartitionBuilder(config_managers, args)
|
|
599
|
+
partition_builder.check_partition_configs()
|
|
599
600
|
partition_builder.partition_configs()
|
|
600
601
|
|
|
601
602
|
|
{google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/cli_tools.py
RENAMED
|
@@ -73,6 +73,10 @@ if TYPE_CHECKING:
|
|
|
73
73
|
CONNECTION_SOURCE_FIELDS = {
|
|
74
74
|
consts.SOURCE_TYPE_BIGQUERY: [
|
|
75
75
|
["project_id", "GCP Project to use for BigQuery"],
|
|
76
|
+
[
|
|
77
|
+
"client_project_id",
|
|
78
|
+
"(Optional) BigQuery job/billing project (can differ from data project)",
|
|
79
|
+
],
|
|
76
80
|
["google_service_account_key_path", "(Optional) GCP SA Key Path"],
|
|
77
81
|
[
|
|
78
82
|
"api_endpoint",
|
|
@@ -84,7 +88,7 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
84
88
|
],
|
|
85
89
|
],
|
|
86
90
|
consts.SOURCE_TYPE_TERADATA: [
|
|
87
|
-
["host", "
|
|
91
|
+
["host", "Teradata host"],
|
|
88
92
|
["port", "Teradata port to connect on"],
|
|
89
93
|
["user_name", "User used to connect"],
|
|
90
94
|
["password", "Password for supplied user"],
|
|
@@ -93,7 +97,7 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
93
97
|
["json_params", "(Optional) Additional teradatasql JSON string parameters"],
|
|
94
98
|
],
|
|
95
99
|
consts.SOURCE_TYPE_ORACLE: [
|
|
96
|
-
["host", "
|
|
100
|
+
["host", "Oracle host"],
|
|
97
101
|
["port", "Oracle port to connect on"],
|
|
98
102
|
["user", "User used to connect"],
|
|
99
103
|
["thick_mode", "Flag indicating thick_mode"],
|
|
@@ -103,7 +107,7 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
103
107
|
["connect_args", "(Optional) Additional connection argument mapping"],
|
|
104
108
|
],
|
|
105
109
|
consts.SOURCE_TYPE_MSSQL: [
|
|
106
|
-
["host", "
|
|
110
|
+
["host", "SQL Server host (default localhost)"],
|
|
107
111
|
["port", "SQL Server port to connect on (default 1433)"],
|
|
108
112
|
["user", "User used to connect"],
|
|
109
113
|
["password", "Password for supplied user"],
|
|
@@ -112,7 +116,7 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
112
116
|
["url", "SQL Server SQLAlchemy connection URL"],
|
|
113
117
|
],
|
|
114
118
|
consts.SOURCE_TYPE_MYSQL: [
|
|
115
|
-
["host", "
|
|
119
|
+
["host", "MySQL host (default localhost)"],
|
|
116
120
|
["port", "MySQL port to connect on (default 3306)"],
|
|
117
121
|
["user", "User used to connect"],
|
|
118
122
|
["password", "Password for supplied user"],
|
|
@@ -123,17 +127,19 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
123
127
|
["password", "Password for authentication of user"],
|
|
124
128
|
["account", "Snowflake account to connect to"],
|
|
125
129
|
["database", "Database in snowflake to connect to"],
|
|
130
|
+
["warehouse", "Warehouse in snowflake to connect to"],
|
|
131
|
+
["role", "Role in snowflake to connect as"],
|
|
126
132
|
["connect_args", "(Optional) Additional connection argument mapping"],
|
|
127
133
|
],
|
|
128
134
|
consts.SOURCE_TYPE_POSTGRES: [
|
|
129
|
-
["host", "
|
|
135
|
+
["host", "PostgreSQL host."],
|
|
130
136
|
["port", "PostgreSQL port to connect on (e.g. 5432)"],
|
|
131
137
|
["user", "Username to connect to"],
|
|
132
138
|
["password", "Password for authentication of user"],
|
|
133
139
|
["database", "Database in PostgreSQL to connect to (default postgres)"],
|
|
134
140
|
],
|
|
135
141
|
consts.SOURCE_TYPE_REDSHIFT: [
|
|
136
|
-
["host", "
|
|
142
|
+
["host", "Redshift host."],
|
|
137
143
|
["port", "Redshift port to connect on (e.g. 5439)"],
|
|
138
144
|
["user", "Username to connect to"],
|
|
139
145
|
["password", "Password for authentication of user"],
|
|
@@ -149,16 +155,26 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
149
155
|
'(Optional) GCP Spanner API endpoint (e.g. "https://spanner-mypsc.p.googleapis.com")',
|
|
150
156
|
],
|
|
151
157
|
],
|
|
158
|
+
consts.SOURCE_TYPE_SYBASE: [
|
|
159
|
+
["host", "Sybase host (default localhost)"],
|
|
160
|
+
["port", "Sybase port to connect on (default 5000)"],
|
|
161
|
+
["user", "User used to connect"],
|
|
162
|
+
["password", "Password for supplied user"],
|
|
163
|
+
["database", "Database to connect to (default master)"],
|
|
164
|
+
["odbc_driver", "ODBC driver name"],
|
|
165
|
+
["query", "Connection query parameters"],
|
|
166
|
+
["url", "Sybase SQLAlchemy connection URL"],
|
|
167
|
+
],
|
|
152
168
|
consts.SOURCE_TYPE_FILESYSTEM: [
|
|
153
169
|
["table_name", "Table name to use as reference for file data"],
|
|
154
170
|
["file_path", "The local, s3, or GCS file path to the data"],
|
|
155
171
|
["file_type", "The file type of the file. 'csv', 'orc', 'parquet' or 'json'"],
|
|
156
172
|
],
|
|
157
173
|
consts.SOURCE_TYPE_IMPALA: [
|
|
158
|
-
["host", "
|
|
159
|
-
["port", "
|
|
160
|
-
["database", "
|
|
161
|
-
["auth_mechanism", "
|
|
174
|
+
["host", "Impala host"],
|
|
175
|
+
["port", "Impala port (10000 if not provided)"],
|
|
176
|
+
["database", "Impala database (default if not provided)"],
|
|
177
|
+
["auth_mechanism", "Impala auth mechanism (PLAIN if not provided)"],
|
|
162
178
|
[
|
|
163
179
|
"kerberos_service_name",
|
|
164
180
|
"Desired Kerberos service name ('impala' if not provided)",
|
|
@@ -183,8 +199,8 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
183
199
|
["http_path", "URL path of HTTP proxy"],
|
|
184
200
|
],
|
|
185
201
|
consts.SOURCE_TYPE_DB2: [
|
|
186
|
-
["host", "
|
|
187
|
-
["port", "
|
|
202
|
+
["host", "DB2 host"],
|
|
203
|
+
["port", "DB2 port (50000 if not provided)"],
|
|
188
204
|
["user", "Username to connect to"],
|
|
189
205
|
["password", "Password for authentication of user"],
|
|
190
206
|
["database", "Database in DB2 to connect to"],
|
|
@@ -646,8 +662,8 @@ def _configure_row_parser(
|
|
|
646
662
|
defaults, so most users do not need to use this option unless they encounter errors."""
|
|
647
663
|
),
|
|
648
664
|
)
|
|
649
|
-
# Generate-table-partitions
|
|
650
|
-
if not
|
|
665
|
+
# Generate-table-partitions does not support random row
|
|
666
|
+
if not is_generate_partitions:
|
|
651
667
|
optional_arguments.add_argument(
|
|
652
668
|
"--use-random-row",
|
|
653
669
|
"-rr",
|
|
@@ -659,17 +675,18 @@ def _configure_row_parser(
|
|
|
659
675
|
"-rbs",
|
|
660
676
|
help="Row batch size used for random row filters (default 10,000).",
|
|
661
677
|
)
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
678
|
+
if not is_custom_query:
|
|
679
|
+
# Generate table partitions follows a new argument spec where either the table names or queries can be provided, but not both.
|
|
680
|
+
# that is specified in configure_partition_parser. If we use the same spec for row and column validation, the custom query commands
|
|
681
|
+
# may get subsumed by validate and validate commands by specifying tables name or queries. Until this -tbls will be
|
|
682
|
+
# a required argument for validate row, validate column and validate schema.
|
|
683
|
+
required_arguments.add_argument(
|
|
684
|
+
"--tables-list",
|
|
685
|
+
"-tbls",
|
|
686
|
+
default=None,
|
|
687
|
+
required=True,
|
|
688
|
+
help="Comma separated tables list in the form 'schema.table=target_schema.target_table'",
|
|
689
|
+
)
|
|
673
690
|
|
|
674
691
|
# Group for mutually exclusive required arguments. Either must be supplied
|
|
675
692
|
mutually_exclusive_arguments = required_arguments.add_mutually_exclusive_group(
|
{google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/clients.py
RENAMED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
from contextlib import contextmanager
|
|
17
17
|
import copy
|
|
18
18
|
import logging
|
|
19
|
-
from typing import TYPE_CHECKING
|
|
19
|
+
from typing import TYPE_CHECKING, Optional
|
|
20
20
|
import warnings
|
|
21
21
|
|
|
22
22
|
import google.oauth2.service_account
|
|
@@ -56,6 +56,7 @@ IBIS_ALCHEMY_BACKENDS = [
|
|
|
56
56
|
"mssql",
|
|
57
57
|
"redshift",
|
|
58
58
|
"snowflake",
|
|
59
|
+
"sybase",
|
|
59
60
|
]
|
|
60
61
|
|
|
61
62
|
|
|
@@ -93,19 +94,32 @@ try:
|
|
|
93
94
|
except ImportError:
|
|
94
95
|
db2_connect = _raise_missing_client_error("pip install ibm_db_sa")
|
|
95
96
|
|
|
97
|
+
# Sybase requires sqlalchemy_sybase package.
|
|
98
|
+
try:
|
|
99
|
+
from third_party.ibis.ibis_sybase.api import sybase_connect
|
|
100
|
+
except ImportError:
|
|
101
|
+
sybase_connect = _raise_missing_client_error("pip install sqlalchemy_sybase")
|
|
102
|
+
|
|
96
103
|
|
|
97
104
|
def get_google_bigquery_client(
|
|
98
|
-
project_id: str,
|
|
105
|
+
project_id: str,
|
|
106
|
+
credentials=None,
|
|
107
|
+
api_endpoint: Optional[str] = None,
|
|
108
|
+
quota_project_id: Optional[str] = None,
|
|
99
109
|
):
|
|
100
110
|
info = client_info.get_http_client_info()
|
|
101
111
|
job_config = bigquery.QueryJobConfig(
|
|
102
112
|
connection_properties=[bigquery.ConnectionProperty("time_zone", "UTC")]
|
|
103
113
|
)
|
|
114
|
+
effective_project = quota_project_id or project_id
|
|
104
115
|
options = None
|
|
105
|
-
if api_endpoint:
|
|
106
|
-
options = client_options.ClientOptions(
|
|
116
|
+
if api_endpoint or quota_project_id:
|
|
117
|
+
options = client_options.ClientOptions(
|
|
118
|
+
api_endpoint=api_endpoint,
|
|
119
|
+
quota_project_id=quota_project_id if quota_project_id else None,
|
|
120
|
+
)
|
|
107
121
|
return bigquery.Client(
|
|
108
|
-
project=
|
|
122
|
+
project=effective_project,
|
|
109
123
|
client_info=info,
|
|
110
124
|
credentials=credentials,
|
|
111
125
|
default_query_job_config=job_config,
|
|
@@ -113,10 +127,17 @@ def get_google_bigquery_client(
|
|
|
113
127
|
)
|
|
114
128
|
|
|
115
129
|
|
|
116
|
-
def _get_google_bqstorage_client(
|
|
130
|
+
def _get_google_bqstorage_client(
|
|
131
|
+
credentials=None,
|
|
132
|
+
api_endpoint: Optional[str] = None,
|
|
133
|
+
quota_project_id: Optional[str] = None,
|
|
134
|
+
):
|
|
117
135
|
options = None
|
|
118
|
-
if api_endpoint:
|
|
119
|
-
options = client_options.ClientOptions(
|
|
136
|
+
if api_endpoint or quota_project_id:
|
|
137
|
+
options = client_options.ClientOptions(
|
|
138
|
+
api_endpoint=api_endpoint,
|
|
139
|
+
quota_project_id=quota_project_id if quota_project_id else None,
|
|
140
|
+
)
|
|
120
141
|
from google.cloud import bigquery_storage_v1 as bigquery_storage
|
|
121
142
|
|
|
122
143
|
return bigquery_storage.BigQueryReadClient(
|
|
@@ -129,20 +150,26 @@ def get_bigquery_client(
|
|
|
129
150
|
project_id: str,
|
|
130
151
|
dataset_id: str = "",
|
|
131
152
|
credentials=None,
|
|
132
|
-
api_endpoint: str = None,
|
|
133
|
-
storage_api_endpoint: str = None,
|
|
153
|
+
api_endpoint: Optional[str] = None,
|
|
154
|
+
storage_api_endpoint: Optional[str] = None,
|
|
155
|
+
client_project_id: Optional[str] = None,
|
|
134
156
|
):
|
|
135
157
|
google_client = get_google_bigquery_client(
|
|
136
|
-
project_id,
|
|
158
|
+
project_id,
|
|
159
|
+
credentials=credentials,
|
|
160
|
+
api_endpoint=api_endpoint,
|
|
161
|
+
quota_project_id=client_project_id,
|
|
137
162
|
)
|
|
138
163
|
bqstorage_client = None
|
|
139
164
|
if storage_api_endpoint:
|
|
140
165
|
bqstorage_client = _get_google_bqstorage_client(
|
|
141
|
-
credentials=credentials,
|
|
166
|
+
credentials=credentials,
|
|
167
|
+
api_endpoint=storage_api_endpoint,
|
|
168
|
+
quota_project_id=client_project_id,
|
|
142
169
|
)
|
|
143
170
|
|
|
144
171
|
return bigquery_connect(
|
|
145
|
-
project_id=project_id,
|
|
172
|
+
project_id=project_id or client_project_id,
|
|
146
173
|
dataset_id=dataset_id,
|
|
147
174
|
credentials=credentials,
|
|
148
175
|
bigquery_client=google_client,
|
|
@@ -202,6 +229,7 @@ def get_ibis_table(client, schema_name, table_name, database_name=None):
|
|
|
202
229
|
"db2",
|
|
203
230
|
"mssql",
|
|
204
231
|
"redshift",
|
|
232
|
+
"sybase",
|
|
205
233
|
]:
|
|
206
234
|
return client.table(table_name, database=database_name, schema=schema_name)
|
|
207
235
|
elif client.name == "pandas":
|
|
@@ -261,7 +289,7 @@ def list_tables(client, schema_name, tables_only=True):
|
|
|
261
289
|
if tables_only and client.name != "pandas"
|
|
262
290
|
else client.list_tables
|
|
263
291
|
)
|
|
264
|
-
if client.name in ["
|
|
292
|
+
if client.name in ["redshift", "snowflake", "pandas"]:
|
|
265
293
|
return fn()
|
|
266
294
|
return fn(database=schema_name)
|
|
267
295
|
|
|
@@ -400,5 +428,6 @@ CLIENT_LOOKUP = {
|
|
|
400
428
|
consts.SOURCE_TYPE_MSSQL: mssql_connect,
|
|
401
429
|
consts.SOURCE_TYPE_SNOWFLAKE: snowflake_connect,
|
|
402
430
|
consts.SOURCE_TYPE_SPANNER: spanner_connect,
|
|
431
|
+
consts.SOURCE_TYPE_SYBASE: sybase_connect,
|
|
403
432
|
consts.SOURCE_TYPE_DB2: db2_connect,
|
|
404
433
|
}
|
|
@@ -23,7 +23,10 @@ from data_validation import clients, consts, gcs_helper, state_manager
|
|
|
23
23
|
from data_validation.result_handlers.factory import build_result_handler
|
|
24
24
|
from data_validation.validation_builder import ValidationBuilder
|
|
25
25
|
|
|
26
|
+
from third_party.ibis.ibis_addon.api import db2_type_string_length
|
|
27
|
+
|
|
26
28
|
if TYPE_CHECKING:
|
|
29
|
+
from ibis.backends.base import BaseBackend
|
|
27
30
|
import ibis.expr.types.Table
|
|
28
31
|
|
|
29
32
|
|
|
@@ -71,7 +74,7 @@ class ConfigManager(object):
|
|
|
71
74
|
"""Return config object."""
|
|
72
75
|
return self._config
|
|
73
76
|
|
|
74
|
-
def get_source_connection(self):
|
|
77
|
+
def get_source_connection(self) -> dict:
|
|
75
78
|
"""Return source connection object."""
|
|
76
79
|
if not self._source_conn:
|
|
77
80
|
if self._config.get(consts.CONFIG_SOURCE_CONN):
|
|
@@ -82,7 +85,7 @@ class ConfigManager(object):
|
|
|
82
85
|
|
|
83
86
|
return self._source_conn
|
|
84
87
|
|
|
85
|
-
def get_target_connection(self):
|
|
88
|
+
def get_target_connection(self) -> dict:
|
|
86
89
|
"""Return target connection object."""
|
|
87
90
|
if not self._target_conn:
|
|
88
91
|
if self._config.get(consts.CONFIG_TARGET_CONN):
|
|
@@ -1160,6 +1163,8 @@ class ConfigManager(object):
|
|
|
1160
1163
|
calculated_config.update(custom_params)
|
|
1161
1164
|
elif calc_type == consts.CONFIG_CAST and custom_params:
|
|
1162
1165
|
calculated_config[consts.CONFIG_DEFAULT_CAST] = custom_params
|
|
1166
|
+
elif calc_type == consts.CALC_FIELD_IFNULL and custom_params:
|
|
1167
|
+
calculated_config.update(custom_params)
|
|
1163
1168
|
|
|
1164
1169
|
return calculated_config
|
|
1165
1170
|
|
|
@@ -1294,7 +1299,45 @@ class ConfigManager(object):
|
|
|
1294
1299
|
|
|
1295
1300
|
return result_source_columns, result_target_columns
|
|
1296
1301
|
|
|
1297
|
-
def
|
|
1302
|
+
def _string_column_ifnull_limits(
|
|
1303
|
+
self,
|
|
1304
|
+
client: "BaseBackend",
|
|
1305
|
+
casefold_columns: dict,
|
|
1306
|
+
ibis_table: "ibis.expr.types.Table",
|
|
1307
|
+
raw_types: dict,
|
|
1308
|
+
string_column_ifnull_limits: dict,
|
|
1309
|
+
):
|
|
1310
|
+
"""Defines IfNull replacement token length limits (due to Db2 limitations).
|
|
1311
|
+
|
|
1312
|
+
This is because in Db2 a coalesce of a column cannot exceed the length of the initial argument resulting in:
|
|
1313
|
+
String data right truncation. SQLSTATE=22001
|
|
1314
|
+
|
|
1315
|
+
We need to ensure both source and target systems use the same replacement token therefore these limits are used for both.
|
|
1316
|
+
|
|
1317
|
+
Mutates string_column_ifnull_limits to contain a dict of column names with replacement token length limits:
|
|
1318
|
+
{"col1": 10, "col2": 12, "col_unlimited": None}
|
|
1319
|
+
"""
|
|
1320
|
+
if not casefold_columns or client.name != "db2":
|
|
1321
|
+
return {}
|
|
1322
|
+
table_schema = {k: v for k, v in ibis_table.schema().items()}
|
|
1323
|
+
for casefold_column, column in casefold_columns.items():
|
|
1324
|
+
ifnull_limit = db2_type_string_length(
|
|
1325
|
+
table_schema[casefold_column], raw_types.get(column, [])
|
|
1326
|
+
)
|
|
1327
|
+
if (
|
|
1328
|
+
not string_column_ifnull_limits.get(casefold_column, None)
|
|
1329
|
+
# If the current limit is shorter than an existing one then overwrite the value.
|
|
1330
|
+
or (
|
|
1331
|
+
ifnull_limit
|
|
1332
|
+
and ifnull_limit < string_column_ifnull_limits[casefold_column]
|
|
1333
|
+
)
|
|
1334
|
+
):
|
|
1335
|
+
string_column_ifnull_limits[casefold_column] = ifnull_limit
|
|
1336
|
+
return string_column_ifnull_limits
|
|
1337
|
+
|
|
1338
|
+
def build_dependent_aliases(
|
|
1339
|
+
self, calc_type: str, col_list: Optional[list] = None
|
|
1340
|
+
) -> List[Dict]:
|
|
1298
1341
|
"""This is a utility function for determining the required depth of all fields"""
|
|
1299
1342
|
source_table = self.get_source_ibis_calculated_table()
|
|
1300
1343
|
target_table = self.get_target_ibis_calculated_table()
|
|
@@ -1318,6 +1361,23 @@ class ConfigManager(object):
|
|
|
1318
1361
|
|
|
1319
1362
|
column_aliases = {}
|
|
1320
1363
|
col_names = []
|
|
1364
|
+
# Get any ifnull token limits from either the source or target system.
|
|
1365
|
+
# Most engines have no requirement for limits and will return an empty dict.
|
|
1366
|
+
string_column_ifnull_limits = {}
|
|
1367
|
+
self._string_column_ifnull_limits(
|
|
1368
|
+
self.source_client,
|
|
1369
|
+
casefold_source_columns,
|
|
1370
|
+
source_table,
|
|
1371
|
+
self.get_source_raw_data_types(),
|
|
1372
|
+
string_column_ifnull_limits,
|
|
1373
|
+
)
|
|
1374
|
+
self._string_column_ifnull_limits(
|
|
1375
|
+
self.target_client,
|
|
1376
|
+
casefold_target_columns,
|
|
1377
|
+
target_table,
|
|
1378
|
+
self.get_target_raw_data_types(),
|
|
1379
|
+
string_column_ifnull_limits,
|
|
1380
|
+
)
|
|
1321
1381
|
for i, calc in enumerate(self._get_order_of_operations(calc_type)):
|
|
1322
1382
|
if i == 0:
|
|
1323
1383
|
previous_level = [x for x in casefold_source_columns.keys()]
|
|
@@ -1331,7 +1391,7 @@ class ConfigManager(object):
|
|
|
1331
1391
|
col["calc_type"] = calc
|
|
1332
1392
|
col["depth"] = i
|
|
1333
1393
|
name = col["name"]
|
|
1334
|
-
#
|
|
1394
|
+
# Need to capture all aliases at the previous level. probably name concat__all
|
|
1335
1395
|
column_aliases[name] = i
|
|
1336
1396
|
col_names.append(col)
|
|
1337
1397
|
else:
|
|
@@ -1343,6 +1403,16 @@ class ConfigManager(object):
|
|
|
1343
1403
|
col["name"] = self._prefix_calc_col_name(column, calc, j)
|
|
1344
1404
|
col["calc_type"] = calc
|
|
1345
1405
|
col["depth"] = i
|
|
1406
|
+
if (
|
|
1407
|
+
calc == consts.CALC_FIELD_IFNULL
|
|
1408
|
+
and string_column_ifnull_limits.get(column)
|
|
1409
|
+
):
|
|
1410
|
+
# Trim the replacement token to the max length allowed for the column.
|
|
1411
|
+
col["calc_params"] = {
|
|
1412
|
+
consts.CALC_FIELD_IFNULL_DEFAULT: consts.CALC_FIELD_IFNULL_DEFAULT_STRING[
|
|
1413
|
+
0 : string_column_ifnull_limits[column]
|
|
1414
|
+
]
|
|
1415
|
+
}
|
|
1346
1416
|
|
|
1347
1417
|
if i == 0:
|
|
1348
1418
|
# If depth 0, get raw column name with correct casing
|
|
@@ -1363,6 +1433,11 @@ class ConfigManager(object):
|
|
|
1363
1433
|
name = col["name"]
|
|
1364
1434
|
column_aliases[name] = i
|
|
1365
1435
|
col_names.append(col)
|
|
1436
|
+
if string_column_ifnull_limits.get(column):
|
|
1437
|
+
# Keep track of column limits as we move through aliased expressions.
|
|
1438
|
+
string_column_ifnull_limits[name] = string_column_ifnull_limits[
|
|
1439
|
+
column
|
|
1440
|
+
]
|
|
1366
1441
|
return col_names
|
|
1367
1442
|
|
|
1368
1443
|
def build_comp_fields(self, col_list: list, exclude_cols: bool) -> dict:
|
{google_pso_data_validator-8.3.0 → google_pso_data_validator-8.5.0}/data_validation/consts.py
RENAMED
|
@@ -139,6 +139,7 @@ SOURCE_TYPE_POSTGRES = "Postgres"
|
|
|
139
139
|
SOURCE_TYPE_REDSHIFT = "Redshift"
|
|
140
140
|
SOURCE_TYPE_SNOWFLAKE = "Snowflake"
|
|
141
141
|
SOURCE_TYPE_SPANNER = "Spanner"
|
|
142
|
+
SOURCE_TYPE_SYBASE = "Sybase"
|
|
142
143
|
SOURCE_TYPE_TERADATA = "Teradata"
|
|
143
144
|
|
|
144
145
|
# BigQuery Result Handler Configs
|
|
@@ -149,6 +150,7 @@ TABLE_ID = "table_id"
|
|
|
149
150
|
GOOGLE_SERVICE_ACCOUNT_KEY_PATH = "google_service_account_key_path"
|
|
150
151
|
API_ENDPOINT = "api_endpoint"
|
|
151
152
|
STORAGE_API_ENDPOINT = "storage_api_endpoint"
|
|
153
|
+
CLIENT_PROJECT_ID = "client_project_id"
|
|
152
154
|
|
|
153
155
|
# Result Handler Output Table Fields
|
|
154
156
|
VALIDATION_TYPE = "validation_type"
|
|
@@ -258,7 +260,12 @@ CALC_FIELD_BYTE_LENGTH = "byte_length"
|
|
|
258
260
|
CALC_FIELD_EPOCH_SECONDS = "epoch_seconds"
|
|
259
261
|
CALC_FIELD_HASH = "hash"
|
|
260
262
|
CALC_FIELD_IFNULL = "ifnull"
|
|
263
|
+
CALC_FIELD_IFNULL_DEFAULT = "default_null_string"
|
|
264
|
+
CALC_FIELD_IFNULL_DEFAULT_STRING = "DEFAULT_REPLACEMENT_STRING"
|
|
261
265
|
CALC_FIELD_LENGTH = "length"
|
|
262
266
|
CALC_FIELD_PADDED_CHAR_LENGTH = "padded_char_length"
|
|
263
267
|
CALC_FIELD_RSTRIP = "rstrip"
|
|
264
268
|
CALC_FIELD_UPPER = "upper"
|
|
269
|
+
|
|
270
|
+
# Backends that do not support window functions.
|
|
271
|
+
NO_WINDOW_FUNCTION_SUPPORT = [SOURCE_TYPE_SYBASE]
|
|
@@ -20,7 +20,7 @@ import re
|
|
|
20
20
|
import datetime
|
|
21
21
|
from typing import List, Dict, TYPE_CHECKING
|
|
22
22
|
|
|
23
|
-
from data_validation import cli_tools, consts, util
|
|
23
|
+
from data_validation import cli_tools, consts, exceptions, util
|
|
24
24
|
from data_validation.config_manager import ConfigManager
|
|
25
25
|
from data_validation.query_builder.partition_row_builder import PartitionRowBuilder
|
|
26
26
|
from data_validation.validation_builder import ValidationBuilder
|
|
@@ -105,6 +105,15 @@ class PartitionBuilder:
|
|
|
105
105
|
yaml_configs_list = self._add_partition_filters(partition_filters)
|
|
106
106
|
self._store_partitions(yaml_configs_list)
|
|
107
107
|
|
|
108
|
+
def check_partition_configs(self) -> None:
|
|
109
|
+
for config_manager in self.config_managers:
|
|
110
|
+
source_type = config_manager.get_source_connection()[consts.SOURCE_TYPE]
|
|
111
|
+
if source_type in consts.NO_WINDOW_FUNCTION_SUPPORT:
|
|
112
|
+
raise exceptions.PartitionBuilderException(
|
|
113
|
+
f"Source client {source_type} does not support window functions, "
|
|
114
|
+
"please use this connection as a target connection for generate-table-partitions."
|
|
115
|
+
)
|
|
116
|
+
|
|
108
117
|
@staticmethod
|
|
109
118
|
def _extract_where(table_expr: "IbisTable", client: "BaseBackend") -> str:
|
|
110
119
|
"""Given a ibis table expression with a filter (i.e. WHERE) clause, this function extracts the
|
|
@@ -341,7 +341,10 @@ class CalculatedField(object):
|
|
|
341
341
|
@staticmethod
|
|
342
342
|
def ifnull(config, fields):
|
|
343
343
|
default_null_string = ibis.literal(
|
|
344
|
-
config.get(
|
|
344
|
+
config.get(
|
|
345
|
+
consts.CALC_FIELD_IFNULL_DEFAULT,
|
|
346
|
+
consts.CALC_FIELD_IFNULL_DEFAULT_STRING,
|
|
347
|
+
)
|
|
345
348
|
)
|
|
346
349
|
fields = [fields[0], default_null_string]
|
|
347
350
|
return CalculatedField(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-pso-data-validator
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.5.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
|
|
@@ -28,7 +28,7 @@ Requires-Dist: jellyfish>=1.1.0
|
|
|
28
28
|
Requires-Dist: pandas
|
|
29
29
|
Requires-Dist: parsy>=2.1
|
|
30
30
|
Requires-Dist: psycopg2-binary>=2.9.9
|
|
31
|
-
Requires-Dist: pyarrow
|
|
31
|
+
Requires-Dist: pyarrow
|
|
32
32
|
Requires-Dist: pydata-google-auth>=1.8.2
|
|
33
33
|
Requires-Dist: PyMySQL>=1.1.1
|
|
34
34
|
Requires-Dist: PyYAML>=6.0.2
|
|
@@ -45,6 +45,7 @@ Requires-Dist: freezegun; extra == "develop"
|
|
|
45
45
|
Requires-Dist: pyfakefs; extra == "develop"
|
|
46
46
|
Requires-Dist: pytest; extra == "develop"
|
|
47
47
|
Requires-Dist: pytest-cov; extra == "develop"
|
|
48
|
+
Requires-Dist: pytest-rerunfailures; extra == "develop"
|
|
48
49
|
Requires-Dist: pytest-timeout; extra == "develop"
|
|
49
50
|
Dynamic: author
|
|
50
51
|
Dynamic: author-email
|
|
@@ -92,8 +93,9 @@ DVT supports the following connection types:
|
|
|
92
93
|
* [Postgres](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#postgres)
|
|
93
94
|
* [Redshift](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#redshift)
|
|
94
95
|
* [Spanner](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-spanner)
|
|
95
|
-
* [Teradata](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#teradata)
|
|
96
96
|
* [Snowflake](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#snowflake)
|
|
97
|
+
* [Sybase ASE](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#sybase)
|
|
98
|
+
* [Teradata](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#teradata)
|
|
97
99
|
|
|
98
100
|
The [Connections](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md) page provides details about how to create
|
|
99
101
|
and list connections for the validation tool.
|
|
@@ -552,6 +554,10 @@ data-validation
|
|
|
552
554
|
Comma-separated key value pair labels for the run.
|
|
553
555
|
[--format or -fmt FORMAT]
|
|
554
556
|
Format for stdout output. Supported formats are (text, csv, json, table). Defaults to table.
|
|
557
|
+
[--use-random-row or -rr]
|
|
558
|
+
Finds a set of random rows of the first primary key supplied.
|
|
559
|
+
[--random-row-batch-size or -rbs]
|
|
560
|
+
Row batch size used for random row filters (default 10,000).
|
|
555
561
|
[--filter-status or -fs STATUSES_LIST]
|
|
556
562
|
Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
|
|
557
563
|
[--case-insensitive-match, -cim]
|
|
@@ -85,6 +85,11 @@ third_party/ibis/ibis_redshift/compiler.py
|
|
|
85
85
|
third_party/ibis/ibis_snowflake/__init__.py
|
|
86
86
|
third_party/ibis/ibis_snowflake/api.py
|
|
87
87
|
third_party/ibis/ibis_snowflake/datatypes.py
|
|
88
|
+
third_party/ibis/ibis_sybase/__init__.py
|
|
89
|
+
third_party/ibis/ibis_sybase/api.py
|
|
90
|
+
third_party/ibis/ibis_sybase/compiler.py
|
|
91
|
+
third_party/ibis/ibis_sybase/datatypes.py
|
|
92
|
+
third_party/ibis/ibis_sybase/registry.py
|
|
88
93
|
third_party/ibis/ibis_teradata/__init__.py
|
|
89
94
|
third_party/ibis/ibis_teradata/api.py
|
|
90
95
|
third_party/ibis/ibis_teradata/compiler.py
|