google-pso-data-validator 7.7.0__tar.gz → 8.0.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.
Files changed (92) hide show
  1. {google_pso_data_validator-7.7.0/google_pso_data_validator.egg-info → google_pso_data_validator-8.0.0}/PKG-INFO +12 -10
  2. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/README.md +10 -8
  3. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/__main__.py +19 -17
  4. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/cli_tools.py +89 -37
  5. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/clients.py +13 -4
  6. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/config_manager.py +27 -27
  7. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/consts.py +6 -1
  8. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/data_validation.py +48 -5
  9. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/partition_builder.py +58 -19
  10. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/schema_validation.py +4 -2
  11. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/validation_builder.py +40 -6
  12. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0/google_pso_data_validator.egg-info}/PKG-INFO +12 -10
  13. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/google_pso_data_validator.egg-info/requires.txt +1 -1
  14. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/setup.py +2 -2
  15. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_addon/api.py +39 -2
  16. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_addon/operations.py +23 -58
  17. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +7 -10
  18. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +12 -1
  19. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_db2/__init__.py +22 -0
  20. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_impala/api.py +7 -1
  21. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mssql/__init__.py +84 -2
  22. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mssql/registry.py +58 -0
  23. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_oracle/__init__.py +48 -27
  24. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_oracle/api.py +10 -4
  25. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_oracle/datatypes.py +55 -50
  26. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_oracle/registry.py +27 -15
  27. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_postgres/client.py +2 -1
  28. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_postgres/datatypes.py +10 -0
  29. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_snowflake/api.py +2 -4
  30. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_teradata/__init__.py +7 -1
  31. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_teradata/datatypes.py +30 -0
  32. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/LICENSE +0 -0
  33. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/__init__.py +0 -0
  34. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/app.py +0 -0
  35. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/client_info.py +0 -0
  36. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/combiner.py +0 -0
  37. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/exceptions.py +0 -0
  38. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/find_tables.py +0 -0
  39. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/gcs_helper.py +0 -0
  40. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/jellyfish_distance.py +0 -0
  41. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/metadata.py +0 -0
  42. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/query_builder/__init__.py +0 -0
  43. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/query_builder/partition_row_builder.py +0 -0
  44. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/query_builder/query_builder.py +0 -0
  45. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/query_builder/random_row_builder.py +0 -0
  46. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/raw_query.py +0 -0
  47. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/result_handlers/__init__.py +0 -0
  48. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/result_handlers/base_backend.py +0 -0
  49. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/result_handlers/bigquery.py +0 -0
  50. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/result_handlers/factory.py +0 -0
  51. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/result_handlers/postgres.py +0 -0
  52. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/result_handlers/text.py +0 -0
  53. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/secret_manager.py +0 -0
  54. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/state_manager.py +0 -0
  55. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/data_validation/util.py +0 -0
  56. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/google_pso_data_validator.egg-info/SOURCES.txt +0 -0
  57. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
  58. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
  59. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
  60. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/setup.cfg +0 -0
  61. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
  62. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_bigquery/__init__.py +0 -0
  63. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_bigquery/api.py +0 -0
  64. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
  65. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
  66. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -0
  67. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
  68. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
  69. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
  70. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
  71. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_db2/api.py +0 -0
  72. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_db2/compiler.py +0 -0
  73. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_db2/datatypes.py +0 -0
  74. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_db2/registry.py +0 -0
  75. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_impala/__init__.py +0 -0
  76. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mssql/api.py +0 -0
  77. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
  78. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
  79. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mysql/base_sql_compiler/__init__.py +0 -0
  80. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mysql/base_sql_compiler/select_builder.py +0 -0
  81. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
  82. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
  83. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
  84. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_postgres/registry.py +0 -0
  85. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_redshift/__init__.py +0 -0
  86. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_redshift/api.py +0 -0
  87. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
  88. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_snowflake/__init__.py +0 -0
  89. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
  90. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_teradata/api.py +0 -0
  91. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
  92. {google_pso_data_validator-7.7.0 → google_pso_data_validator-8.0.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: 7.7.0
3
+ Version: 8.0.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
@@ -32,7 +32,7 @@ Requires-Dist: pyarrow==14.0.1
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
35
- Requires-Dist: SQLAlchemy==1.4.49
35
+ Requires-Dist: SQLAlchemy==2.0.41
36
36
  Requires-Dist: tabulate>=0.9.0
37
37
  Provides-Extra: apache-airflow
38
38
  Requires-Dist: 1.10.11; extra == "apache-airflow"
@@ -171,7 +171,9 @@ data-validation
171
171
  [--min COLUMNS] Comma separated list of columns for min or * for all numeric
172
172
  [--max COLUMNS] Comma separated list of columns for max or * for all numeric
173
173
  [--avg COLUMNS] Comma separated list of columns for avg or * for all numeric
174
- [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric
174
+ [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric.
175
+ Please note that not all supported SQL engines give results from STDDV_SAMP (or engine specific equivalent) that
176
+ are comparable across all other supported SQL engines. This option may produce unreliable results.
175
177
  [--exclude-columns or -ec]
176
178
  Flag to indicate the list of columns provided should be excluded and not included.
177
179
  [--result-handler or -rh CONNECTION_NAME.SCHEMA.TABLE or BQ_PROJECT_ID.DATASET.TABLE]
@@ -256,6 +258,8 @@ data-validation
256
258
  See: *Calculated Fields* section for details
257
259
  --hash COLUMNS Comma separated list of columns to hash or * for all columns
258
260
  --concat COLUMNS Comma separated list of columns to concatenate or * for all columns (use if a common hash function is not available between databases)
261
+ --max-concat-columns INT, -mcc INT
262
+ Maximum number of columns used in one --hash or --concat validation. When there are more columns in the validation, the validation will be split into multiple validations. There are engine specific defaults, so most users do not need to use this option unless they encounter errors.
259
263
  [--primary-keys PRIMARY_KEYS, -pk PRIMARY_KEYS]
260
264
  Comma separated list of primary key columns, when not specified the value will be inferred
261
265
  from the source or target table if available. See *Primary Keys* section
@@ -288,8 +292,6 @@ data-validation
288
292
  Row batch size used for random row filters (default 10,000).
289
293
  [--filter-status or -fs STATUSES_LIST]
290
294
  Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
291
- [--trim-string-pks, -tsp]
292
- Trims string based primary key values, intended for use when one engine uses padded string semantics (e.g. CHAR(n)) and the other does not (e.g. VARCHAR(n)).
293
295
  [--case-insensitive-match, -cim]
294
296
  Performs a case insensitive match by adding an UPPER() before comparison.
295
297
  ```
@@ -365,8 +367,6 @@ data-validation
365
367
  Format for stdout output. Supported formats are (text, csv, json, table). Defaults to table.
366
368
  [--filter-status or -fs STATUSES_LIST]
367
369
  Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
368
- [--trim-string-pks, -tsp]
369
- Trims string based primary key values, intended for use when one engine uses padded string semantics (e.g. CHAR(n)) and the other does not (e.g. VARCHAR(n)).
370
370
  [--case-insensitive-match, -cim]
371
371
  Performs a case insensitive match by adding an UPPER() before comparison.
372
372
  ```
@@ -454,7 +454,9 @@ data-validation
454
454
  [--min COLUMNS] Comma separated list of columns for min or * for all numeric
455
455
  [--max COLUMNS] Comma separated list of columns for max or * for all numeric
456
456
  [--avg COLUMNS] Comma separated list of columns for avg or * for all numeric
457
- [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric
457
+ [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric.
458
+ Please note that not all supported SQL engines give results from STDDV_SAMP (or engine specific equivalent) that
459
+ are comparable across all other supported SQL engines. This option may produce unreliable results.
458
460
  [--exclude-columns or -ec]
459
461
  Flag to indicate the list of columns provided should be excluded and not included.
460
462
  [--result-handler or -rh CONNECTION_NAME.SCHEMA.TABLE or BQ_PROJECT_ID.DATASET.TABLE]
@@ -525,6 +527,8 @@ data-validation
525
527
  --hash '*' '*' to hash all columns.
526
528
  --concat COLUMNS Comma separated list of columns to concatenate or * for all columns
527
529
  (use if a common hash function is not available between databases)
530
+ --max-concat-columns INT, -mcc INT
531
+ Maximum number of columns used in one --hash or --concat validation. When there are more columns in the validation, the validation will be split into multiple validations. There are engine specific defaults, so most users do not need to use this option unless they encounter errors.
528
532
  [--primary-keys PRIMARY_KEYS, -pk PRIMARY_KEYS]
529
533
  Common column between source and target queries for join
530
534
  [--exclude-columns or -ec]
@@ -548,8 +552,6 @@ data-validation
548
552
  Format for stdout output. Supported formats are (text, csv, json, table). Defaults to table.
549
553
  [--filter-status or -fs STATUSES_LIST]
550
554
  Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
551
- [--trim-string-pks, -tsp]
552
- Trims string based primary key values, intended for use when one engine uses padded string semantics (e.g. CHAR(n)) and the other does not (e.g. VARCHAR(n)).
553
555
  [--case-insensitive-match, -cim]
554
556
  Performs a case insensitive match by adding an UPPER() before comparison.
555
557
  ```
@@ -112,7 +112,9 @@ data-validation
112
112
  [--min COLUMNS] Comma separated list of columns for min or * for all numeric
113
113
  [--max COLUMNS] Comma separated list of columns for max or * for all numeric
114
114
  [--avg COLUMNS] Comma separated list of columns for avg or * for all numeric
115
- [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric
115
+ [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric.
116
+ Please note that not all supported SQL engines give results from STDDV_SAMP (or engine specific equivalent) that
117
+ are comparable across all other supported SQL engines. This option may produce unreliable results.
116
118
  [--exclude-columns or -ec]
117
119
  Flag to indicate the list of columns provided should be excluded and not included.
118
120
  [--result-handler or -rh CONNECTION_NAME.SCHEMA.TABLE or BQ_PROJECT_ID.DATASET.TABLE]
@@ -197,6 +199,8 @@ data-validation
197
199
  See: *Calculated Fields* section for details
198
200
  --hash COLUMNS Comma separated list of columns to hash or * for all columns
199
201
  --concat COLUMNS Comma separated list of columns to concatenate or * for all columns (use if a common hash function is not available between databases)
202
+ --max-concat-columns INT, -mcc INT
203
+ Maximum number of columns used in one --hash or --concat validation. When there are more columns in the validation, the validation will be split into multiple validations. There are engine specific defaults, so most users do not need to use this option unless they encounter errors.
200
204
  [--primary-keys PRIMARY_KEYS, -pk PRIMARY_KEYS]
201
205
  Comma separated list of primary key columns, when not specified the value will be inferred
202
206
  from the source or target table if available. See *Primary Keys* section
@@ -229,8 +233,6 @@ data-validation
229
233
  Row batch size used for random row filters (default 10,000).
230
234
  [--filter-status or -fs STATUSES_LIST]
231
235
  Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
232
- [--trim-string-pks, -tsp]
233
- Trims string based primary key values, intended for use when one engine uses padded string semantics (e.g. CHAR(n)) and the other does not (e.g. VARCHAR(n)).
234
236
  [--case-insensitive-match, -cim]
235
237
  Performs a case insensitive match by adding an UPPER() before comparison.
236
238
  ```
@@ -306,8 +308,6 @@ data-validation
306
308
  Format for stdout output. Supported formats are (text, csv, json, table). Defaults to table.
307
309
  [--filter-status or -fs STATUSES_LIST]
308
310
  Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
309
- [--trim-string-pks, -tsp]
310
- Trims string based primary key values, intended for use when one engine uses padded string semantics (e.g. CHAR(n)) and the other does not (e.g. VARCHAR(n)).
311
311
  [--case-insensitive-match, -cim]
312
312
  Performs a case insensitive match by adding an UPPER() before comparison.
313
313
  ```
@@ -395,7 +395,9 @@ data-validation
395
395
  [--min COLUMNS] Comma separated list of columns for min or * for all numeric
396
396
  [--max COLUMNS] Comma separated list of columns for max or * for all numeric
397
397
  [--avg COLUMNS] Comma separated list of columns for avg or * for all numeric
398
- [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric
398
+ [--std COLUMNS] Comma separated list of columns for stddev_samp or * for all numeric.
399
+ Please note that not all supported SQL engines give results from STDDV_SAMP (or engine specific equivalent) that
400
+ are comparable across all other supported SQL engines. This option may produce unreliable results.
399
401
  [--exclude-columns or -ec]
400
402
  Flag to indicate the list of columns provided should be excluded and not included.
401
403
  [--result-handler or -rh CONNECTION_NAME.SCHEMA.TABLE or BQ_PROJECT_ID.DATASET.TABLE]
@@ -466,6 +468,8 @@ data-validation
466
468
  --hash '*' '*' to hash all columns.
467
469
  --concat COLUMNS Comma separated list of columns to concatenate or * for all columns
468
470
  (use if a common hash function is not available between databases)
471
+ --max-concat-columns INT, -mcc INT
472
+ Maximum number of columns used in one --hash or --concat validation. When there are more columns in the validation, the validation will be split into multiple validations. There are engine specific defaults, so most users do not need to use this option unless they encounter errors.
469
473
  [--primary-keys PRIMARY_KEYS, -pk PRIMARY_KEYS]
470
474
  Common column between source and target queries for join
471
475
  [--exclude-columns or -ec]
@@ -489,8 +493,6 @@ data-validation
489
493
  Format for stdout output. Supported formats are (text, csv, json, table). Defaults to table.
490
494
  [--filter-status or -fs STATUSES_LIST]
491
495
  Comma separated list of statuses to filter the validation results. Supported statuses are (success, fail). If no list is provided, all statuses are returned.
492
- [--trim-string-pks, -tsp]
493
- Trims string based primary key values, intended for use when one engine uses padded string semantics (e.g. CHAR(n)) and the other does not (e.g. VARCHAR(n)).
494
496
  [--case-insensitive-match, -cim]
495
497
  Performs a case insensitive match by adding an UPPER() before comparison.
496
498
  ```
@@ -108,12 +108,16 @@ def get_aggregate_config(args, config_manager: ConfigManager):
108
108
  if args.count:
109
109
  col_args = None if args.count == "*" else cli_tools.get_arg_list(args.count)
110
110
  aggregate_configs += config_manager.build_config_column_aggregates(
111
- "count", col_args, args.exclude_columns, None, cast_to_bigint=cast_to_bigint
111
+ consts.CONFIG_TYPE_COUNT,
112
+ col_args,
113
+ args.exclude_columns,
114
+ None,
115
+ cast_to_bigint=cast_to_bigint,
112
116
  )
113
117
  if args.sum:
114
118
  col_args = None if args.sum == "*" else cli_tools.get_arg_list(args.sum)
115
119
  aggregate_configs += config_manager.build_config_column_aggregates(
116
- "sum",
120
+ consts.CONFIG_TYPE_SUM,
117
121
  col_args,
118
122
  args.exclude_columns,
119
123
  supported_data_types,
@@ -122,7 +126,7 @@ def get_aggregate_config(args, config_manager: ConfigManager):
122
126
  if args.avg:
123
127
  col_args = None if args.avg == "*" else cli_tools.get_arg_list(args.avg)
124
128
  aggregate_configs += config_manager.build_config_column_aggregates(
125
- "avg",
129
+ consts.CONFIG_TYPE_AVG,
126
130
  col_args,
127
131
  args.exclude_columns,
128
132
  supported_data_types,
@@ -131,7 +135,7 @@ def get_aggregate_config(args, config_manager: ConfigManager):
131
135
  if args.min:
132
136
  col_args = None if args.min == "*" else cli_tools.get_arg_list(args.min)
133
137
  aggregate_configs += config_manager.build_config_column_aggregates(
134
- "min",
138
+ consts.CONFIG_TYPE_MIN,
135
139
  col_args,
136
140
  args.exclude_columns,
137
141
  supported_data_types + uuid_types,
@@ -140,7 +144,7 @@ def get_aggregate_config(args, config_manager: ConfigManager):
140
144
  if args.max:
141
145
  col_args = None if args.max == "*" else cli_tools.get_arg_list(args.max)
142
146
  aggregate_configs += config_manager.build_config_column_aggregates(
143
- "max",
147
+ consts.CONFIG_TYPE_MAX,
144
148
  col_args,
145
149
  args.exclude_columns,
146
150
  supported_data_types + uuid_types,
@@ -149,7 +153,7 @@ def get_aggregate_config(args, config_manager: ConfigManager):
149
153
  if args.bit_xor:
150
154
  col_args = None if args.bit_xor == "*" else cli_tools.get_arg_list(args.bit_xor)
151
155
  aggregate_configs += config_manager.build_config_column_aggregates(
152
- "bit_xor",
156
+ consts.CONFIG_TYPE_BIT_XOR,
153
157
  col_args,
154
158
  args.exclude_columns,
155
159
  supported_data_types,
@@ -158,7 +162,7 @@ def get_aggregate_config(args, config_manager: ConfigManager):
158
162
  if args.std:
159
163
  col_args = None if args.std == "*" else cli_tools.get_arg_list(args.std)
160
164
  aggregate_configs += config_manager.build_config_column_aggregates(
161
- "std",
165
+ consts.CONFIG_TYPE_STD,
162
166
  col_args,
163
167
  args.exclude_columns,
164
168
  supported_data_types,
@@ -181,18 +185,14 @@ def _get_calculated_config(args, config_manager: ConfigManager) -> List[dict]:
181
185
  if config_manager.hash == "*"
182
186
  else cli_tools.get_arg_list(config_manager.hash)
183
187
  )
184
- fields = config_manager.build_dependent_aliases(
185
- "hash", col_list, args.exclude_columns
186
- )
188
+ fields = config_manager.build_dependent_aliases("hash", col_list)
187
189
  elif config_manager.concat:
188
190
  col_list = (
189
191
  None
190
192
  if config_manager.concat == "*"
191
193
  else cli_tools.get_arg_list(config_manager.concat)
192
194
  )
193
- fields = config_manager.build_dependent_aliases(
194
- "concat", col_list, args.exclude_columns
195
- )
195
+ fields = config_manager.build_dependent_aliases("concat", col_list)
196
196
 
197
197
  if len(fields) > 0:
198
198
  max_depth = max([x["depth"] for x in fields])
@@ -232,10 +232,7 @@ def _get_comparison_config(
232
232
  if args.comparison_fields == "*"
233
233
  else cli_tools.get_arg_list(args.comparison_fields)
234
234
  )
235
- comparison_fields = config_manager.build_comp_fields(
236
- col_list,
237
- args.exclude_columns,
238
- )
235
+ comparison_fields = config_manager.build_comp_fields(col_list, args.exclude_columns)
239
236
  # We can't have the PK columns in the comparison SQL twice therefore filter them out here if included.
240
237
  comparison_fields = [_ for _ in comparison_fields if _ not in primary_keys]
241
238
 
@@ -520,6 +517,11 @@ def run_validation(config_manager: ConfigManager, dry_run=False, verbose=False):
520
517
  if clients.is_sqlalchemy_backend(config_manager.target_client)
521
518
  else None
522
519
  )
520
+ # Though trims string based primary key value has been deprecated, some yaml files may still have that property set.
521
+ if config_manager.trim_string_pks():
522
+ logging.warning(
523
+ "Trim String Primary Keys has been deprecated, validation results may vary"
524
+ )
523
525
  with DataValidation(
524
526
  config_manager.config,
525
527
  validation_builder=None,
@@ -96,9 +96,11 @@ CONNECTION_SOURCE_FIELDS = {
96
96
  ["host", "Desired Oracle host"],
97
97
  ["port", "Oracle port to connect on"],
98
98
  ["user", "User used to connect"],
99
+ ["thick_mode", "Flag indicating thick_mode"],
99
100
  ["password", "Password for supplied user"],
100
101
  ["database", "Database to connect to"],
101
- ["url", "Oracle SQLAlchemy connection URL"],
102
+ ["protocol", "Oracle networking protocol (default TPC)"],
103
+ ["connect_args", "(Optional) Additional connection argument mapping"],
102
104
  ],
103
105
  consts.SOURCE_TYPE_MSSQL: [
104
106
  ["host", "Desired SQL Server host (default localhost)"],
@@ -121,7 +123,7 @@ CONNECTION_SOURCE_FIELDS = {
121
123
  ["password", "Password for authentication of user"],
122
124
  ["account", "Snowflake account to connect to"],
123
125
  ["database", "Database in snowflake to connect to"],
124
- ["connect_args", "(Optional) Additional connection arg mapping"],
126
+ ["connect_args", "(Optional) Additional connection argument mapping"],
125
127
  ],
126
128
  consts.SOURCE_TYPE_POSTGRES: [
127
129
  ["host", "Desired PostgreSQL host."],
@@ -198,6 +200,16 @@ VALIDATE_SCHEMA_HELP_TEXT = "Run a schema validation"
198
200
  VALIDATE_CUSTOM_QUERY_HELP_TEXT = "Run a custom query validation"
199
201
 
200
202
 
203
+ class deprecate_action(argparse.Action):
204
+ def __init__(self, option_strings, dest, nargs=0, **kwargs):
205
+ super().__init__(option_strings, dest, nargs=0, **kwargs)
206
+
207
+ def __call__(self, parser, namespace, values, option_string=None):
208
+ logging.warning(
209
+ f"Argument {option_string} is deprecated and may be removed in a future release"
210
+ )
211
+
212
+
201
213
  def _check_custom_query_args(parser: argparse.ArgumentParser, parsed_args: "Namespace"):
202
214
  # This is where we make additional checks if the arguments provided are what we expect
203
215
  # For example, only one of -tbls and custom query options can be provided
@@ -529,7 +541,12 @@ def _configure_database_specific_parsers(parser):
529
541
  for field_obj in CONNECTION_SOURCE_FIELDS[database]:
530
542
  arg_field = "--" + field_obj[0].replace("_", "-")
531
543
  help_txt = field_obj[1]
532
- db_parser.add_argument(arg_field, help=help_txt)
544
+ if (
545
+ field_obj[0] == "thick_mode" and database == consts.SOURCE_TYPE_ORACLE
546
+ ): # flag
547
+ db_parser.add_argument(arg_field, help=help_txt, action="store_true")
548
+ else:
549
+ db_parser.add_argument(arg_field, help=help_txt)
533
550
 
534
551
 
535
552
  def _configure_validate_parser(subparsers):
@@ -607,11 +624,9 @@ def _configure_row_parser(
607
624
  optional_arguments.add_argument(
608
625
  "--trim-string-pks",
609
626
  "-tsp",
610
- action="store_true",
611
- help=(
612
- "Trims string based primary key values, intended for use when one engine uses "
613
- "padded string semantics (e.g. CHAR(n)) and the other does not (e.g. VARCHAR(n))."
614
- ),
627
+ action=deprecate_action,
628
+ default=argparse.SUPPRESS,
629
+ help=argparse.SUPPRESS,
615
630
  )
616
631
  optional_arguments.add_argument(
617
632
  "--case-insensitive-match",
@@ -626,9 +641,9 @@ def _configure_row_parser(
626
641
  "-mcc",
627
642
  type=int,
628
643
  help=(
629
- "The maximum number of columns accepted by a --hash or --concat validation. When there are "
630
- "more columns than this the validation will implicitly be split into multiple validations. "
631
- "This option has engine specific defaults."
644
+ """Maximum number of columns used in one --hash or --concat validation. When there are more columns
645
+ in the validation, the validation will be split into multiple validations. There are engine specific
646
+ defaults, so most users do not need to use this option unless they encounter errors."""
632
647
  ),
633
648
  )
634
649
  # Generate-table-partitions and custom-query does not support random row
@@ -729,7 +744,10 @@ def _configure_column_parser(column_parser):
729
744
  optional_arguments.add_argument(
730
745
  "--std",
731
746
  "-std",
732
- help="Comma separated list of columns for standard deviation 'col_a,col_b' or * for all columns",
747
+ help="""Comma separated list of columns for standard deviation 'col_a,col_b' or * for all columns.
748
+ Please note that not all supported SQL engines give results from STDDV_SAMP (or engine specific
749
+ equivalent) that are comparable across all other supported SQL engines. This option may produce
750
+ unreliable results.""",
733
751
  )
734
752
  optional_arguments.add_argument(
735
753
  "--grouped-columns",
@@ -925,7 +943,10 @@ def _configure_custom_query_column_parser(custom_query_column_parser):
925
943
  optional_arguments.add_argument(
926
944
  "--std",
927
945
  "-std",
928
- help="Comma separated list of columns for standard deviation 'col_a,col_b' or * for all columns",
946
+ help="""Comma separated list of columns for standard deviation 'col_a,col_b' or * for all columns.
947
+ Please note that not all supported SQL engines give results from STDDV_SAMP (or engine specific
948
+ equivalent) that are comparable across all other supported SQL engines. This option may produce
949
+ unreliable results.""",
929
950
  )
930
951
  optional_arguments.add_argument(
931
952
  "--exclude-columns",
@@ -1490,26 +1511,49 @@ def _concat_column_count_configs(
1490
1511
  return return_list
1491
1512
 
1492
1513
 
1514
+ def _get_pre_build_configs_base_columns(
1515
+ client, table_obj: dict, query_str: str
1516
+ ) -> list:
1517
+ """Return a list of base columns for the table/custom query, used for both columns="*" and --exclude-columns."""
1518
+ if table_obj:
1519
+ full_col_list = clients.get_ibis_table_schema(
1520
+ client,
1521
+ table_obj["schema_name"],
1522
+ table_obj["table_name"],
1523
+ ).names
1524
+ else:
1525
+ full_col_list = clients.get_ibis_query_schema(
1526
+ client,
1527
+ query_str,
1528
+ ).names
1529
+ return [_.casefold() for _ in full_col_list]
1530
+
1531
+
1532
+ def _get_pre_build_configs_cols_from_arg(
1533
+ column_csv_arg: str, casefold_columns: list, exclude_columns: bool
1534
+ ) -> Optional[list]:
1535
+ if column_csv_arg is None:
1536
+ return None
1537
+
1538
+ column_arg_list = [_.casefold() for _ in get_arg_list(column_csv_arg)]
1539
+ if column_csv_arg == "*" and exclude_columns:
1540
+ raise ValueError(
1541
+ "Exclude columns flag cannot be present with '*' column specification"
1542
+ )
1543
+ elif column_csv_arg == "*" or exclude_columns:
1544
+ # If validating with "*" or need to invert the list then we need to expand to count the columns.
1545
+ if column_csv_arg == "*":
1546
+ return casefold_columns
1547
+
1548
+ if exclude_columns:
1549
+ return [col for col in casefold_columns if col not in column_arg_list]
1550
+ else:
1551
+ return column_arg_list
1552
+
1553
+
1493
1554
  def get_pre_build_configs(args: "Namespace", validate_cmd: str) -> List[Dict]:
1494
1555
  """Return a dict of configurations to build ConfigManager object"""
1495
1556
 
1496
- def cols_from_arg(concat_arg: str, client, table_obj: dict, query_str: str) -> list:
1497
- if concat_arg == "*":
1498
- # If validating with "*" then we need to expand to count the columns.
1499
- if table_obj:
1500
- return clients.get_ibis_table_schema(
1501
- client,
1502
- table_obj["schema_name"],
1503
- table_obj["table_name"],
1504
- ).names
1505
- else:
1506
- return clients.get_ibis_query_schema(
1507
- client,
1508
- query_str,
1509
- ).names
1510
- else:
1511
- return get_arg_list(concat_arg)
1512
-
1513
1557
  # validate_cmd will be set to 'row`, or 'Custom-query' if invoked by generate-table-partitions depending
1514
1558
  # on what is being partitioned. Otherwise validate_cmd will be set to None
1515
1559
  if validate_cmd is None:
@@ -1589,6 +1633,10 @@ def get_pre_build_configs(args: "Namespace", validate_cmd: str) -> List[Dict]:
1589
1633
  tables_list, source_client, target_client
1590
1634
  )
1591
1635
  for table_obj in tables_list:
1636
+ casefold_source_columns = _get_pre_build_configs_base_columns(
1637
+ source_client, table_obj, query_str
1638
+ )
1639
+
1592
1640
  pre_build_configs = {
1593
1641
  "config_type": config_type,
1594
1642
  consts.CONFIG_SOURCE_CONN_NAME: args.source_conn,
@@ -1604,9 +1652,6 @@ def get_pre_build_configs(args: "Namespace", validate_cmd: str) -> List[Dict]:
1604
1652
  "result_handler_config": result_handler_config,
1605
1653
  "filter_config": filter_config,
1606
1654
  consts.CONFIG_FILTER_STATUS: filter_status,
1607
- consts.CONFIG_TRIM_STRING_PKS: getattr(
1608
- args, consts.CONFIG_TRIM_STRING_PKS, False
1609
- ),
1610
1655
  consts.CONFIG_CASE_INSENSITIVE_MATCH: getattr(
1611
1656
  args, consts.CONFIG_CASE_INSENSITIVE_MATCH, False
1612
1657
  ),
@@ -1615,18 +1660,25 @@ def get_pre_build_configs(args: "Namespace", validate_cmd: str) -> List[Dict]:
1615
1660
  consts.CONFIG_RUN_ID: getattr(args, consts.CONFIG_RUN_ID, None),
1616
1661
  "verbose": args.verbose,
1617
1662
  }
1663
+
1618
1664
  if (
1619
1665
  pre_build_configs[consts.CONFIG_ROW_CONCAT]
1620
1666
  or pre_build_configs[consts.CONFIG_ROW_HASH]
1621
1667
  ):
1622
1668
  # Ensure we don't have too many columns for the engines involved.
1623
- cols = cols_from_arg(
1669
+ cols = _get_pre_build_configs_cols_from_arg(
1624
1670
  pre_build_configs[consts.CONFIG_ROW_HASH]
1625
1671
  or pre_build_configs[consts.CONFIG_ROW_CONCAT],
1626
- source_client,
1627
- table_obj,
1628
- query_str,
1672
+ casefold_source_columns,
1673
+ args.exclude_columns,
1629
1674
  )
1675
+ if args.exclude_columns:
1676
+ # Put the column csv back into pre_build_configs because it has been inverted.
1677
+ if pre_build_configs[consts.CONFIG_ROW_HASH]:
1678
+ pre_build_configs[consts.CONFIG_ROW_HASH] = ",".join(cols)
1679
+ elif pre_build_configs[consts.CONFIG_ROW_CONCAT]:
1680
+ pre_build_configs[consts.CONFIG_ROW_CONCAT] = ",".join(cols)
1681
+
1630
1682
  new_pre_build_configs = _concat_column_count_configs(
1631
1683
  cols,
1632
1684
  pre_build_configs,
@@ -73,11 +73,11 @@ except Exception:
73
73
  msg = "pip install teradatasql (requires Teradata licensing)"
74
74
  teradata_connect = _raise_missing_client_error(msg)
75
75
 
76
- # Oracle requires cx_Oracle driver
76
+ # Oracle requires python-oracldb driver
77
77
  try:
78
78
  from third_party.ibis.ibis_oracle.api import oracle_connect
79
79
  except Exception:
80
- oracle_connect = _raise_missing_client_error("pip install cx_Oracle")
80
+ oracle_connect = _raise_missing_client_error("pip install oracledb")
81
81
 
82
82
  # Snowflake requires snowflake-connector-python and snowflake-sqlalchemy
83
83
  try:
@@ -90,7 +90,8 @@ except Exception:
90
90
  # DB2 requires ibm_db_sa
91
91
  try:
92
92
  from third_party.ibis.ibis_db2.api import db2_connect
93
- except Exception:
93
+ except Exception as e:
94
+ logging.error(f"Exception {str(e)} while importing db2_connect")
94
95
  db2_connect = _raise_missing_client_error("pip install ibm_db_sa")
95
96
 
96
97
 
@@ -261,7 +262,7 @@ def list_tables(client, schema_name, tables_only=True):
261
262
  if tables_only and client.name != "pandas"
262
263
  else client.list_tables
263
264
  )
264
- if client.name in ["db2", "mssql", "redshift", "snowflake", "pandas"]:
265
+ if client.name in ["db2", "redshift", "snowflake", "pandas"]:
265
266
  return fn()
266
267
  return fn(database=schema_name)
267
268
 
@@ -320,6 +321,14 @@ def get_data_client(connection_config):
320
321
  key_path
321
322
  )
322
323
 
324
+ # Oracle no longer supports the url option, so check and warn users
325
+ if (
326
+ source_type == consts.SOURCE_TYPE_ORACLE
327
+ and "url" in decrypted_connection_config
328
+ ):
329
+ msg = f"Connection Configuration Error: url parameter no longer supported for {source_type}.\nRecreate connection with --connect-args parameter."
330
+ raise Exception(msg)
331
+
323
332
  if source_type not in CLIENT_LOOKUP:
324
333
  msg = 'ConfigurationError: Source type "{source_type}" is not supported'.format(
325
334
  source_type=source_type