google-pso-data-validator 6.2.0__tar.gz → 6.3.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 (84) hide show
  1. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/PKG-INFO +28 -11
  2. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/README.md +27 -10
  3. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/__main__.py +61 -62
  4. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/cli_tools.py +105 -50
  5. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/clients.py +5 -1
  6. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/combiner.py +34 -20
  7. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/config_manager.py +101 -42
  8. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/consts.py +1 -0
  9. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/partition_builder.py +2 -0
  10. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/query_builder/partition_row_builder.py +8 -2
  11. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/query_builder/query_builder.py +5 -0
  12. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/secret_manager.py +9 -5
  13. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/validation_builder.py +0 -2
  14. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/google_pso_data_validator.egg-info/PKG-INFO +28 -11
  15. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/setup.py +6 -6
  16. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_addon/api.py +21 -2
  17. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_addon/operations.py +17 -5
  18. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_db2/registry.py +1 -0
  19. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_oracle/datatypes.py +2 -2
  20. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_oracle/registry.py +9 -0
  21. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_postgres/client.py +7 -1
  22. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_teradata/registry.py +29 -0
  23. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/LICENSE +0 -0
  24. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/__init__.py +0 -0
  25. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/app.py +0 -0
  26. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/client_info.py +0 -0
  27. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/data_validation.py +0 -0
  28. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/exceptions.py +0 -0
  29. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/find_tables.py +0 -0
  30. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/gcs_helper.py +0 -0
  31. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/jellyfish_distance.py +0 -0
  32. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/metadata.py +0 -0
  33. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/query_builder/__init__.py +0 -0
  34. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/query_builder/random_row_builder.py +0 -0
  35. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/result_handlers/__init__.py +0 -0
  36. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/result_handlers/bigquery.py +0 -0
  37. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/result_handlers/text.py +0 -0
  38. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/schema_validation.py +0 -0
  39. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/data_validation/state_manager.py +0 -0
  40. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/google_pso_data_validator.egg-info/SOURCES.txt +0 -0
  41. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
  42. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
  43. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/google_pso_data_validator.egg-info/requires.txt +0 -0
  44. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
  45. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/setup.cfg +0 -0
  46. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
  47. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +0 -0
  48. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
  49. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
  50. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -0
  51. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
  52. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
  53. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
  54. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
  55. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +0 -0
  56. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_db2/__init__.py +0 -0
  57. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_db2/api.py +0 -0
  58. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_db2/compiler.py +0 -0
  59. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_db2/datatypes.py +0 -0
  60. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_impala/__init__.py +0 -0
  61. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_impala/api.py +0 -0
  62. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mssql/__init__.py +0 -0
  63. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mssql/api.py +0 -0
  64. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
  65. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mssql/registry.py +0 -0
  66. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
  67. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mysql/base_sql_compiler/__init__.py +0 -0
  68. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mysql/base_sql_compiler/select_builder.py +0 -0
  69. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
  70. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_oracle/__init__.py +0 -0
  71. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_oracle/api.py +0 -0
  72. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
  73. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
  74. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_postgres/datatypes.py +0 -0
  75. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_redshift/__init__.py +0 -0
  76. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_redshift/api.py +0 -0
  77. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
  78. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_snowflake/__init__.py +0 -0
  79. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_snowflake/api.py +0 -0
  80. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
  81. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_teradata/__init__.py +0 -0
  82. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_teradata/api.py +0 -0
  83. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
  84. {google_pso_data_validator-6.2.0 → google_pso_data_validator-6.3.0}/third_party/ibis/ibis_teradata/datatypes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: google-pso-data-validator
3
- Version: 6.2.0
3
+ Version: 6.3.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
@@ -267,13 +267,13 @@ data-validation
267
267
  [--case-insensitive-match, -cim]
268
268
  Performs a case insensitive match by adding an UPPER() before comparison.
269
269
  ```
270
- #### Generate Table Partitions for Large Table Row Validations
270
+ #### Generate Partitions for Large Row Validations
271
271
 
272
- When performing row validations, Data Validation Tool brings each row into memory and can run into MemoryError. Below is the command syntax for generating table partitions in order to perform row validations on large tables to alleviate MemoryError. Each partition contains a range of primary key(s) and the ranges of keys across partitions are distinct. The partitions have nearly equal number of rows. See *Primary Keys* section
272
+ When performing row validations, Data Validation Tool brings each row into memory and can run into MemoryError. Below is the command syntax for generating partitions in order to perform row validations on large dataset (table or custom-query) to alleviate MemoryError. Each partition contains a range of primary key(s) and the ranges of keys across partitions are distinct. The partitions have nearly equal number of rows. See *Primary Keys* section
273
273
 
274
- The command generates and stores multiple YAML validations each representing a chunk of the large table using filters (`WHERE primary_key(s) >= X AND primary_key(s) < Y`) in one YAML file. The parameter parts-per-file, specifies the number of validations in one YAML file. Each yaml file will have parts-per-file validations in it - except the last one which will contain the remaining partitions (i.e. parts-per-file may not divide partition-num evenly). You can then run the validations in the directory serially (or in parallel in multiple containers, VMs) with the `data-validation configs run --config-dir PATH` command as described [here](https://github.com/GoogleCloudPlatform/professional-services-data-validator#yaml-configuration-files).
274
+ The command generates and stores multiple YAML validations each representing a chunk of the large dataset using filters (`WHERE primary_key(s) >= X AND primary_key(s) < Y`) in YAML files. The parameter parts-per-file, specifies the number of validations in one YAML file. Each yaml file will have parts-per-file validations in it - except the last one which will contain the remaining partitions (i.e. parts-per-file may not divide partition-num evenly). You can then run the validations in the directory serially (or in parallel in multiple containers, VMs) with the `data-validation configs run --config-dir PATH` command as described [here](https://github.com/GoogleCloudPlatform/professional-services-data-validator#yaml-configuration-files).
275
275
 
276
- The command takes the same parameters as required for `Row Validation` *plus* a few parameters to support partitioning. Single and multiple primary keys are supported and keys can be of any indexable type, except for date and timestamp type. A parameter used in earlier versions, ```partition-key``` is no longer supported.
276
+ The command takes the same parameters as required for `Row Validation` *plus* a few parameters to support partitioning. Single and multiple primary keys are supported and keys can be of any indexable type, except for date and timestamp type. You can specify tables that are being validated or the source and target custom query. A parameter used in earlier versions, ```partition-key``` is no longer supported.
277
277
 
278
278
  ```
279
279
  data-validation
@@ -292,6 +292,17 @@ data-validation
292
292
  Comma separated list of tables in the form schema.table=target_schema.target_table
293
293
  Target schema name and table name are optional.
294
294
  i.e 'bigquery-public-data.new_york_citibike.citibike_trips'
295
+ Either --tables-list or --source-query (or file) and --target-query (or file) must be provided
296
+ --source-query SOURCE_QUERY, -sq SOURCE_QUERY
297
+ Source sql query
298
+ Either --tables-list or --source-query (or file) and --target-query (or file) must be provided
299
+ --source-query-file SOURCE_QUERY_FILE, -sqf SOURCE_QUERY_FILE
300
+ File containing the source sql command. Supports GCS and local paths.
301
+ --target-query TARGET_QUERY, -tq TARGET_QUERY
302
+ Target sql query
303
+ Either --tables-list or --source-query (or file) and --target-query (or file) must be provided
304
+ --target-query-file TARGET_QUERY_FILE, -tqf TARGET_QUERY_FILE
305
+ File containing the target sql command. Supports GCS and local paths.
295
306
  --primary-keys PRIMARY_KEYS, -pk PRIMARY_KEYS
296
307
  Comma separated list of primary key columns 'col_a,col_b'. See *Primary Keys* section
297
308
  --comparison-fields or -comp-fields FIELDS
@@ -303,6 +314,7 @@ data-validation
303
314
  Directory Path to store YAML Config Files
304
315
  GCS: Provide a full gs:// path of the target directory. Eg: `gs://<BUCKET>/partitions_dir`
305
316
  Local: Provide a relative path of the target directory. Eg: `partitions_dir`
317
+ If invoked with -tbls parameter, the validations are stored in a directory named <schema>.<table>, otherwise the directory is named `custom.<random_string>`
306
318
  --partition-num INT, -pn INT
307
319
  Number of partitions into which the table should be split, e.g. 1000 or 10000
308
320
  In case this value exceeds the row count of the source/target table, it will be decreased to max(source_row_count, target_row_count)
@@ -581,10 +593,10 @@ View the complete YAML file for a Grouped Column validation on the
581
593
 
582
594
  ### Scaling DVT
583
595
 
584
- You can scale DVT for large table validations by running the tool in a distributed manner. To optimize the validation speed for large tables, you can use GKE Jobs ([Google Kubernetes Jobs](https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-workloads-overview#batch_jobs)) or [Cloud Run Jobs](https://cloud.google.com/run/docs/create-jobs). If you are not familiar with Kubernetes or Cloud Run Jobs, see [Scaling DVT with Distributed Jobs](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/internal/distributed_jobs.md) for a detailed overview.
596
+ You can scale DVT for large validations by running the tool in a distributed manner. To optimize the validation speed for large tables, you can use GKE Jobs ([Google Kubernetes Jobs](https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-workloads-overview#batch_jobs)) or [Cloud Run Jobs](https://cloud.google.com/run/docs/create-jobs). If you are not familiar with Kubernetes or Cloud Run Jobs, see [Scaling DVT with Distributed Jobs](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/internal/distributed_jobs.md) for a detailed overview.
585
597
 
586
598
 
587
- We recommend first generating table partitions with the `generate-table-partitions` command for your large tables. Then, use Cloud Run or GKE to distribute validating each chunk in parallel. See the [Cloud Run Jobs Quickstart sample](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples/cloud_run_jobs) to get started.
599
+ We recommend first generating partitions with the `generate-table-partitions` command for your large datasets (tables or queries). Then, use Cloud Run or GKE to distribute the validation of each chunk in parallel. See the [Cloud Run Jobs Quickstart sample](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples/cloud_run_jobs) to get started.
588
600
 
589
601
  When running DVT in a distributed fashion, both the `--kube-completions` and `--config-dir` flags are required. The `--kube-completions` flag specifies that the validation is being run in indexed completion mode in Kubernetes or as multiple independent tasks in Cloud Run. If the `-kc` option is used and you are not running in indexed mode, you will receive a warning and the container will process all the validations sequentially. If the `-kc` option is used and a config directory is not provided (i.e. a `--config-file` is provided instead), a warning is issued.
590
602
 
@@ -719,10 +731,15 @@ resultset that breaks down the count of rows per calendar date.
719
731
  Row level validations can involve either a hash/checksum, concat, or comparison fields.
720
732
  A hash validation (`--hash '*'`) will first sanitize the data with the following
721
733
  operations on all or selected columns: CAST to string, IFNULL replace with a default
722
- replacement string, RSTRIP, and UPPER. Then, it will CONCAT() the results
723
- and run a SHA256() hash and compare the source and target results. Since each row will
724
- be returned in the result set, it is recommended to utilize the `--use-random-row` feature
725
- to validate a subset of the table.
734
+ replacement string and RSTRIP. Then, it will CONCAT() the results
735
+ and run a SHA256() hash and compare the source and target results.
736
+
737
+ When there are data type mismatches for columns, for example dates compared to timestamps and
738
+ booleans compared with numeric columns, you may see other expressions in SQL statements which
739
+ ensure that consistent values are used to build comparison values.
740
+
741
+ Since each row will be returned in the result set if is recommended recommended to validate a
742
+ subset of the table. The `--filters` and `--use-random-row` options can be used for this purpose.
726
743
 
727
744
  Please note that SHA256 is not a supported function on Teradata systems. If you wish to perform
728
745
  this comparison on Teradata you will need to [deploy a UDF to perform the conversion](https://github.com/akuroda/teradata-udf-sha2/blob/master/src/sha256.c).
@@ -226,13 +226,13 @@ data-validation
226
226
  [--case-insensitive-match, -cim]
227
227
  Performs a case insensitive match by adding an UPPER() before comparison.
228
228
  ```
229
- #### Generate Table Partitions for Large Table Row Validations
229
+ #### Generate Partitions for Large Row Validations
230
230
 
231
- When performing row validations, Data Validation Tool brings each row into memory and can run into MemoryError. Below is the command syntax for generating table partitions in order to perform row validations on large tables to alleviate MemoryError. Each partition contains a range of primary key(s) and the ranges of keys across partitions are distinct. The partitions have nearly equal number of rows. See *Primary Keys* section
231
+ When performing row validations, Data Validation Tool brings each row into memory and can run into MemoryError. Below is the command syntax for generating partitions in order to perform row validations on large dataset (table or custom-query) to alleviate MemoryError. Each partition contains a range of primary key(s) and the ranges of keys across partitions are distinct. The partitions have nearly equal number of rows. See *Primary Keys* section
232
232
 
233
- The command generates and stores multiple YAML validations each representing a chunk of the large table using filters (`WHERE primary_key(s) >= X AND primary_key(s) < Y`) in one YAML file. The parameter parts-per-file, specifies the number of validations in one YAML file. Each yaml file will have parts-per-file validations in it - except the last one which will contain the remaining partitions (i.e. parts-per-file may not divide partition-num evenly). You can then run the validations in the directory serially (or in parallel in multiple containers, VMs) with the `data-validation configs run --config-dir PATH` command as described [here](https://github.com/GoogleCloudPlatform/professional-services-data-validator#yaml-configuration-files).
233
+ The command generates and stores multiple YAML validations each representing a chunk of the large dataset using filters (`WHERE primary_key(s) >= X AND primary_key(s) < Y`) in YAML files. The parameter parts-per-file, specifies the number of validations in one YAML file. Each yaml file will have parts-per-file validations in it - except the last one which will contain the remaining partitions (i.e. parts-per-file may not divide partition-num evenly). You can then run the validations in the directory serially (or in parallel in multiple containers, VMs) with the `data-validation configs run --config-dir PATH` command as described [here](https://github.com/GoogleCloudPlatform/professional-services-data-validator#yaml-configuration-files).
234
234
 
235
- The command takes the same parameters as required for `Row Validation` *plus* a few parameters to support partitioning. Single and multiple primary keys are supported and keys can be of any indexable type, except for date and timestamp type. A parameter used in earlier versions, ```partition-key``` is no longer supported.
235
+ The command takes the same parameters as required for `Row Validation` *plus* a few parameters to support partitioning. Single and multiple primary keys are supported and keys can be of any indexable type, except for date and timestamp type. You can specify tables that are being validated or the source and target custom query. A parameter used in earlier versions, ```partition-key``` is no longer supported.
236
236
 
237
237
  ```
238
238
  data-validation
@@ -251,6 +251,17 @@ data-validation
251
251
  Comma separated list of tables in the form schema.table=target_schema.target_table
252
252
  Target schema name and table name are optional.
253
253
  i.e 'bigquery-public-data.new_york_citibike.citibike_trips'
254
+ Either --tables-list or --source-query (or file) and --target-query (or file) must be provided
255
+ --source-query SOURCE_QUERY, -sq SOURCE_QUERY
256
+ Source sql query
257
+ Either --tables-list or --source-query (or file) and --target-query (or file) must be provided
258
+ --source-query-file SOURCE_QUERY_FILE, -sqf SOURCE_QUERY_FILE
259
+ File containing the source sql command. Supports GCS and local paths.
260
+ --target-query TARGET_QUERY, -tq TARGET_QUERY
261
+ Target sql query
262
+ Either --tables-list or --source-query (or file) and --target-query (or file) must be provided
263
+ --target-query-file TARGET_QUERY_FILE, -tqf TARGET_QUERY_FILE
264
+ File containing the target sql command. Supports GCS and local paths.
254
265
  --primary-keys PRIMARY_KEYS, -pk PRIMARY_KEYS
255
266
  Comma separated list of primary key columns 'col_a,col_b'. See *Primary Keys* section
256
267
  --comparison-fields or -comp-fields FIELDS
@@ -262,6 +273,7 @@ data-validation
262
273
  Directory Path to store YAML Config Files
263
274
  GCS: Provide a full gs:// path of the target directory. Eg: `gs://<BUCKET>/partitions_dir`
264
275
  Local: Provide a relative path of the target directory. Eg: `partitions_dir`
276
+ If invoked with -tbls parameter, the validations are stored in a directory named <schema>.<table>, otherwise the directory is named `custom.<random_string>`
265
277
  --partition-num INT, -pn INT
266
278
  Number of partitions into which the table should be split, e.g. 1000 or 10000
267
279
  In case this value exceeds the row count of the source/target table, it will be decreased to max(source_row_count, target_row_count)
@@ -540,10 +552,10 @@ View the complete YAML file for a Grouped Column validation on the
540
552
 
541
553
  ### Scaling DVT
542
554
 
543
- You can scale DVT for large table validations by running the tool in a distributed manner. To optimize the validation speed for large tables, you can use GKE Jobs ([Google Kubernetes Jobs](https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-workloads-overview#batch_jobs)) or [Cloud Run Jobs](https://cloud.google.com/run/docs/create-jobs). If you are not familiar with Kubernetes or Cloud Run Jobs, see [Scaling DVT with Distributed Jobs](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/internal/distributed_jobs.md) for a detailed overview.
555
+ You can scale DVT for large validations by running the tool in a distributed manner. To optimize the validation speed for large tables, you can use GKE Jobs ([Google Kubernetes Jobs](https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-workloads-overview#batch_jobs)) or [Cloud Run Jobs](https://cloud.google.com/run/docs/create-jobs). If you are not familiar with Kubernetes or Cloud Run Jobs, see [Scaling DVT with Distributed Jobs](https://github.com/GoogleCloudPlatform/professional-services-data-validator/blob/develop/docs/internal/distributed_jobs.md) for a detailed overview.
544
556
 
545
557
 
546
- We recommend first generating table partitions with the `generate-table-partitions` command for your large tables. Then, use Cloud Run or GKE to distribute validating each chunk in parallel. See the [Cloud Run Jobs Quickstart sample](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples/cloud_run_jobs) to get started.
558
+ We recommend first generating partitions with the `generate-table-partitions` command for your large datasets (tables or queries). Then, use Cloud Run or GKE to distribute the validation of each chunk in parallel. See the [Cloud Run Jobs Quickstart sample](https://github.com/GoogleCloudPlatform/professional-services-data-validator/tree/develop/samples/cloud_run_jobs) to get started.
547
559
 
548
560
  When running DVT in a distributed fashion, both the `--kube-completions` and `--config-dir` flags are required. The `--kube-completions` flag specifies that the validation is being run in indexed completion mode in Kubernetes or as multiple independent tasks in Cloud Run. If the `-kc` option is used and you are not running in indexed mode, you will receive a warning and the container will process all the validations sequentially. If the `-kc` option is used and a config directory is not provided (i.e. a `--config-file` is provided instead), a warning is issued.
549
561
 
@@ -678,10 +690,15 @@ resultset that breaks down the count of rows per calendar date.
678
690
  Row level validations can involve either a hash/checksum, concat, or comparison fields.
679
691
  A hash validation (`--hash '*'`) will first sanitize the data with the following
680
692
  operations on all or selected columns: CAST to string, IFNULL replace with a default
681
- replacement string, RSTRIP, and UPPER. Then, it will CONCAT() the results
682
- and run a SHA256() hash and compare the source and target results. Since each row will
683
- be returned in the result set, it is recommended to utilize the `--use-random-row` feature
684
- to validate a subset of the table.
693
+ replacement string and RSTRIP. Then, it will CONCAT() the results
694
+ and run a SHA256() hash and compare the source and target results.
695
+
696
+ When there are data type mismatches for columns, for example dates compared to timestamps and
697
+ booleans compared with numeric columns, you may see other expressions in SQL statements which
698
+ ensure that consistent values are used to build comparison values.
699
+
700
+ Since each row will be returned in the result set if is recommended recommended to validate a
701
+ subset of the table. The `--filters` and `--use-random-row` options can be used for this purpose.
685
702
 
686
703
  Please note that SHA256 is not a supported function on Teradata systems. If you wish to perform
687
704
  this comparison on Teradata you will need to [deploy a UDF to perform the conversion](https://github.com/akuroda/teradata-udf-sha2/blob/master/src/sha256.c).
@@ -160,7 +160,7 @@ def get_aggregate_config(args, config_manager: ConfigManager):
160
160
  return aggregate_configs
161
161
 
162
162
 
163
- def get_calculated_config(args, config_manager: ConfigManager) -> List[dict]:
163
+ def _get_calculated_config(args, config_manager: ConfigManager) -> List[dict]:
164
164
  """Return list of formatted calculated objects.
165
165
 
166
166
  Args:
@@ -217,8 +217,41 @@ def get_calculated_config(args, config_manager: ConfigManager) -> List[dict]:
217
217
  return calculated_configs
218
218
 
219
219
 
220
+ def _get_comparison_config(args, config_manager: ConfigManager) -> List[dict]:
221
+ col_list = (
222
+ None
223
+ if config_manager.comparison_fields == "*"
224
+ else cli_tools.get_arg_list(config_manager.comparison_fields)
225
+ )
226
+ comparison_fields = config_manager.build_comp_fields(
227
+ col_list,
228
+ args.exclude_columns,
229
+ )
230
+ # We can't have the PK columns in the comparison SQL twice therefore filter them out here if included.
231
+ comparison_fields = [
232
+ _
233
+ for _ in comparison_fields
234
+ if _ not in cli_tools.get_arg_list(args.primary_keys.casefold())
235
+ ]
236
+
237
+ # As per #1190, add rstrip for Teradata string comparison fields
238
+ if (
239
+ config_manager.source_client.name == "teradata"
240
+ or config_manager.target_client.name == "teradata"
241
+ ):
242
+ comparison_fields = config_manager.add_rstrip_to_comp_fields(comparison_fields)
243
+
244
+ return config_manager.build_config_comparison_fields(comparison_fields)
245
+
246
+
220
247
  def build_config_from_args(args: Namespace, config_manager: ConfigManager):
221
- """Append build configs to ConfigManager object.
248
+ """This function is used to append build configs to the config manager for all validation commands and generate-table-partitions.
249
+ Instead of having two separate commands, e.g. validate row and validate custom-query row, generate-table-partitions
250
+ uses implicit choice of table or custom-query. A user can specify either tables or source/target query/file,
251
+ but not both. In the case of generate-table-partitions with custom query, the user will not provide
252
+ args.custom_query_type. However, the code will inject args.custom_query_type as 'row' before invoking
253
+ build_config_from_args.
254
+
222
255
 
223
256
  Args:
224
257
  args (Namespace): User specified Arguments
@@ -227,14 +260,14 @@ def build_config_from_args(args: Namespace, config_manager: ConfigManager):
227
260
 
228
261
  # Append SCHEMA_VALIDATION configs
229
262
  if config_manager.validation_type == consts.SCHEMA_VALIDATION:
230
- if args.exclusion_columns is not None:
263
+ if args.exclusion_columns:
231
264
  exclusion_columns = cli_tools.get_arg_list(args.exclusion_columns)
232
265
  config_manager.append_exclusion_columns(
233
266
  [col.casefold() for col in exclusion_columns]
234
267
  )
235
268
  config_manager.append_allow_list(args.allow_list, args.allow_list_file)
236
269
 
237
- # Append CUSTOM_QUERY configs
270
+ # Append configs specific to CUSTOM_QUERY (i.e. query strings or strings from files)
238
271
  if config_manager.validation_type == consts.CUSTOM_QUERY:
239
272
  config_manager.append_custom_query_type(args.custom_query_type)
240
273
 
@@ -252,75 +285,37 @@ def build_config_from_args(args: Namespace, config_manager: ConfigManager):
252
285
  )
253
286
  )
254
287
 
255
- # For custom-query column command
256
- if args.custom_query_type == consts.COLUMN_VALIDATION.lower():
257
- config_manager.append_aggregates(get_aggregate_config(args, config_manager))
258
-
259
- # For custom-query row command
260
- if args.custom_query_type == consts.ROW_VALIDATION.lower():
261
- # Append Comparison fields
262
- if args.comparison_fields is not None:
263
- comparison_fields = cli_tools.get_arg_list(
264
- args.comparison_fields, default_value=[]
265
- )
266
-
267
- # As per #1190, add rstrip for Teradata string comparison fields
268
- if (
269
- config_manager.source_client.name == "teradata"
270
- or config_manager.target_client.name == "teradata"
271
- ):
272
- comparison_fields = config_manager.add_rstrip_to_comp_fields(
273
- comparison_fields
274
- )
275
-
276
- config_manager.append_comparison_fields(
277
- config_manager.build_config_comparison_fields(comparison_fields)
278
- )
279
-
280
- # Append calculated fields: --hash/--concat
281
- config_manager.append_calculated_fields(
282
- get_calculated_config(args, config_manager)
283
- )
284
-
285
- # Append primary_keys
286
- primary_keys = cli_tools.get_arg_list(args.primary_keys)
287
- config_manager.append_primary_keys(
288
- config_manager.build_column_configs(primary_keys)
289
- )
290
-
291
- # Append COLUMN_VALIDATION configs
292
- if config_manager.validation_type == consts.COLUMN_VALIDATION:
288
+ # Append COLUMN_VALIDATION configs, including custom-query column validation
289
+ if (
290
+ config_manager.validation_type == consts.COLUMN_VALIDATION
291
+ or config_manager.validation_type == consts.CUSTOM_QUERY
292
+ and args.custom_query_type == consts.COLUMN_VALIDATION.lower()
293
+ ):
293
294
  config_manager.append_aggregates(get_aggregate_config(args, config_manager))
294
- if args.grouped_columns is not None:
295
+ if (
296
+ config_manager.validation_type == consts.COLUMN_VALIDATION
297
+ and args.grouped_columns # grouped_columns not supported in custom queries - at least now.
298
+ ):
295
299
  grouped_columns = cli_tools.get_arg_list(args.grouped_columns)
296
300
  config_manager.append_query_groups(
297
301
  config_manager.build_column_configs(grouped_columns)
298
302
  )
299
303
 
300
- # Append ROW_VALIDATION configs
301
- if config_manager.validation_type == consts.ROW_VALIDATION:
304
+ # Append ROW_VALIDATION configs, including custom-query row validation
305
+ if (
306
+ config_manager.validation_type == consts.ROW_VALIDATION
307
+ or config_manager.validation_type == consts.CUSTOM_QUERY
308
+ and args.custom_query_type == consts.ROW_VALIDATION.lower()
309
+ ):
302
310
  # Append calculated fields: --hash/--concat
303
311
  config_manager.append_calculated_fields(
304
- get_calculated_config(args, config_manager)
312
+ _get_calculated_config(args, config_manager)
305
313
  )
306
314
 
307
315
  # Append Comparison fields
308
- if args.comparison_fields is not None:
309
- comparison_fields = cli_tools.get_arg_list(
310
- args.comparison_fields, default_value=[]
311
- )
312
-
313
- # As per #1190, add rstrip for Teradata string comparison fields
314
- if (
315
- config_manager.source_client.name == "teradata"
316
- or config_manager.target_client.name == "teradata"
317
- ):
318
- comparison_fields = config_manager.add_rstrip_to_comp_fields(
319
- comparison_fields
320
- )
321
-
316
+ if args.comparison_fields:
322
317
  config_manager.append_comparison_fields(
323
- config_manager.build_config_comparison_fields(comparison_fields)
318
+ _get_comparison_config(args, config_manager)
324
319
  )
325
320
 
326
321
  # Append primary_keys
@@ -599,7 +594,11 @@ def partition_and_store_config_files(args: Namespace) -> None:
599
594
  None
600
595
  """
601
596
  # Default Validate Type
602
- config_managers = build_config_managers_from_args(args, consts.ROW_VALIDATION)
597
+ if args.tables_list:
598
+ config_managers = build_config_managers_from_args(args, consts.ROW_VALIDATION)
599
+ else:
600
+ setattr(args, "custom_query_type", "row")
601
+ config_managers = build_config_managers_from_args(args, consts.CUSTOM_QUERY)
603
602
  partition_builder = PartitionBuilder(config_managers, args)
604
603
  partition_builder.partition_configs()
605
604
 
@@ -129,7 +129,7 @@ CONNECTION_SOURCE_FIELDS = {
129
129
  "FileSystem": [
130
130
  ["table_name", "Table name to use as reference for file data"],
131
131
  ["file_path", "The local, s3, or GCS file path to the data"],
132
- ["file_type", "The file type of the file. 'csv' or 'json'"],
132
+ ["file_type", "The file type of the file. 'csv', 'orc', 'parquet' or 'json'"],
133
133
  ],
134
134
  "Impala": [
135
135
  ["host", "Desired Impala host"],
@@ -171,11 +171,45 @@ CONNECTION_SOURCE_FIELDS = {
171
171
  }
172
172
 
173
173
 
174
+ def _check_custom_query_args(parser: argparse.ArgumentParser, parsed_args: Namespace):
175
+ # This is where we make additional checks if the arguments provided are what we expect
176
+ # For example, only one of -tbls and custom query options can be provided
177
+ if hasattr(parsed_args, "tables_list") and hasattr(
178
+ parsed_args, "source_query"
179
+ ): # New Format
180
+ if (
181
+ parsed_args.tables_list
182
+ ): # Tables_list is not None - so source and target queries all must be None
183
+ if (
184
+ parsed_args.source_query_file
185
+ or parsed_args.source_query
186
+ or parsed_args.target_query_file
187
+ or parsed_args.target_query
188
+ ):
189
+ parser.error(
190
+ f"{parsed_args.command}: when --tables-list/-tbls is specified, --source-query-file/-sqf, --source-query/-sq, --target-query-file/-tqf and --target-query/-tq must not be specified"
191
+ )
192
+ else:
193
+ return
194
+ elif (parsed_args.source_query_file or parsed_args.source_query) and (
195
+ parsed_args.target_query_file or parsed_args.target_query
196
+ ):
197
+ return
198
+ else:
199
+ parser.error(
200
+ f"{parsed_args.command}: Must specify both source (--source-query-file/-sqf or --source-query/-sq) and target (--target-query-file/-tqf or --target-query/-tq) - when --tables-list/-tbls is not specified"
201
+ )
202
+ else:
203
+ return # old format - only one of them is present
204
+
205
+
174
206
  def get_parsed_args() -> Namespace:
175
207
  """Return ArgParser with configured CLI arguments."""
176
208
  parser = configure_arg_parser()
177
209
  args = ["--help"] if len(sys.argv) == 1 else None
178
- return parser.parse_args(args)
210
+ parsed_args = parser.parse_args(args)
211
+ _check_custom_query_args(parser, parsed_args)
212
+ return parsed_args
179
213
 
180
214
 
181
215
  def configure_arg_parser():
@@ -225,6 +259,7 @@ def _configure_partition_parser(subparsers):
225
259
  default=1,
226
260
  help="Number of partitions to be validated in a single yaml file.",
227
261
  )
262
+
228
263
  required_arguments.add_argument(
229
264
  "--config-dir",
230
265
  "-cdir",
@@ -242,6 +277,46 @@ def _configure_partition_parser(subparsers):
242
277
  help="Number of partitions into which the table should be split",
243
278
  type=_check_positive,
244
279
  )
280
+ # User can provide tables or custom queries, but not both
281
+ # However, Argparse does not support adding an argument_group to an argument_group or adding a
282
+ # mutually_exclusive_group or argument_group to a mutually_exclusive_group since version 3.11.
283
+ # We are only ensuring leaf level mutual exclusivity here and will need to check higher level
284
+ # mutual exclusivity in the code - i.e. a) when --tables-list is present, there can be no custom
285
+ # query parameters and b) when custom query parameters are specified, both source and target must be
286
+ # specified.
287
+ optional_arguments.add_argument(
288
+ "--tables-list",
289
+ "-tbls",
290
+ help=(
291
+ "Comma separated tables list in the form "
292
+ "'schema.table=target_schema.target_table'"
293
+ ),
294
+ )
295
+
296
+ source_mutually_exclusive = optional_arguments.add_mutually_exclusive_group()
297
+ source_mutually_exclusive.add_argument(
298
+ "--source-query-file",
299
+ "-sqf",
300
+ help="File containing the source sql query",
301
+ )
302
+ source_mutually_exclusive.add_argument(
303
+ "--source-query",
304
+ "-sq",
305
+ help="Source sql query",
306
+ )
307
+
308
+ # Group for mutually exclusive target query arguments. Either must be supplied
309
+ target_mutually_exclusive = optional_arguments.add_mutually_exclusive_group()
310
+ target_mutually_exclusive.add_argument(
311
+ "--target-query-file",
312
+ "-tqf",
313
+ help="File containing the target sql query",
314
+ )
315
+ target_mutually_exclusive.add_argument(
316
+ "--target-query",
317
+ "-tq",
318
+ help="Target sql query",
319
+ )
245
320
 
246
321
 
247
322
  def _configure_beta_parser(subparsers):
@@ -443,6 +518,7 @@ def _configure_row_parser(
443
518
  "--threshold",
444
519
  "-th",
445
520
  type=threshold_float,
521
+ default=0.0,
446
522
  help="Float max threshold for percent difference",
447
523
  )
448
524
  optional_arguments.add_argument(
@@ -454,6 +530,8 @@ def _configure_row_parser(
454
530
  optional_arguments.add_argument(
455
531
  "--filters",
456
532
  "-filters",
533
+ type=get_filters,
534
+ default=[],
457
535
  help="Filters in the format source_filter:target_filter",
458
536
  )
459
537
  optional_arguments.add_argument(
@@ -496,9 +574,10 @@ def _configure_row_parser(
496
574
  "-rbs",
497
575
  help="Row batch size used for random row filters (default 10,000).",
498
576
  )
499
-
500
- # Group required arguments
501
- if not is_custom_query:
577
+ # Generate table partitions follows a new argument spec where either the table names or queries can be provided, but not both.
578
+ # that is specified in configure_partition_parser. If we use the same spec for row and column validation, the custom query commands
579
+ # may get subsumed by validate and validate commands by specifying tables name or queries. Until this -tbls will be
580
+ # a required argument for validate row, validate column and validate schema.
502
581
  required_arguments.add_argument(
503
582
  "--tables-list",
504
583
  "-tbls",
@@ -506,6 +585,8 @@ def _configure_row_parser(
506
585
  required=True,
507
586
  help="Comma separated tables list in the form 'schema.table=target_schema.target_table'",
508
587
  )
588
+
589
+ # Group required arguments
509
590
  required_arguments.add_argument(
510
591
  "--primary-keys",
511
592
  "-pk",
@@ -603,24 +684,17 @@ def _configure_column_parser(column_parser):
603
684
  "--threshold",
604
685
  "-th",
605
686
  type=threshold_float,
687
+ default=0.0,
606
688
  help="Float max threshold for percent difference",
607
689
  )
608
690
  optional_arguments.add_argument(
609
691
  "--filters",
610
692
  "-filters",
693
+ type=get_filters,
694
+ default=[],
611
695
  help="Filters in the format source_filter:target_filter",
612
696
  )
613
- optional_arguments.add_argument(
614
- "--use-random-row",
615
- "-rr",
616
- action="store_true",
617
- help="Finds a set of random rows of the first primary key supplied.",
618
- )
619
- optional_arguments.add_argument(
620
- "--random-row-batch-size",
621
- "-rbs",
622
- help="Row batch size used for random row filters (default 10,000).",
623
- )
697
+
624
698
  optional_arguments.add_argument(
625
699
  "--wildcard-include-string-len",
626
700
  "-wis",
@@ -818,25 +892,17 @@ def _configure_custom_query_column_parser(custom_query_column_parser):
818
892
  optional_arguments.add_argument(
819
893
  "--filters",
820
894
  "-filters",
895
+ type=get_filters,
896
+ default=[],
821
897
  help="Filters in the format source_filter:target_filter",
822
898
  )
823
899
  optional_arguments.add_argument(
824
900
  "--threshold",
825
901
  "-th",
826
902
  type=threshold_float,
903
+ default=0.0,
827
904
  help="Float max threshold for percent difference",
828
905
  )
829
- optional_arguments.add_argument(
830
- "--use-random-row",
831
- "-rr",
832
- action="store_true",
833
- help="Finds a set of random rows of the first primary key supplied.",
834
- )
835
- optional_arguments.add_argument(
836
- "--random-row-batch-size",
837
- "-rbs",
838
- help="Row batch size used for random row filters (default 10,000).",
839
- )
840
906
 
841
907
  # Group required arguments
842
908
  required_arguments = custom_query_column_parser.add_argument_group(
@@ -910,6 +976,7 @@ def _add_common_arguments(
910
976
  "-cj",
911
977
  help="Store the validation config in the JSON File Path specified to be used for application use cases",
912
978
  )
979
+
913
980
  optional_arguments.add_argument(
914
981
  "--format",
915
982
  "-fmt",
@@ -1080,7 +1147,7 @@ def get_filters(filter_value: str) -> List[Dict]:
1080
1147
  filter_config = []
1081
1148
  if result := re.fullmatch(single_filter, filter_value):
1082
1149
  if result.group(0) == "":
1083
- raise ValueError("Empty string not allowed in filter")
1150
+ raise argparse.ArgumentTypeError("Empty string not allowed in filter")
1084
1151
  filter_dict = {
1085
1152
  "type": "custom",
1086
1153
  "source": result.group(0),
@@ -1088,14 +1155,14 @@ def get_filters(filter_value: str) -> List[Dict]:
1088
1155
  }
1089
1156
  elif result := re.fullmatch(double_filter, filter_value):
1090
1157
  if result.group("source") == "" or result.group("target") == "":
1091
- raise ValueError("Empty string not allowed in filter")
1158
+ raise argparse.ArgumentTypeError("Empty string not allowed in filter")
1092
1159
  filter_dict = {
1093
1160
  "type": "custom",
1094
1161
  "source": result.group("source"),
1095
1162
  "target": result.group("target"),
1096
1163
  }
1097
1164
  else:
1098
- raise ValueError("Unable to parse filter arguments.")
1165
+ raise argparse.ArgumentTypeError("Unable to parse filter arguments.")
1099
1166
  filter_config.append(filter_dict)
1100
1167
  return filter_config
1101
1168
 
@@ -1315,8 +1382,8 @@ def get_pre_build_configs(args: Namespace, validate_cmd: str) -> List[Dict]:
1315
1382
  else:
1316
1383
  return get_arg_list(concat_arg)
1317
1384
 
1318
- # Since `generate-table-partitions` defaults to `validate_cmd=row`,
1319
- # `validate_cmd` is passed along while calling this method
1385
+ # validate_cmd will be set to 'row`, or 'Custom-query' if invoked by generate-table-partitions depending
1386
+ # on what is being partitioned. Otherwise validate_cmd will be set to None
1320
1387
  if validate_cmd is None:
1321
1388
  validate_cmd = args.validate_cmd.capitalize()
1322
1389
 
@@ -1339,14 +1406,9 @@ def get_pre_build_configs(args: Namespace, validate_cmd: str) -> List[Dict]:
1339
1406
  else:
1340
1407
  result_handler_config = None
1341
1408
 
1342
- # Get filter_config and threshold. Not supported in case of schema validation
1343
- filter_config = []
1344
- threshold = 0.0
1345
- if config_type != consts.SCHEMA_VALIDATION:
1346
- if args.filters:
1347
- filter_config = get_filters(args.filters)
1348
- if args.threshold:
1349
- threshold = args.threshold
1409
+ # Set filter_config and threshold. Not supported in case of schema validation
1410
+ filter_config = getattr(args, "filters", [])
1411
+ threshold = getattr(args, "threshold", 0.0)
1350
1412
 
1351
1413
  # Get labels
1352
1414
  if args.labels is None:
@@ -1362,16 +1424,9 @@ def get_pre_build_configs(args: Namespace, validate_cmd: str) -> List[Dict]:
1362
1424
  # Get format: text, csv, json, table. Default is table
1363
1425
  format = args.format if args.format else "table"
1364
1426
 
1365
- # Get random row arguments. Not supported in case of schema validation,
1366
- # custom-query validation and generate-table-partitions
1367
- use_random_rows = None
1368
- random_row_batch_size = None
1369
- if (
1370
- args.command != "generate-table-partitions"
1371
- and config_type != consts.SCHEMA_VALIDATION
1372
- ):
1373
- use_random_rows = getattr(args, "use_random_row", False)
1374
- random_row_batch_size = getattr(args, "random_row_batch_size", None)
1427
+ # Get random row arguments. Only in row validations these attributes can be present.
1428
+ use_random_rows = getattr(args, "use_random_row", False)
1429
+ random_row_batch_size = getattr(args, "random_row_batch_size", None)
1375
1430
 
1376
1431
  # Get table list. Not supported in case of custom query validation
1377
1432
  is_filesystem = source_client._source_type == "FileSystem"
@@ -119,12 +119,16 @@ def get_pandas_client(table_name, file_path, file_type):
119
119
 
120
120
  table_name (str): Table name to use as reference for file data
121
121
  file_path (str): The local, s3, or GCS file path to the data
122
- file_type (str): The file type of the file (csv or json)
122
+ file_type (str): The file type of the file (csv, json, orc or parquet)
123
123
  """
124
124
  if file_type == "csv":
125
125
  df = pandas.read_csv(file_path)
126
126
  elif file_type == "json":
127
127
  df = pandas.read_json(file_path)
128
+ elif file_type == "orc":
129
+ df = pandas.read_orc(file_path)
130
+ elif file_type == "parquet":
131
+ df = pandas.read_parquet(file_path)
128
132
  else:
129
133
  raise ValueError(f"Unknown Pandas File Type: {file_type}")
130
134