google-pso-data-validator 8.5.2__tar.gz → 8.7.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.5.2/google_pso_data_validator.egg-info → google_pso_data_validator-8.7.0}/PKG-INFO +15 -4
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/README.md +13 -2
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/__init__.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/cli_tools.py +26 -9
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/client_info.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/clients.py +23 -11
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/config_manager.py +41 -2
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/consts.py +2 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/find_tables.py +34 -10
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/gcs_helper.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/query_builder/random_row_builder.py +15 -3
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/result_handlers/base_backend.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/result_handlers/bigquery.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/result_handlers/postgres.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/schema_validation.py +4 -2
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/util.py +17 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0/google_pso_data_validator.egg-info}/PKG-INFO +15 -4
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/google_pso_data_validator.egg-info/SOURCES.txt +5 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/google_pso_data_validator.egg-info/requires.txt +1 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/setup.py +2 -2
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_addon/api.py +44 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_addon/operations.py +34 -71
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -1
- google_pso_data_validator-8.7.0/third_party/ibis/ibis_db2/__init__.py +271 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_db2/api.py +11 -7
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_db2/datatypes.py +22 -6
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_db2/registry.py +44 -18
- google_pso_data_validator-8.7.0/third_party/ibis/ibis_db2_zos/__init__.py +84 -0
- google_pso_data_validator-8.7.0/third_party/ibis/ibis_db2_zos/api.py +45 -0
- google_pso_data_validator-8.7.0/third_party/ibis/ibis_db2_zos/compiler.py +27 -0
- google_pso_data_validator-8.7.0/third_party/ibis/ibis_db2_zos/registry.py +105 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_impala/api.py +3 -1
- google_pso_data_validator-8.7.0/third_party/ibis/ibis_impala/registry.py +70 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mssql/__init__.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_oracle/__init__.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_oracle/datatypes.py +3 -3
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_postgres/registry.py +6 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_redshift/__init__.py +16 -9
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_sybase/__init__.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_sybase/datatypes.py +0 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_teradata/__init__.py +3 -3
- google_pso_data_validator-8.5.2/third_party/ibis/ibis_db2/__init__.py +0 -172
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/LICENSE +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/__main__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/app.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/combiner.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/data_validation.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/exceptions.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/jellyfish_distance.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/metadata.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/partition_builder.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/query_builder/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/query_builder/partition_row_builder.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/query_builder/query_builder.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/raw_query.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/result_handlers/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/result_handlers/factory.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/result_handlers/text.py +1 -1
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/secret_manager.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/state_manager.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/validation_builder.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/setup.cfg +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_bigquery/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_bigquery/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_bigquery/registry.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_db2/compiler.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_impala/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mssql/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mssql/registry.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mysql/base_sql_compiler/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mysql/base_sql_compiler/select_builder.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_oracle/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_oracle/registry.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_postgres/client.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_postgres/datatypes.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_redshift/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_snowflake/__init__.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_snowflake/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_sybase/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_sybase/compiler.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_sybase/registry.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_teradata/api.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/third_party/ibis/ibis_teradata/datatypes.py +0 -0
- {google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.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.7.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
|
|
@@ -39,7 +39,7 @@ Requires-Dist: 1.10.11; extra == "apache-airflow"
|
|
|
39
39
|
Provides-Extra: pyspark
|
|
40
40
|
Requires-Dist: 3.0.0; extra == "pyspark"
|
|
41
41
|
Provides-Extra: develop
|
|
42
|
-
Requires-Dist: black==
|
|
42
|
+
Requires-Dist: black==26.1.0; extra == "develop"
|
|
43
43
|
Requires-Dist: flake8; extra == "develop"
|
|
44
44
|
Requires-Dist: freezegun; extra == "develop"
|
|
45
45
|
Requires-Dist: pyfakefs; extra == "develop"
|
|
@@ -83,7 +83,8 @@ DVT supports the following connection types:
|
|
|
83
83
|
|
|
84
84
|
* [AlloyDB](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#alloydb)
|
|
85
85
|
* [BigQuery](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-bigquery)
|
|
86
|
-
* [
|
|
86
|
+
* [Db2 LUW](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#db2_luw)
|
|
87
|
+
* [Db2 z/OS](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#db2_zos)
|
|
87
88
|
* [FileSystem](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#filesystem)
|
|
88
89
|
* [Hive](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#hive)
|
|
89
90
|
* [Impala](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#impala)
|
|
@@ -130,7 +131,7 @@ The CLI is the main interface to use this tool and it has several different
|
|
|
130
131
|
commands which can be used to create and run validations. DVT is designed to run in
|
|
131
132
|
an environment connected to GCP services, specifically, BigQuery, GCS and Secret manager.
|
|
132
133
|
If DVT is being run on-premises or in an environment with restricted access to GCP services, see
|
|
133
|
-
[running DVT
|
|
134
|
+
[running DVT at on-prem](#running-dvt-at-on-prem). Below are the command syntax and options for running validations.
|
|
134
135
|
|
|
135
136
|
Alternatives to running DVT in the CLI include deploying DVT to Cloud Run, Cloud Functions, or Airflow
|
|
136
137
|
([Examples Here](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples)). See the [Validation Logic](https://github.com/GoogleCloudPlatform/professional-services-data-validator#validation-logic) section
|
|
@@ -719,17 +720,27 @@ target. The `find-tables` command:
|
|
|
719
720
|
- Pulls all tables in the source (applying a supplied `allowed-schemas` filter)
|
|
720
721
|
- Pulls all tables from the target
|
|
721
722
|
- Uses Jaro Similarity algorithm to match tables
|
|
723
|
+
- Optionally translates source schema names using mappings supplied in `allowed-schemas` before matching
|
|
722
724
|
- Finally, it prints a JSON list of tables which can be a reference for the
|
|
723
725
|
validation run config.
|
|
724
726
|
|
|
725
727
|
Note that our default value for the `score-cutoff` parameter is 1 and it seeks for identical matches. If no matches occur, reduce this value as deemed necessary. By using smaller numbers such as 0.7, 0.65 etc you can get more matches. For reference, we make use of [this jaro_similarity method](https://jamesturk.github.io/jellyfish/functions/#jaro-similarity) for the string comparison.
|
|
726
728
|
|
|
729
|
+
|
|
727
730
|
```shell
|
|
728
731
|
data-validation find-tables --source-conn source --target-conn target \
|
|
729
732
|
--allowed-schemas pso_data_validator \
|
|
730
733
|
--score-cutoff 1
|
|
731
734
|
```
|
|
732
735
|
|
|
736
|
+
If your source and target environments have different schema names (e.g., `prod_raw` vs `dwh_raw`), you can provide a mapping directly in the `--allowed-schemas` flag using the `source_schema=target_schema` syntax.
|
|
737
|
+
|
|
738
|
+
```shell
|
|
739
|
+
data-validation find-tables --source-conn source --target-conn target \
|
|
740
|
+
--allowed-schemas prod=dwh \
|
|
741
|
+
--score-cutoff 1
|
|
742
|
+
```
|
|
743
|
+
|
|
733
744
|
### Using Beta CLI Features
|
|
734
745
|
|
|
735
746
|
There may be occasions we want to release a new CLI feature under a Beta flag.
|
|
@@ -23,7 +23,8 @@ DVT supports the following connection types:
|
|
|
23
23
|
|
|
24
24
|
* [AlloyDB](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#alloydb)
|
|
25
25
|
* [BigQuery](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#google-bigquery)
|
|
26
|
-
* [
|
|
26
|
+
* [Db2 LUW](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#db2_luw)
|
|
27
|
+
* [Db2 z/OS](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#db2_zos)
|
|
27
28
|
* [FileSystem](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#filesystem)
|
|
28
29
|
* [Hive](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#hive)
|
|
29
30
|
* [Impala](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/connections.md#impala)
|
|
@@ -70,7 +71,7 @@ The CLI is the main interface to use this tool and it has several different
|
|
|
70
71
|
commands which can be used to create and run validations. DVT is designed to run in
|
|
71
72
|
an environment connected to GCP services, specifically, BigQuery, GCS and Secret manager.
|
|
72
73
|
If DVT is being run on-premises or in an environment with restricted access to GCP services, see
|
|
73
|
-
[running DVT
|
|
74
|
+
[running DVT at on-prem](#running-dvt-at-on-prem). Below are the command syntax and options for running validations.
|
|
74
75
|
|
|
75
76
|
Alternatives to running DVT in the CLI include deploying DVT to Cloud Run, Cloud Functions, or Airflow
|
|
76
77
|
([Examples Here](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples)). See the [Validation Logic](https://github.com/GoogleCloudPlatform/professional-services-data-validator#validation-logic) section
|
|
@@ -659,17 +660,27 @@ target. The `find-tables` command:
|
|
|
659
660
|
- Pulls all tables in the source (applying a supplied `allowed-schemas` filter)
|
|
660
661
|
- Pulls all tables from the target
|
|
661
662
|
- Uses Jaro Similarity algorithm to match tables
|
|
663
|
+
- Optionally translates source schema names using mappings supplied in `allowed-schemas` before matching
|
|
662
664
|
- Finally, it prints a JSON list of tables which can be a reference for the
|
|
663
665
|
validation run config.
|
|
664
666
|
|
|
665
667
|
Note that our default value for the `score-cutoff` parameter is 1 and it seeks for identical matches. If no matches occur, reduce this value as deemed necessary. By using smaller numbers such as 0.7, 0.65 etc you can get more matches. For reference, we make use of [this jaro_similarity method](https://jamesturk.github.io/jellyfish/functions/#jaro-similarity) for the string comparison.
|
|
666
668
|
|
|
669
|
+
|
|
667
670
|
```shell
|
|
668
671
|
data-validation find-tables --source-conn source --target-conn target \
|
|
669
672
|
--allowed-schemas pso_data_validator \
|
|
670
673
|
--score-cutoff 1
|
|
671
674
|
```
|
|
672
675
|
|
|
676
|
+
If your source and target environments have different schema names (e.g., `prod_raw` vs `dwh_raw`), you can provide a mapping directly in the `--allowed-schemas` flag using the `source_schema=target_schema` syntax.
|
|
677
|
+
|
|
678
|
+
```shell
|
|
679
|
+
data-validation find-tables --source-conn source --target-conn target \
|
|
680
|
+
--allowed-schemas prod=dwh \
|
|
681
|
+
--score-cutoff 1
|
|
682
|
+
```
|
|
683
|
+
|
|
673
684
|
### Using Beta CLI Features
|
|
674
685
|
|
|
675
686
|
There may be occasions we want to release a new CLI feature under a Beta flag.
|
{google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/cli_tools.py
RENAMED
|
@@ -75,9 +75,13 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
75
75
|
["project_id", "GCP Project to use for BigQuery"],
|
|
76
76
|
[
|
|
77
77
|
"client_project_id",
|
|
78
|
-
"(
|
|
78
|
+
"(Deprecated) BigQuery job/billing project (can differ from data project)",
|
|
79
79
|
],
|
|
80
|
-
[
|
|
80
|
+
[
|
|
81
|
+
"billing_project_id",
|
|
82
|
+
"(Optional) BigQuery billing project to override default billing project",
|
|
83
|
+
],
|
|
84
|
+
["google_service_account_key_path", "(Deprecated) GCP SA Key Path"],
|
|
81
85
|
[
|
|
82
86
|
"api_endpoint",
|
|
83
87
|
'(Optional) GCP BigQuery API endpoint (e.g. "https://bigquery-mypsc.p.googleapis.com")',
|
|
@@ -149,7 +153,7 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
149
153
|
["project_id", "GCP Project to use for Spanner"],
|
|
150
154
|
["instance_id", "ID of Spanner instance to connect to"],
|
|
151
155
|
["database_id", "ID of Spanner database (schema) to connect to"],
|
|
152
|
-
["google_service_account_key_path", "(
|
|
156
|
+
["google_service_account_key_path", "(Deprecated) GCP SA Key Path"],
|
|
153
157
|
[
|
|
154
158
|
"api_endpoint",
|
|
155
159
|
'(Optional) GCP Spanner API endpoint (e.g. "https://spanner-mypsc.p.googleapis.com")',
|
|
@@ -199,13 +203,24 @@ CONNECTION_SOURCE_FIELDS = {
|
|
|
199
203
|
["http_path", "URL path of HTTP proxy"],
|
|
200
204
|
],
|
|
201
205
|
consts.SOURCE_TYPE_DB2: [
|
|
202
|
-
["host", "
|
|
203
|
-
["port", "
|
|
206
|
+
["host", "Db2 host"],
|
|
207
|
+
["port", "Db2 port (50000 if not provided)"],
|
|
204
208
|
["user", "Username to connect to"],
|
|
205
209
|
["password", "Password for authentication of user"],
|
|
206
|
-
["database", "Database in
|
|
207
|
-
["url", "URL link in
|
|
208
|
-
["driver", "Driver link in
|
|
210
|
+
["database", "Database in Db2 to connect to"],
|
|
211
|
+
["url", "URL link in Db2 to connect to"],
|
|
212
|
+
["driver", "Driver link in Db2 to connect to (default ibm_db_sa)"],
|
|
213
|
+
["connect_args", "(Optional) Additional connection argument mapping"],
|
|
214
|
+
],
|
|
215
|
+
consts.SOURCE_TYPE_DB2_ZOS: [
|
|
216
|
+
["host", "Db2 host"],
|
|
217
|
+
["port", "Db2 port (50000 if not provided)"],
|
|
218
|
+
["user", "Username to connect to"],
|
|
219
|
+
["password", "Password for authentication of user"],
|
|
220
|
+
["database", "Database in Db2 to connect to"],
|
|
221
|
+
["url", "URL link in Db2 to connect to"],
|
|
222
|
+
["driver", "Driver link in Db2 to connect to (default ibm_db_sa)"],
|
|
223
|
+
["connect_args", "(Optional) Additional connection argument mapping"],
|
|
209
224
|
],
|
|
210
225
|
}
|
|
211
226
|
|
|
@@ -404,7 +419,9 @@ def _configure_find_tables(subparsers):
|
|
|
404
419
|
"--target-conn", "-tc", help="Target connection name."
|
|
405
420
|
)
|
|
406
421
|
find_tables_parser.add_argument(
|
|
407
|
-
"--allowed-schemas",
|
|
422
|
+
"--allowed-schemas",
|
|
423
|
+
"-as",
|
|
424
|
+
help="List of source schemas to match. Can include mappings like 'source_schema=target_schema'.",
|
|
408
425
|
)
|
|
409
426
|
find_tables_parser.add_argument(
|
|
410
427
|
"--include-views",
|
{google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/clients.py
RENAMED
|
@@ -53,6 +53,7 @@ IBIS_ALCHEMY_BACKENDS = [
|
|
|
53
53
|
"oracle",
|
|
54
54
|
"postgres",
|
|
55
55
|
"db2",
|
|
56
|
+
"db2_zos",
|
|
56
57
|
"mssql",
|
|
57
58
|
"redshift",
|
|
58
59
|
"snowflake",
|
|
@@ -91,8 +92,10 @@ except ImportError:
|
|
|
91
92
|
# DB2 requires ibm_db_sa
|
|
92
93
|
try:
|
|
93
94
|
from third_party.ibis.ibis_db2.api import db2_connect
|
|
95
|
+
from third_party.ibis.ibis_db2_zos.api import db2_zos_connect
|
|
94
96
|
except ImportError:
|
|
95
97
|
db2_connect = _raise_missing_client_error("pip install ibm_db_sa")
|
|
98
|
+
db2_zos_connect = _raise_missing_client_error("pip install ibm_db_sa")
|
|
96
99
|
|
|
97
100
|
# Sybase requires sqlalchemy_sybase package.
|
|
98
101
|
try:
|
|
@@ -111,15 +114,13 @@ def get_google_bigquery_client(
|
|
|
111
114
|
job_config = bigquery.QueryJobConfig(
|
|
112
115
|
connection_properties=[bigquery.ConnectionProperty("time_zone", "UTC")]
|
|
113
116
|
)
|
|
114
|
-
effective_project = quota_project_id or project_id
|
|
115
117
|
options = None
|
|
116
118
|
if api_endpoint or quota_project_id:
|
|
117
119
|
options = client_options.ClientOptions(
|
|
118
120
|
api_endpoint=api_endpoint,
|
|
119
|
-
quota_project_id=quota_project_id if quota_project_id else None,
|
|
120
121
|
)
|
|
121
122
|
return bigquery.Client(
|
|
122
|
-
project=
|
|
123
|
+
project=quota_project_id,
|
|
123
124
|
client_info=info,
|
|
124
125
|
credentials=credentials,
|
|
125
126
|
default_query_job_config=job_config,
|
|
@@ -136,7 +137,6 @@ def _get_google_bqstorage_client(
|
|
|
136
137
|
if api_endpoint or quota_project_id:
|
|
137
138
|
options = client_options.ClientOptions(
|
|
138
139
|
api_endpoint=api_endpoint,
|
|
139
|
-
quota_project_id=quota_project_id if quota_project_id else None,
|
|
140
140
|
)
|
|
141
141
|
from google.cloud import bigquery_storage_v1 as bigquery_storage
|
|
142
142
|
|
|
@@ -152,20 +152,26 @@ def get_bigquery_client(
|
|
|
152
152
|
credentials=None,
|
|
153
153
|
api_endpoint: Optional[str] = None,
|
|
154
154
|
storage_api_endpoint: Optional[str] = None,
|
|
155
|
-
client_project_id: Optional[str] = None,
|
|
155
|
+
client_project_id: Optional[str] = None, # to be deprecated in the future
|
|
156
|
+
billing_project_id: Optional[str] = None,
|
|
156
157
|
):
|
|
158
|
+
if client_project_id:
|
|
159
|
+
logging.warning(
|
|
160
|
+
"client_project_id is deprecated and will be removed in the future, use --billing-project-id instead"
|
|
161
|
+
)
|
|
162
|
+
billing_project_id = client_project_id
|
|
157
163
|
google_client = get_google_bigquery_client(
|
|
158
164
|
project_id,
|
|
159
165
|
credentials=credentials,
|
|
160
166
|
api_endpoint=api_endpoint,
|
|
161
|
-
quota_project_id=
|
|
167
|
+
quota_project_id=billing_project_id,
|
|
162
168
|
)
|
|
163
169
|
bqstorage_client = None
|
|
164
170
|
if storage_api_endpoint:
|
|
165
171
|
bqstorage_client = _get_google_bqstorage_client(
|
|
166
172
|
credentials=credentials,
|
|
167
173
|
api_endpoint=storage_api_endpoint,
|
|
168
|
-
quota_project_id=
|
|
174
|
+
quota_project_id=billing_project_id,
|
|
169
175
|
)
|
|
170
176
|
|
|
171
177
|
return bigquery_connect(
|
|
@@ -227,6 +233,7 @@ def get_ibis_table(client, schema_name, table_name, database_name=None):
|
|
|
227
233
|
"oracle",
|
|
228
234
|
"postgres",
|
|
229
235
|
"db2",
|
|
236
|
+
"db2_zos",
|
|
230
237
|
"mssql",
|
|
231
238
|
"redshift",
|
|
232
239
|
"sybase",
|
|
@@ -342,10 +349,14 @@ def get_data_client(connection_config):
|
|
|
342
349
|
consts.GOOGLE_SERVICE_ACCOUNT_KEY_PATH
|
|
343
350
|
)
|
|
344
351
|
if key_path:
|
|
345
|
-
|
|
346
|
-
"
|
|
347
|
-
|
|
348
|
-
|
|
352
|
+
logging.warning(
|
|
353
|
+
""""Use of Service Account Keys is strongly discouraged. This option is deprecated and may be removed.
|
|
354
|
+
Run DVT with the service account identity by using application-default-credentials with --impersonate-service-account"""
|
|
355
|
+
)
|
|
356
|
+
decrypted_connection_config["credentials"] = (
|
|
357
|
+
google.oauth2.service_account.Credentials.from_service_account_file(
|
|
358
|
+
key_path
|
|
359
|
+
)
|
|
349
360
|
)
|
|
350
361
|
|
|
351
362
|
if source_type not in CLIENT_LOOKUP:
|
|
@@ -430,4 +441,5 @@ CLIENT_LOOKUP = {
|
|
|
430
441
|
consts.SOURCE_TYPE_SPANNER: spanner_connect,
|
|
431
442
|
consts.SOURCE_TYPE_SYBASE: sybase_connect,
|
|
432
443
|
consts.SOURCE_TYPE_DB2: db2_connect,
|
|
444
|
+
consts.SOURCE_TYPE_DB2_ZOS: db2_zos_connect,
|
|
433
445
|
}
|
|
@@ -667,12 +667,34 @@ class ConfigManager(object):
|
|
|
667
667
|
isinstance(source_type, dt.UUID) or isinstance(target_type, dt.UUID)
|
|
668
668
|
)
|
|
669
669
|
|
|
670
|
+
def _is_db2_blob(self, source_column_name: str, target_column_name: str) -> bool:
|
|
671
|
+
"""Returns True when either source or target column is Db2 (LUW and z/OS) BLOB data type."""
|
|
672
|
+
return self._is_raw_data_type(
|
|
673
|
+
"db2", source_column_name, target_column_name, ["BLOB"]
|
|
674
|
+
) or self._is_raw_data_type(
|
|
675
|
+
"db2_zos", source_column_name, target_column_name, ["BLOB"]
|
|
676
|
+
)
|
|
677
|
+
|
|
670
678
|
def _is_db2_xml(self, source_column_name: str, target_column_name: str) -> bool:
|
|
671
|
-
"""Returns True when either source or target column is
|
|
679
|
+
"""Returns True when either source or target column is Db2 XML data type."""
|
|
672
680
|
return self._is_raw_data_type(
|
|
673
681
|
"db2", source_column_name, target_column_name, ["XML"]
|
|
674
682
|
)
|
|
675
683
|
|
|
684
|
+
def _is_db2_zos_blob(
|
|
685
|
+
self, source_column_name: str, target_column_name: str
|
|
686
|
+
) -> bool:
|
|
687
|
+
"""Returns True when either source or target column is Db2 z/OS BLOB data type."""
|
|
688
|
+
return self._is_raw_data_type(
|
|
689
|
+
"db2_zos", source_column_name, target_column_name, ["BLOB"]
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
def _is_db2_zos_xml(self, source_column_name: str, target_column_name: str) -> bool:
|
|
693
|
+
"""Returns True when either source or target column is Db2 z/OS XML data type."""
|
|
694
|
+
return self._is_raw_data_type(
|
|
695
|
+
"db2_zos", source_column_name, target_column_name, ["XML"]
|
|
696
|
+
)
|
|
697
|
+
|
|
676
698
|
def _is_oracle_lob(self, source_column_name: str, target_column_name: str) -> bool:
|
|
677
699
|
"""Returns True when either source or target column is Oracle LOB data type.
|
|
678
700
|
|
|
@@ -1058,7 +1080,11 @@ class ConfigManager(object):
|
|
|
1058
1080
|
# Oracle BLOB is invalid for use with SQL COUNT function.
|
|
1059
1081
|
# The expression below returns True if client is Oracle which
|
|
1060
1082
|
# has the effect of triggering use of byte_length transformation.
|
|
1061
|
-
|
|
1083
|
+
# Same for Db2 z/OS.
|
|
1084
|
+
return bool(
|
|
1085
|
+
self._is_oracle_lob(source_column, target_column)
|
|
1086
|
+
or self._is_db2_zos_blob(source_column, target_column)
|
|
1087
|
+
)
|
|
1062
1088
|
else:
|
|
1063
1089
|
# Convert to length for any min/max/sum on binary columns.
|
|
1064
1090
|
return True
|
|
@@ -1146,6 +1172,11 @@ class ConfigManager(object):
|
|
|
1146
1172
|
f"Skipping {agg_type} on {column} due to SQL Server image data type"
|
|
1147
1173
|
)
|
|
1148
1174
|
continue
|
|
1175
|
+
elif self._is_db2_zos_xml(column, column):
|
|
1176
|
+
logging.info(
|
|
1177
|
+
f"Skipping {agg_type} on {column} due to Db2 z/OS XML data type"
|
|
1178
|
+
)
|
|
1179
|
+
continue
|
|
1149
1180
|
elif agg_type != "count" and self._is_db2_xml(column, column):
|
|
1150
1181
|
logging.info(
|
|
1151
1182
|
f"Skipping {agg_type} on {column} due to Db2 XML data type"
|
|
@@ -1351,6 +1382,14 @@ class ConfigManager(object):
|
|
|
1351
1382
|
)
|
|
1352
1383
|
result_source_columns.pop(source_column)
|
|
1353
1384
|
result_target_columns.pop(target_column)
|
|
1385
|
+
if self._is_db2_blob(source_column, target_column):
|
|
1386
|
+
# Db2 BLOB is incompatible with Db2s own HEX function.
|
|
1387
|
+
# Users would need to use a custom query to a custom UDF to row validate these.
|
|
1388
|
+
logging.info(
|
|
1389
|
+
f"Skipping column {source_column} due to Db2 BLOB data type"
|
|
1390
|
+
)
|
|
1391
|
+
result_source_columns.pop(source_column)
|
|
1392
|
+
result_target_columns.pop(target_column)
|
|
1354
1393
|
|
|
1355
1394
|
return result_source_columns, result_target_columns
|
|
1356
1395
|
|
{google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/consts.py
RENAMED
|
@@ -130,6 +130,7 @@ YAML_VALIDATIONS = "validations"
|
|
|
130
130
|
# Connection key constants.
|
|
131
131
|
SOURCE_TYPE_BIGQUERY = "BigQuery"
|
|
132
132
|
SOURCE_TYPE_DB2 = "DB2"
|
|
133
|
+
SOURCE_TYPE_DB2_ZOS = "DB2_ZOS"
|
|
133
134
|
SOURCE_TYPE_FILESYSTEM = "FileSystem"
|
|
134
135
|
SOURCE_TYPE_IMPALA = "Impala"
|
|
135
136
|
SOURCE_TYPE_MSSQL = "MSSQL"
|
|
@@ -151,6 +152,7 @@ GOOGLE_SERVICE_ACCOUNT_KEY_PATH = "google_service_account_key_path"
|
|
|
151
152
|
API_ENDPOINT = "api_endpoint"
|
|
152
153
|
STORAGE_API_ENDPOINT = "storage_api_endpoint"
|
|
153
154
|
CLIENT_PROJECT_ID = "client_project_id"
|
|
155
|
+
BILLING_PROJECT_ID = "billing_project_id"
|
|
154
156
|
|
|
155
157
|
# Result Handler Output Table Fields
|
|
156
158
|
VALIDATION_TYPE = "validation_type"
|
{google_pso_data_validator-8.5.2 → google_pso_data_validator-8.7.0}/data_validation/find_tables.py
RENAMED
|
@@ -28,26 +28,37 @@ if TYPE_CHECKING:
|
|
|
28
28
|
import ibis
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def _compare_match_tables(
|
|
31
|
+
def _compare_match_tables(
|
|
32
|
+
source_table_map: dict,
|
|
33
|
+
target_table_map: dict,
|
|
34
|
+
score_cutoff: float = 0.8,
|
|
35
|
+
schema_map: dict = None,
|
|
36
|
+
) -> list:
|
|
32
37
|
"""Return dict config object from matching tables."""
|
|
33
38
|
# TODO(dhercher): evaluate if improved comparison and score cutoffs should be used.
|
|
34
39
|
table_configs = []
|
|
40
|
+
schema_map = schema_map or {}
|
|
35
41
|
|
|
36
42
|
target_keys = target_table_map.keys()
|
|
37
43
|
for source_key in source_table_map:
|
|
44
|
+
source_schema = source_table_map[source_key][consts.CONFIG_SCHEMA_NAME]
|
|
45
|
+
source_table = source_table_map[source_key][consts.CONFIG_TABLE_NAME]
|
|
46
|
+
|
|
47
|
+
# Apply schema mapping if it exists, when there is a mapping
|
|
48
|
+
# lookup_key is {mapped_schema}.{source_name} which should then
|
|
49
|
+
# find a match in target_keys.
|
|
50
|
+
lookup_schema = schema_map.get(source_schema, source_schema)
|
|
51
|
+
lookup_key = f"{lookup_schema}.{source_table}".casefold()
|
|
52
|
+
|
|
38
53
|
target_key = jellyfish_distance.extract_closest_match(
|
|
39
|
-
|
|
54
|
+
lookup_key, target_keys, score_cutoff=score_cutoff
|
|
40
55
|
)
|
|
41
56
|
if target_key is None:
|
|
42
57
|
continue
|
|
43
58
|
|
|
44
59
|
table_config = {
|
|
45
|
-
consts.CONFIG_SCHEMA_NAME:
|
|
46
|
-
|
|
47
|
-
],
|
|
48
|
-
consts.CONFIG_TABLE_NAME: source_table_map[source_key][
|
|
49
|
-
consts.CONFIG_TABLE_NAME
|
|
50
|
-
],
|
|
60
|
+
consts.CONFIG_SCHEMA_NAME: source_schema,
|
|
61
|
+
consts.CONFIG_TABLE_NAME: source_table,
|
|
51
62
|
consts.CONFIG_TARGET_SCHEMA_NAME: target_table_map[target_key][
|
|
52
63
|
consts.CONFIG_SCHEMA_NAME
|
|
53
64
|
],
|
|
@@ -95,6 +106,7 @@ def get_mapped_table_configs(
|
|
|
95
106
|
allowed_schemas: list = None,
|
|
96
107
|
include_views: bool = False,
|
|
97
108
|
score_cutoff: int = 1,
|
|
109
|
+
schema_map: dict = None,
|
|
98
110
|
) -> list:
|
|
99
111
|
"""Get table list from each client and match them together into a single list of dicts."""
|
|
100
112
|
source_table_map = _get_table_map(
|
|
@@ -102,7 +114,10 @@ def get_mapped_table_configs(
|
|
|
102
114
|
)
|
|
103
115
|
target_table_map = _get_table_map(target_client, include_views=include_views)
|
|
104
116
|
return _compare_match_tables(
|
|
105
|
-
source_table_map,
|
|
117
|
+
source_table_map,
|
|
118
|
+
target_table_map,
|
|
119
|
+
score_cutoff=score_cutoff,
|
|
120
|
+
schema_map=schema_map,
|
|
106
121
|
)
|
|
107
122
|
|
|
108
123
|
|
|
@@ -114,13 +129,22 @@ def find_tables_using_string_matching(args) -> str:
|
|
|
114
129
|
source_client = clients.get_data_client(mgr.get_connection_config(args.source_conn))
|
|
115
130
|
target_client = clients.get_data_client(mgr.get_connection_config(args.target_conn))
|
|
116
131
|
|
|
117
|
-
|
|
132
|
+
allowed_schemas_raw = cli_tools.get_arg_list(args.allowed_schemas) or []
|
|
133
|
+
allowed_schemas = []
|
|
134
|
+
schema_map = {}
|
|
135
|
+
for schema in allowed_schemas_raw:
|
|
136
|
+
if "=" in schema:
|
|
137
|
+
schema, target_schema = schema.split("=", 1)
|
|
138
|
+
schema_map[schema] = target_schema
|
|
139
|
+
allowed_schemas.append(schema)
|
|
140
|
+
|
|
118
141
|
table_configs = get_mapped_table_configs(
|
|
119
142
|
source_client,
|
|
120
143
|
target_client,
|
|
121
144
|
allowed_schemas=allowed_schemas,
|
|
122
145
|
include_views=args.include_views,
|
|
123
146
|
score_cutoff=score_cutoff,
|
|
147
|
+
schema_map=schema_map,
|
|
124
148
|
)
|
|
125
149
|
return json.dumps(table_configs)
|
|
126
150
|
|
|
@@ -19,9 +19,8 @@ import ibis
|
|
|
19
19
|
from data_validation import clients
|
|
20
20
|
from data_validation.query_builder.query_builder import QueryBuilder
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
# Adding new data sources should be done by adding the Backend name here
|
|
24
|
-
|
|
23
|
+
SUPPORTS_SORT_BY_RANDOM = [
|
|
25
24
|
"bigquery",
|
|
26
25
|
"teradata",
|
|
27
26
|
"impala",
|
|
@@ -36,6 +35,10 @@ RANDOM_SORT_SUPPORTS = [
|
|
|
36
35
|
"sybase",
|
|
37
36
|
]
|
|
38
37
|
|
|
38
|
+
SUPPORTS_SORT_BY_ALIASED_RANDOM = [
|
|
39
|
+
"db2_zos",
|
|
40
|
+
]
|
|
41
|
+
|
|
39
42
|
|
|
40
43
|
class RandomRowBuilder(object):
|
|
41
44
|
def __init__(self, primary_keys: List[str], batch_size: int):
|
|
@@ -88,7 +91,16 @@ class RandomRowBuilder(object):
|
|
|
88
91
|
self, data_client: ibis.backends.base.BaseBackend, table: ibis.Expr
|
|
89
92
|
) -> ibis.Expr:
|
|
90
93
|
"""Return a randomly sorted query if it is supported for the client."""
|
|
91
|
-
if data_client.name in
|
|
94
|
+
if data_client.name in SUPPORTS_SORT_BY_ALIASED_RANDOM:
|
|
95
|
+
random_sort_col = "random_sort"
|
|
96
|
+
return (
|
|
97
|
+
table[self.primary_keys]
|
|
98
|
+
.mutate(**{random_sort_col: ibis.random()})
|
|
99
|
+
.order_by(random_sort_col)
|
|
100
|
+
.limit(self.batch_size)[self.primary_keys]
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if data_client.name in SUPPORTS_SORT_BY_RANDOM:
|
|
92
104
|
# Teradata 'SAMPLE' and Spanner 'TABLESAMPLE' is random by nature
|
|
93
105
|
# and does not require a sort by
|
|
94
106
|
if data_client.name == "teradata" or data_client.name == "spanner":
|
|
@@ -23,7 +23,6 @@ import google.oauth2.service_account
|
|
|
23
23
|
from data_validation import clients, consts, exceptions, util
|
|
24
24
|
from data_validation.result_handlers.base_backend import BaseBackendResultHandler
|
|
25
25
|
|
|
26
|
-
|
|
27
26
|
BQRH_WRITE_MESSAGE = "Results written to BigQuery"
|
|
28
27
|
BQRH_NO_WRITE_MESSAGE = "No results to write to BigQuery"
|
|
29
28
|
|
|
@@ -20,7 +20,6 @@ import re
|
|
|
20
20
|
|
|
21
21
|
from data_validation import metadata, consts, clients, exceptions
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
# Check for decimal data type with precision and/or scale. Permits hyphen in p/s for value ranges.
|
|
25
24
|
DECIMAL_PRECISION_SCALE_PATTERN = re.compile(
|
|
26
25
|
r"([!]?decimal)\(([0-9\-]+)(?:,[ ]*([0-9\-]+))?\)", re.I
|
|
@@ -187,7 +186,10 @@ def schema_validation_matching(
|
|
|
187
186
|
)
|
|
188
187
|
else:
|
|
189
188
|
# Target data type mismatch
|
|
190
|
-
(
|
|
189
|
+
(
|
|
190
|
+
higher_precision,
|
|
191
|
+
lower_precision,
|
|
192
|
+
) = parse_n_validate_datatypes(
|
|
191
193
|
string_val(source_field_type), string_val(target_field_type)
|
|
192
194
|
)
|
|
193
195
|
if higher_precision:
|
|
@@ -16,6 +16,7 @@ import json
|
|
|
16
16
|
import logging
|
|
17
17
|
import re
|
|
18
18
|
import time
|
|
19
|
+
import uuid
|
|
19
20
|
|
|
20
21
|
from data_validation import clients, exceptions
|
|
21
22
|
|
|
@@ -87,3 +88,19 @@ def ibis_table_to_sql(ibis_table: "IbisTable", alchemy_client: "BaseBackend") ->
|
|
|
87
88
|
else:
|
|
88
89
|
sql_string = str(ibis_table.compile())
|
|
89
90
|
return sql_string
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def dvt_temp_object_name(prefix: str = "dvt_temp") -> str:
|
|
94
|
+
"""Generate a random name for when DVT needs to create a temporary object.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
prefix: The prefix to use for the temporary object name.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
A random name for when DVT needs to create a temporary object.
|
|
101
|
+
"""
|
|
102
|
+
if not isinstance(prefix, str) or not re.match(r"^[a-zA-Z0-9_]+$", prefix):
|
|
103
|
+
raise exceptions.ValidationException(
|
|
104
|
+
f"Invalid prefix: '{prefix}'. Only alphanumeric and underscore characters are allowed."
|
|
105
|
+
)
|
|
106
|
+
return f"{prefix}_{uuid.uuid4().hex[:8].lower()}"
|