datacontract-cli 1.2.3__tar.gz → 1.2.4__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.
- {datacontract_cli-1.2.3/datacontract_cli.egg-info → datacontract_cli-1.2.4}/PKG-INFO +7 -7
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/README.md +1 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/api.py +8 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/cli.py +20 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_ci.py +5 -2
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_test.py +4 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/config/settings.py +5 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/config/variables.py +38 -8
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/check_spec.py +6 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/create_checks.py +178 -22
- datacontract_cli-1.2.4/datacontract/engines/checks/custom_quality_check.py +552 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/dimensions.py +2 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/sql_guard.py +4 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/data_contract_test.py +7 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/hana/check_hana_execute.py +2 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/hana/hana_quality_check.py +126 -16
- datacontract_cli-1.2.4/datacontract/engines/ibis/__init__.py +16 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/connect.py +6 -6
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/duckdb_connection.py +13 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/ibis_check_execute.py +32 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/mysql_importer.py +2 -3
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/output/test_results_writer.py +2 -2
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4/datacontract_cli.egg-info}/PKG-INFO +7 -7
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract_cli.egg-info/SOURCES.txt +3 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract_cli.egg-info/requires.txt +5 -5
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/pyproject.toml +6 -7
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_api.py +14 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_mysql.py +15 -4
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_sql_placeholders.py +22 -17
- datacontract_cli-1.2.4/tests/test_custom_quality_checks.py +531 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_hana_quality_check.py +39 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_mysql.py +30 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_lint.py +1 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_quality_sql_dialects.py +4 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_postgres.py +13 -0
- datacontract_cli-1.2.4/tests/test_test_relationships.py +270 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_results_writer.py +6 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_untrusted_contract.py +1 -1
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_variables.py +19 -0
- datacontract_cli-1.2.3/datacontract/output/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/LICENSE +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/MANIFEST.in +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/breaking/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/breaking/detector.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/breaking/rules.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/catalog/catalog.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/changelog/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/changelog/changelog.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/changelog/normalize.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_api.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_breaking.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_catalog.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_changelog.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_dbt.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_edit.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_export.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_import.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_init.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_lint.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/command_publish.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/config/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/config/cli_context.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/data_contract.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/VERSION +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/datacontract-editor.css +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/datacontract-editor.es.js +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/index.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/monaco-4.7.0.js +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/odcs.svg +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/robots.txt +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/rolldown-runtime-DY7j01NX.js +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/editor_assets/sitemap.xml +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/check_filter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/physical_type_match.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/severity.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/type_normalize.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/hana/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/hana/hana_check_selection.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/hana/hana_connection.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/hana/hana_schema_check.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/hana/hana_type_mapping.py +0 -0
- {datacontract_cli-1.2.3/datacontract/engines/ibis → datacontract_cli-1.2.4/datacontract/engines/ibis/connections}/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/aws_credentials.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/databricks_patch.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/exasol_patch.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/hive_patch.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/iceberg.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/kafka.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/redshift_credentials.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/connections/redshift_patch.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/dtype_category.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/native_type.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/ibis/snowflake_structured_types.py +0 -0
- {datacontract_cli-1.2.3/datacontract/engines/ibis/connections → datacontract_cli-1.2.4/datacontract/export}/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/avro_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/avro_idl_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/bigquery_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/data_caterer_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/dbml_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/dbt_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/dqx_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/excel_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/great_expectations_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/html_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/iceberg_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/markdown_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/mermaid_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/protobuf_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/pydantic_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/rdf_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/sodacl_check_builder.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/sql_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/sqlalchemy_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/export/xsd_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/athena_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/clickhouse_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/dcs_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/excel_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/hive_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/json_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/object_storage_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/odata_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/odcs_helper.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/openapi_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/oracle_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/postgres_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/powerbi_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/pydantic_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/redshift_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/snowflake_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/spark_type_json.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/sqlserver_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/trino_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/imports/xsd_importer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/integration/dbt_sync.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/integration/dbt_test_mapping.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/lint/constraints.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/lint/files.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/lint/s3.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/breaking.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/changelog.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/enum_values.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/map_type.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/natural_keys.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/run.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/server.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/vector_type.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/model/workbook.py +0 -0
- {datacontract_cli-1.2.3/datacontract/export → datacontract_cli-1.2.4/datacontract/output}/__init__.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/output/ci_output.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/output/json_test_results.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/output/junit_test_results.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/output/text_breaking_results.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/output/text_changelog_results.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/py.typed +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/odcs-3.2.0.init.yaml +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/schemas/odcs-3.2.0.schema.json +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/excel/odcs-template-v3.0.xlsx +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/excel/odcs-template-v3.1.xlsx +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/excel/odcs-template-v3.2.xlsx +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/index.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/macros/authoritative_definitions.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/macros/context.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/macros/schema.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/macros/server.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/macros/support.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/model_field.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/context.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/custom_properties.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/diagram.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/dialog_yaml.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/footer.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/fundamentals.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/header.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/pricing.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/roles.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/schema.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/servers.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/sla.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/support.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/team.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/term_of_use.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/partials_odcs/title.html +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/setup.cfg +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_api_openapi.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_breaking.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_breaking_odcs_3_2.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_catalog.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_changelog.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_changelog_engine.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_changelog_normalize.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_changelog_output_text.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_check_quality_provenance.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_ci_output.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_cli.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_command_api.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_command_api_options.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_config.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_config_file.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_config_require.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_config_threading.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_athena.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_bigquery.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_clickhouse.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_databricks.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_exasol.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_hive.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_impala.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_oracle.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_postgres.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_redshift.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_s3_credentials.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_snowflake.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_sqlserver.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_connect_trino.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_array_items.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_nested.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_nested_type.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_physical_type.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_primary_key.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_retention_period.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_create_checks_servicelevel.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_data_contract.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_data_contract_checks.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_dbt_sync.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_dbt_test_mapping.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_description_linter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_docs_commands.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_docs_config_options.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_docs_ordering.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_dtype_category.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_edit.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_enum_values.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_avro.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_custom.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_custom_model.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_dcs.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_excel.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_go.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_html.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_large_contract.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_spark.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_sql.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_sql_clickhouse.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_export_xsd.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_hana_connection.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_hana_schema_check.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_hana_type_mapping.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_ibis_check_execute.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_ibis_mssql_pattern.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_ibis_mssql_schema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_ibis_oracle_schema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_athena.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_avro.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_clickhouse.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_csv.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_excel.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_glue.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_hive.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_json.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_object_storage.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_odata.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_openapi.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_oracle.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_postgres.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_powerbi.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_pydantic_model.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_redshift.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_snowflake.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_spark_type_json.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sql_clickhouse.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sql_hive.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sql_oracle.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sql_snowflake.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sql_struct.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_sqlserver.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_trino.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_unmapped_types.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_import_xsd.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_install_extras.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_lint_files.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_lint_odcs_3_2_constraints.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_lint_schema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_lint_urls.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_map_type.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_metadata_fields.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_native_type_schema_scope.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_nested_path_checks.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_oracle_patch.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_physical_type_match.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_publish_test_results.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_publish_test_results_payload.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_quality_unrunnable_rules.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_redshift_credentials.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_redshift_patch.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_resolve.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_resolve_definitions.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_resolve_local_definitions.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_roundtrip_pydantic_model.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_roundtrip_xsd.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_row_filter_duplicate_count.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_run_check_deprecated_fields.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_run_check_engine.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_server_overrides.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_server_type_mssql.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_server_type_synonyms.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_servers_3_2_0.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_snowflake_structured_types.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_sql_type_converter_physicaltype.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_api.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_api_openapi_import.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_array_items.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_azure_blob_file.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_checks_filter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_clickhouse.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_delta.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_diagnostics.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_dimension_filter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_dry_run.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_duckdb.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_failed_samples.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_hana.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_hive.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_iceberg.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_iceberg_rest.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_iceberg_s3tables.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_kafka_decoding.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_local_xml.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_metadata_only.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_mysql.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_nested_checks.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_oracle_xe.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_output_json.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_output_junit.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_quality.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_quality_id_and_tag_filter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_quality_local_fallback.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_quality_percent_severity.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_redshift.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_row_filter.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_s3_json_multiple_files.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_schema_evolution.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_server_not_found.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_soda_connection_error.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_trino.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_test_variables.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_type_normalize.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_untrusted_contract_variables.py +0 -0
- {datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/tests/test_vector_type.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: The datacontract CLI is an open source command-line tool for working with Data Contracts. It uses data contract YAML files to lint the data contract, connect to data sources and execute schema and quality tests, detect breaking changes, and export to different formats. The tool is written in Python. It can be used as a standalone CLI tool, in a CI/CD pipeline, or directly as a Python library.
|
|
5
5
|
Author-email: Jochen Christ <jochen.christ@entropy-data.com>, Stefan Negele <stefan.negele@innoq.com>, Simon Harrer <simon.harrer@entropy-data.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -40,7 +40,7 @@ Requires-Dist: jsonschema<5.0.0,>=4.23.0
|
|
|
40
40
|
Requires-Dist: pytz>=2024.1
|
|
41
41
|
Requires-Dist: python-multipart<1.0.0,>=0.0.20
|
|
42
42
|
Requires-Dist: rich<16.0,>=13.7
|
|
43
|
-
Requires-Dist: sqlglot<
|
|
43
|
+
Requires-Dist: sqlglot<31.0.0,>=26.6.0
|
|
44
44
|
Requires-Dist: python-dotenv<2.0.0,>=1.0.0
|
|
45
45
|
Requires-Dist: boto3<2.0.0,>=1.34.41
|
|
46
46
|
Requires-Dist: Jinja2<4.0.0,>=3.1.5
|
|
@@ -104,7 +104,7 @@ Requires-Dist: duckdb-extension-azure<1.6.0,>=1.5.0; extra == "azure"
|
|
|
104
104
|
Requires-Dist: azure-identity<1.26,>=1.17.1; extra == "azure"
|
|
105
105
|
Requires-Dist: azure-storage-blob<12.31,>=12.24; extra == "azure"
|
|
106
106
|
Provides-Extra: snowflake
|
|
107
|
-
Requires-Dist: snowflake-connector-python[pandas]<4.
|
|
107
|
+
Requires-Dist: snowflake-connector-python[pandas]<4.9,>=3.6; extra == "snowflake"
|
|
108
108
|
Requires-Dist: ibis-framework[snowflake]<13.0.0,>=10.0.0; extra == "snowflake"
|
|
109
109
|
Provides-Extra: sqlserver
|
|
110
110
|
Requires-Dist: ibis-framework[mssql]<13.0.0,>=10.0.0; extra == "sqlserver"
|
|
@@ -141,7 +141,7 @@ Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
|
|
|
141
141
|
Provides-Extra: rdf
|
|
142
142
|
Requires-Dist: rdflib==7.6.0; extra == "rdf"
|
|
143
143
|
Provides-Extra: api
|
|
144
|
-
Requires-Dist: fastapi<0.
|
|
144
|
+
Requires-Dist: fastapi<0.143.0,>=0.115.0; extra == "api"
|
|
145
145
|
Requires-Dist: uvicorn<0.55.0,>=0.44.0; extra == "api"
|
|
146
146
|
Provides-Extra: protobuf
|
|
147
147
|
Requires-Dist: proto-schema-parser<3.0,>=1.0; extra == "protobuf"
|
|
@@ -161,10 +161,10 @@ Requires-Dist: pre-commit<4.7.0,>=3.7.1; extra == "dev"
|
|
|
161
161
|
Requires-Dist: pytest; extra == "dev"
|
|
162
162
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
163
163
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
164
|
-
Requires-Dist: pymssql==2.4.
|
|
164
|
+
Requires-Dist: pymssql==2.4.2; extra == "dev"
|
|
165
165
|
Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == "dev"
|
|
166
166
|
Requires-Dist: mysql-connector-python<26.8.0,>=8.0.30; extra == "dev"
|
|
167
|
-
Requires-Dist: ruff==0.16.
|
|
167
|
+
Requires-Dist: ruff==0.16.10; extra == "dev"
|
|
168
168
|
Requires-Dist: testcontainers[kafka,minio,mssql,mysql,postgres]==4.15.0; extra == "dev"
|
|
169
169
|
Requires-Dist: trino==0.339.0; extra == "dev"
|
|
170
170
|
Dynamic: license-file
|
|
@@ -256,7 +256,7 @@ Server: production (type=postgres, host=aws-1-eu-central-2.pooler.supabase.com,
|
|
|
256
256
|
│ passed │ Check that field order_total has physical type INTEGER │ orders.order_total │ │
|
|
257
257
|
│ passed │ Check that field order_total has no missing values │ orders.order_total │ │
|
|
258
258
|
╰────────┴───────────────────────────────────────────────────────────────────┴─────────────────────────┴─────────╯
|
|
259
|
-
🟢 Data contract is valid.
|
|
259
|
+
🟢 Data contract is valid. Ran 30 checks. Took 2.504495 seconds.
|
|
260
260
|
```
|
|
261
261
|
|
|
262
262
|
Voilà, the CLI tested that the YAML itself is valid, all records comply with the schema, and all quality attributes are met.
|
|
@@ -85,7 +85,7 @@ Server: production (type=postgres, host=aws-1-eu-central-2.pooler.supabase.com,
|
|
|
85
85
|
│ passed │ Check that field order_total has physical type INTEGER │ orders.order_total │ │
|
|
86
86
|
│ passed │ Check that field order_total has no missing values │ orders.order_total │ │
|
|
87
87
|
╰────────┴───────────────────────────────────────────────────────────────────┴─────────────────────────┴─────────╯
|
|
88
|
-
🟢 Data contract is valid.
|
|
88
|
+
🟢 Data contract is valid. Ran 30 checks. Took 2.504495 seconds.
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
Voilà, the CLI tested that the YAML itself is valid, all records comply with the schema, and all quality attributes are met.
|
|
@@ -449,7 +449,8 @@ def config_from_headers(headers) -> "Config | None":
|
|
|
449
449
|
→ ``DATACONTRACT_SNOWFLAKE_PASSWORD``, ``entropy-data-api-key`` →
|
|
450
450
|
``ENTROPY_DATA_API_KEY``. Returns None when no config headers are present,
|
|
451
451
|
so env-var-configured deployments behave exactly as before. Unknown
|
|
452
|
-
``datacontract-*`` option names are rejected with a 400
|
|
452
|
+
``datacontract-*`` option names are rejected with a 400, and so is the
|
|
453
|
+
custom quality checks folder.
|
|
453
454
|
"""
|
|
454
455
|
known = known_env_names()
|
|
455
456
|
values = {}
|
|
@@ -457,6 +458,12 @@ def config_from_headers(headers) -> "Config | None":
|
|
|
457
458
|
lowered = name.lower()
|
|
458
459
|
env = lowered.upper().replace("-", "_")
|
|
459
460
|
if lowered.startswith(_CONFIG_HEADER_PREFIX) or env in known:
|
|
461
|
+
if env == "DATACONTRACT_CUSTOM_QUALITY_CHECKS":
|
|
462
|
+
# A folder on the server's disk is the operator's to choose, never the caller's.
|
|
463
|
+
raise HTTPException(
|
|
464
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
465
|
+
detail="The custom quality checks folder is configured by the API server, not per request.",
|
|
466
|
+
)
|
|
460
467
|
values[env] = value
|
|
461
468
|
if not values:
|
|
462
469
|
return None
|
|
@@ -15,7 +15,7 @@ from rich.markup import escape
|
|
|
15
15
|
from typer.core import TyperGroup
|
|
16
16
|
from typing_extensions import Annotated
|
|
17
17
|
|
|
18
|
-
from datacontract.config import Config, set_cli_config
|
|
18
|
+
from datacontract.config import Config, cli_config, set_cli_config
|
|
19
19
|
from datacontract.output.output_format import OutputFormat
|
|
20
20
|
|
|
21
21
|
console = Console()
|
|
@@ -31,6 +31,23 @@ inline_references_option = Annotated[
|
|
|
31
31
|
),
|
|
32
32
|
]
|
|
33
33
|
|
|
34
|
+
custom_quality_checks_option = Annotated[
|
|
35
|
+
Optional[Path],
|
|
36
|
+
typer.Option(
|
|
37
|
+
metavar="DIR",
|
|
38
|
+
help="Folder with the custom quality checks the contract's quality rules use, one YAML file per check. "
|
|
39
|
+
"Defaults to DATACONTRACT_CUSTOM_QUALITY_CHECKS.",
|
|
40
|
+
),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def config_with_custom_quality_checks(custom_quality_checks: Optional[Path]) -> Config | None:
|
|
45
|
+
"""The --config-file config, with the --custom-quality-checks folder if one was given."""
|
|
46
|
+
config = cli_config()
|
|
47
|
+
if custom_quality_checks is None:
|
|
48
|
+
return config
|
|
49
|
+
return Config.resolve(config).model_copy(update={"custom_quality_checks": str(custom_quality_checks)})
|
|
50
|
+
|
|
34
51
|
|
|
35
52
|
# Order in which top-level commands appear in `datacontract --help` (cf. README.md)
|
|
36
53
|
COMMAND_ORDER = [
|
|
@@ -130,6 +147,8 @@ app = typer.Typer(
|
|
|
130
147
|
cls=OrderedCommandsWithMigrationHints,
|
|
131
148
|
no_args_is_help=True,
|
|
132
149
|
add_completion=False,
|
|
150
|
+
# the locals of a --debug traceback can hold credentials
|
|
151
|
+
pretty_exceptions_show_locals=False,
|
|
133
152
|
help="CLI to manage data contracts. Documentation: https://docs.datacontract.com",
|
|
134
153
|
epilog="Read the full documentation at https://docs.datacontract.com",
|
|
135
154
|
)
|
|
@@ -10,14 +10,15 @@ from datacontract.cli import (
|
|
|
10
10
|
_print_logs,
|
|
11
11
|
_print_publish_failure,
|
|
12
12
|
app,
|
|
13
|
+
config_with_custom_quality_checks,
|
|
13
14
|
console,
|
|
15
|
+
custom_quality_checks_option,
|
|
14
16
|
debug_option,
|
|
15
17
|
enable_debug_logging,
|
|
16
18
|
inline_references_option,
|
|
17
19
|
resolve_output_format,
|
|
18
20
|
validate_publish_url,
|
|
19
21
|
)
|
|
20
|
-
from datacontract.config import cli_config
|
|
21
22
|
from datacontract.data_contract import DataContract
|
|
22
23
|
from datacontract.output.ci_output import write_ci_output, write_ci_summary, write_json_results
|
|
23
24
|
from datacontract.output.output_format import OutputFormat
|
|
@@ -80,6 +81,7 @@ def ci(
|
|
|
80
81
|
bool,
|
|
81
82
|
typer.Option(help="SSL verification when publishing the data contract."),
|
|
82
83
|
] = True,
|
|
84
|
+
custom_quality_checks: custom_quality_checks_option = None,
|
|
83
85
|
inline_references: inline_references_option = True,
|
|
84
86
|
debug: debug_option = None,
|
|
85
87
|
):
|
|
@@ -104,6 +106,7 @@ def ci(
|
|
|
104
106
|
# Plain text output for CI logs; --json sends human output to stderr.
|
|
105
107
|
out = Console(stderr=True, no_color=True) if json_output else Console(no_color=True)
|
|
106
108
|
|
|
109
|
+
config = config_with_custom_quality_checks(custom_quality_checks)
|
|
107
110
|
results = []
|
|
108
111
|
fail_results = {
|
|
109
112
|
"warning": {"warning", "failed", "error"},
|
|
@@ -115,7 +118,7 @@ def ci(
|
|
|
115
118
|
for location in locations:
|
|
116
119
|
out.print(f"Testing {location}")
|
|
117
120
|
run = DataContract(
|
|
118
|
-
config=
|
|
121
|
+
config=config,
|
|
119
122
|
data_contract_file=location,
|
|
120
123
|
schema_location=schema,
|
|
121
124
|
publish_url=publish,
|
|
@@ -10,7 +10,9 @@ from datacontract.cli import (
|
|
|
10
10
|
_print_logs,
|
|
11
11
|
_print_publish_failure,
|
|
12
12
|
app,
|
|
13
|
+
config_with_custom_quality_checks,
|
|
13
14
|
console,
|
|
15
|
+
custom_quality_checks_option,
|
|
14
16
|
debug_option,
|
|
15
17
|
enable_debug_logging,
|
|
16
18
|
inline_references_option,
|
|
@@ -200,6 +202,7 @@ def test(
|
|
|
200
202
|
bool,
|
|
201
203
|
typer.Option(help="SSL verification when publishing the data contract."),
|
|
202
204
|
] = True,
|
|
205
|
+
custom_quality_checks: custom_quality_checks_option = None,
|
|
203
206
|
inline_references: inline_references_option = True,
|
|
204
207
|
debug: debug_option = None,
|
|
205
208
|
):
|
|
@@ -231,7 +234,7 @@ def test(
|
|
|
231
234
|
if server == "all":
|
|
232
235
|
server = None
|
|
233
236
|
run = DataContract(
|
|
234
|
-
config=
|
|
237
|
+
config=config_with_custom_quality_checks(custom_quality_checks),
|
|
235
238
|
data_contract_file=location,
|
|
236
239
|
schema_location=schema,
|
|
237
240
|
publish_test_results=publish_test_results,
|
|
@@ -110,6 +110,7 @@ class Config(BaseSettings):
|
|
|
110
110
|
|
|
111
111
|
# general
|
|
112
112
|
api_header_authorization: SecretStr | None = None
|
|
113
|
+
custom_quality_checks: str | None = None
|
|
113
114
|
max_errors: int | None = None
|
|
114
115
|
|
|
115
116
|
# athena (credentials come from the s3_* options)
|
|
@@ -521,6 +522,10 @@ class Config(BaseSettings):
|
|
|
521
522
|
def get_api_header_authorization(self, required: bool = False) -> str | None:
|
|
522
523
|
return self._str_option("api_header_authorization", required)
|
|
523
524
|
|
|
525
|
+
# --- custom quality checks ---
|
|
526
|
+
def get_custom_quality_checks(self) -> str | None:
|
|
527
|
+
return self._str_option("custom_quality_checks")
|
|
528
|
+
|
|
524
529
|
# --- max ---
|
|
525
530
|
def get_max_errors(self) -> int | None:
|
|
526
531
|
return self._int_option("max_errors")
|
|
@@ -231,26 +231,56 @@ _DEFERRED_FIELDS = {
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
|
|
234
|
-
|
|
234
|
+
# Compared with the value a query returns, so a whole reference keeps the type it reads as.
|
|
235
|
+
_TYPED_FIELDS = {("DataQuality", "mustBe"), ("DataQuality", "mustNotBe")}
|
|
236
|
+
_PLAIN_NUMBER = re.compile(r"-?(0|[1-9][0-9]*)(\.[0-9]+)?")
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def resolve_runtime_variables(
|
|
240
|
+
value, source: str = "contract", variables: Optional[Mapping[str, str]] = None, typed: bool = False
|
|
241
|
+
):
|
|
235
242
|
"""Copy test inputs with variables resolved, recursively, without altering the contract.
|
|
236
243
|
|
|
237
244
|
Handles property names/types, enum values, logical type options, library
|
|
238
245
|
quality arguments, SLA values, and nested array/map definitions. Dictionary
|
|
239
|
-
keys are structural identifiers and are never interpolated.
|
|
246
|
+
keys are structural identifiers and are never interpolated. With ``typed``, a
|
|
247
|
+
value that is one whole reference becomes a number or boolean if its resolved
|
|
248
|
+
text is a plain one (``1000``, ``-2.5``, ``true``); ``007`` stays a string.
|
|
240
249
|
"""
|
|
241
250
|
if isinstance(value, BaseModel):
|
|
242
251
|
owner = type(value).__name__
|
|
243
252
|
updates = {}
|
|
244
253
|
for field in type(value).model_fields:
|
|
245
|
-
if field in _DEFERRED_FIELDS:
|
|
246
|
-
continue
|
|
247
254
|
original = getattr(value, field)
|
|
248
255
|
field_source = f"{source}.{_field_name(field)}"
|
|
249
|
-
|
|
256
|
+
# A custom quality check's arguments are test inputs, like a library metric's.
|
|
257
|
+
if (
|
|
258
|
+
field == "implementation"
|
|
259
|
+
and getattr(value, "engine", None) == "datacontract-cli"
|
|
260
|
+
and isinstance(original, dict)
|
|
261
|
+
and "arguments" in original
|
|
262
|
+
):
|
|
263
|
+
arguments = resolve_runtime_variables(original["arguments"], f"{field_source}.arguments", variables)
|
|
264
|
+
updates[field] = {**original, "arguments": arguments}
|
|
265
|
+
continue
|
|
266
|
+
if field in _DEFERRED_FIELDS:
|
|
267
|
+
continue
|
|
268
|
+
resolved = resolve_runtime_variables(original, field_source, variables, (owner, field) in _TYPED_FIELDS)
|
|
250
269
|
updates[field] = _checked(original, resolved, owner, field, field_source)
|
|
251
270
|
return value.model_copy(update=updates)
|
|
252
271
|
if isinstance(value, dict):
|
|
253
|
-
return {
|
|
272
|
+
return {
|
|
273
|
+
key: resolve_runtime_variables(item, f"{source}.{key}", variables, typed) for key, item in value.items()
|
|
274
|
+
}
|
|
254
275
|
if isinstance(value, list):
|
|
255
|
-
return [
|
|
256
|
-
|
|
276
|
+
return [
|
|
277
|
+
resolve_runtime_variables(item, f"{source}[{index}]", variables, typed) for index, item in enumerate(value)
|
|
278
|
+
]
|
|
279
|
+
resolved = resolve_variables(value, source=source, variables=variables)
|
|
280
|
+
if not typed or not isinstance(value, str) or not _VARIABLE.fullmatch(value):
|
|
281
|
+
return resolved
|
|
282
|
+
if _PLAIN_NUMBER.fullmatch(resolved):
|
|
283
|
+
return float(resolved) if "." in resolved else int(resolved)
|
|
284
|
+
if resolved in ("true", "false"):
|
|
285
|
+
return resolved == "true"
|
|
286
|
+
return resolved
|
|
@@ -27,6 +27,7 @@ class MetricType(str, Enum):
|
|
|
27
27
|
MISSING_COUNT = "missing_count"
|
|
28
28
|
DUPLICATE_COUNT = "duplicate_count"
|
|
29
29
|
INVALID_COUNT = "invalid_count"
|
|
30
|
+
MISSING_REFERENCE_COUNT = "missing_reference_count"
|
|
30
31
|
FIELD_PRESENT = "field_present"
|
|
31
32
|
FIELD_TYPE = "field_type"
|
|
32
33
|
FIELD_PHYSICAL_TYPE = "field_physical_type"
|
|
@@ -158,10 +159,14 @@ class CheckSpec:
|
|
|
158
159
|
expected_schema_property: Optional["SchemaProperty"] = None # FIELD_TYPE: structural comparison
|
|
159
160
|
expected_physical_type: Optional[str] = None # FIELD_PHYSICAL_TYPE: contract physicalType
|
|
160
161
|
|
|
161
|
-
columns: Optional[List[str]] = None # DUPLICATE_COUNT across multiple columns
|
|
162
|
+
columns: Optional[List[str]] = None # DUPLICATE_COUNT across multiple columns; MISSING_REFERENCE_COUNT keys
|
|
163
|
+
|
|
164
|
+
referenced_model: Optional[str] = None # MISSING_REFERENCE_COUNT
|
|
165
|
+
referenced_columns: Optional[List[str]] = None # MISSING_REFERENCE_COUNT, pairwise with `columns`
|
|
162
166
|
|
|
163
167
|
query: Optional[str] = None # CUSTOM_SQL (placeholders already substituted)
|
|
164
168
|
dialect: Optional[str] = None # CUSTOM_SQL input SQL dialect
|
|
169
|
+
diagnostics: Optional[dict] = None # CUSTOM_SQL: reported alongside the measured value
|
|
165
170
|
|
|
166
171
|
seconds: Optional[int] = None # FRESHNESS / RETENTION threshold in seconds
|
|
167
172
|
|
{datacontract_cli-1.2.3 → datacontract_cli-1.2.4}/datacontract/engines/checks/create_checks.py
RENAMED
|
@@ -25,6 +25,14 @@ from sqlglot import Dialect, exp
|
|
|
25
25
|
|
|
26
26
|
from datacontract.config.variables import VariableError, contains_variables, resolve_variables
|
|
27
27
|
from datacontract.engines.checks.check_spec import METADATA_METRICS, CheckSpec, MetricType, Op, Threshold
|
|
28
|
+
from datacontract.engines.checks.custom_quality_check import (
|
|
29
|
+
COLUMN_PLACEHOLDERS,
|
|
30
|
+
ENGINE,
|
|
31
|
+
CustomQualityCheckUnusable,
|
|
32
|
+
Instance,
|
|
33
|
+
instantiate,
|
|
34
|
+
placeholder_pattern,
|
|
35
|
+
)
|
|
28
36
|
from datacontract.engines.checks.dimensions import default_dimension
|
|
29
37
|
from datacontract.engines.checks.sql_guard import dialect_for_server_type, refusal_reason, sqlglot_dialect_by_name
|
|
30
38
|
from datacontract.engines.checks.type_normalize import normalize_type_name
|
|
@@ -191,7 +199,11 @@ def to_threshold(quality: DataQuality) -> Optional[Threshold]:
|
|
|
191
199
|
|
|
192
200
|
|
|
193
201
|
def prepare_query(
|
|
194
|
-
|
|
202
|
+
query: Optional[str],
|
|
203
|
+
model_name: str,
|
|
204
|
+
field_name: Optional[str],
|
|
205
|
+
server: Optional[Server],
|
|
206
|
+
instance: Optional[Instance] = None,
|
|
195
207
|
) -> Optional[str]:
|
|
196
208
|
"""Substitute placeholders in a user SQL query.
|
|
197
209
|
|
|
@@ -199,8 +211,9 @@ def prepare_query(
|
|
|
199
211
|
cannot read it bare, so a plain name keeps the backend's case-insensitive
|
|
200
212
|
resolution. Quotes the author wrote around a placeholder are dropped, except
|
|
201
213
|
that backticks force the name to be quoted (e.g. a reserved word on Spark).
|
|
214
|
+
For a custom quality check ``instance``, its arguments are substituted too.
|
|
202
215
|
"""
|
|
203
|
-
if not
|
|
216
|
+
if not query:
|
|
204
217
|
return None
|
|
205
218
|
|
|
206
219
|
dialect = sqlglot_dialect_by_name(dialect_for_server_type(get_server_type(server)))
|
|
@@ -213,17 +226,21 @@ def prepare_query(
|
|
|
213
226
|
for placeholder in ("dataset", "project", "catalog", "database"):
|
|
214
227
|
names[placeholder] = (getattr(server, placeholder, None) if server else None) or model_name
|
|
215
228
|
if field_name is not None:
|
|
216
|
-
names |= dict.fromkeys(
|
|
229
|
+
names |= dict.fromkeys(COLUMN_PLACEHOLDERS, field_name)
|
|
217
230
|
|
|
218
|
-
def identifier(
|
|
219
|
-
forced = "`" in match.group(0)
|
|
231
|
+
def identifier(name: str, forced: bool) -> str:
|
|
220
232
|
return ".".join(
|
|
221
233
|
exp.to_identifier(part, quoted=forced or not bare.fullmatch(part)).sql(dialect=dialect)
|
|
222
|
-
for part in
|
|
234
|
+
for part in name.split(".")
|
|
223
235
|
)
|
|
224
236
|
|
|
237
|
+
if instance is not None:
|
|
238
|
+
return instance.render(dialect, names, identifier)
|
|
239
|
+
|
|
225
240
|
# one pass, so a substituted name is not searched for placeholders again
|
|
226
|
-
return
|
|
241
|
+
return placeholder_pattern(list(names)).sub(
|
|
242
|
+
lambda match: identifier(names[match.group(1)], "`" in match.group(0)), query
|
|
243
|
+
)
|
|
227
244
|
|
|
228
245
|
|
|
229
246
|
# ---------------------------------------------------------------------------
|
|
@@ -234,6 +251,7 @@ def create_checks(
|
|
|
234
251
|
server: Optional[Server],
|
|
235
252
|
schema_name: str = "all",
|
|
236
253
|
variables: Optional[Mapping[str, str]] = None,
|
|
254
|
+
custom_quality_checks: Optional[str] = None,
|
|
237
255
|
) -> List[CheckSpec]:
|
|
238
256
|
checks: List[CheckSpec] = []
|
|
239
257
|
if data_contract.schema_ is None:
|
|
@@ -244,7 +262,8 @@ def create_checks(
|
|
|
244
262
|
if _is_azure_blob_schema(schema_obj, server):
|
|
245
263
|
# File-metadata checks are emitted by check_azure_blob_file
|
|
246
264
|
continue
|
|
247
|
-
checks.extend(_to_schema_checks(schema_obj, server, variables))
|
|
265
|
+
checks.extend(_to_schema_checks(schema_obj, server, variables, custom_quality_checks))
|
|
266
|
+
checks.extend(_relationship_checks(schema_obj, data_contract.schema_, server))
|
|
248
267
|
checks.extend(_to_servicelevel_checks(data_contract, server))
|
|
249
268
|
checks = [c for c in checks if c is not None]
|
|
250
269
|
# Schema and service level checks cannot declare an ODCS dimension, so fill
|
|
@@ -260,7 +279,10 @@ def _is_azure_blob_schema(schema_object: SchemaObject, server: Optional[Server])
|
|
|
260
279
|
|
|
261
280
|
|
|
262
281
|
def _to_schema_checks(
|
|
263
|
-
schema_object: SchemaObject,
|
|
282
|
+
schema_object: SchemaObject,
|
|
283
|
+
server: Optional[Server],
|
|
284
|
+
variables: Optional[Mapping[str, str]] = None,
|
|
285
|
+
custom_quality_checks: Optional[str] = None,
|
|
264
286
|
) -> List[CheckSpec]:
|
|
265
287
|
checks: List[CheckSpec] = []
|
|
266
288
|
server_type = get_server_type(server) if server is not None else None
|
|
@@ -575,7 +597,7 @@ def _to_schema_checks(
|
|
|
575
597
|
)
|
|
576
598
|
|
|
577
599
|
if prop.quality:
|
|
578
|
-
checks.extend(_quality_checks(model, field, prop.quality, server, variables))
|
|
600
|
+
checks.extend(_quality_checks(model, field, prop.quality, server, variables, custom_quality_checks))
|
|
579
601
|
|
|
580
602
|
# A check the server cannot run is reported, not dropped.
|
|
581
603
|
unenforced = []
|
|
@@ -613,11 +635,100 @@ def _to_schema_checks(
|
|
|
613
635
|
)
|
|
614
636
|
|
|
615
637
|
if schema_object.quality:
|
|
616
|
-
checks.extend(_quality_checks(model, None, schema_object.quality, server, variables))
|
|
638
|
+
checks.extend(_quality_checks(model, None, schema_object.quality, server, variables, custom_quality_checks))
|
|
617
639
|
|
|
618
640
|
return checks
|
|
619
641
|
|
|
620
642
|
|
|
643
|
+
def _relationship_checks(
|
|
644
|
+
schema_object: SchemaObject, schemas: List[SchemaObject], server: Optional[Server]
|
|
645
|
+
) -> List[CheckSpec]:
|
|
646
|
+
"""A foreign key holds when every non-null key in this model exists in the referenced model."""
|
|
647
|
+
server_type = get_server_type(server) if server is not None else None
|
|
648
|
+
model = to_schema_name(schema_object, server_type)
|
|
649
|
+
properties = schema_object.properties or []
|
|
650
|
+
declared = [(prop.name, rel) for prop in properties for rel in prop.relationships or []]
|
|
651
|
+
declared += [(None, rel) for rel in schema_object.relationships or []]
|
|
652
|
+
|
|
653
|
+
checks: List[CheckSpec] = []
|
|
654
|
+
for source, rel in declared:
|
|
655
|
+
if (rel.type or "foreignKey") != "foreignKey":
|
|
656
|
+
continue
|
|
657
|
+
sources = [source] if source is not None else rel.from_ if isinstance(rel.from_, list) else [rel.from_]
|
|
658
|
+
targets = rel.to if isinstance(rel.to, list) else [rel.to]
|
|
659
|
+
# `from` may repeat this schema's name; any other prefix is kept, so it matches no property.
|
|
660
|
+
source_names = [str(s).removeprefix(f"{schema_object.name}.") for s in sources if s]
|
|
661
|
+
parts = [str(t).rsplit(".", 1) for t in targets if t]
|
|
662
|
+
target_schema = next((s for s in schemas if parts and len(parts[0]) == 2 and s.name == parts[0][0]), None)
|
|
663
|
+
|
|
664
|
+
def physical(props, name):
|
|
665
|
+
prop = next((p for p in props or [] if p.name == name), None)
|
|
666
|
+
return None if prop is None else prop.physicalName or prop.name
|
|
667
|
+
|
|
668
|
+
columns = [physical(properties, name) for name in source_names]
|
|
669
|
+
referenced = [
|
|
670
|
+
physical(target_schema.properties, part[-1])
|
|
671
|
+
if target_schema is not None and part[0] == target_schema.name
|
|
672
|
+
else None
|
|
673
|
+
for part in parts
|
|
674
|
+
]
|
|
675
|
+
label = ", ".join(source_names) or "?"
|
|
676
|
+
if not columns or None in columns + referenced or len(referenced) != len(columns):
|
|
677
|
+
target_label = ", ".join(str(t) for t in targets)
|
|
678
|
+
if not columns or len(parts) != len(columns):
|
|
679
|
+
cause = "its from and to lists differ in length"
|
|
680
|
+
elif None in columns:
|
|
681
|
+
cause = f"{schema_object.name} has no property {source_names[columns.index(None)]}"
|
|
682
|
+
elif any(len(part) == 1 for part in parts):
|
|
683
|
+
cause = f"{next(part[0] for part in parts if len(part) == 1)} is not a schema.property reference"
|
|
684
|
+
elif target_schema is None:
|
|
685
|
+
cause = f"the contract has no schema {parts[0][0]}"
|
|
686
|
+
elif any(part[0] != target_schema.name for part in parts):
|
|
687
|
+
cause = "a composite key must reference a single schema"
|
|
688
|
+
else:
|
|
689
|
+
cause = f"{target_schema.name} has no property {parts[referenced.index(None)][-1]}"
|
|
690
|
+
checks.append(
|
|
691
|
+
CheckSpec(
|
|
692
|
+
key=f"{model}__{'__'.join(source_names)}__{'__'.join('__'.join(p) for p in parts)}"
|
|
693
|
+
"__field_relationships",
|
|
694
|
+
category="schema",
|
|
695
|
+
type="field_relationships",
|
|
696
|
+
name=f"Check that {label} has no values missing from {target_label}",
|
|
697
|
+
model=model,
|
|
698
|
+
field=source_names[0] if len(source_names) == 1 else None,
|
|
699
|
+
metric=MetricType.UNSUPPORTED,
|
|
700
|
+
preset_result="warning",
|
|
701
|
+
preset_reason=f"The relationship from {label} to {target_label} is not checked: {cause}.",
|
|
702
|
+
)
|
|
703
|
+
)
|
|
704
|
+
continue
|
|
705
|
+
|
|
706
|
+
referenced_model = to_schema_name(target_schema, server_type)
|
|
707
|
+
if len(columns) == 1:
|
|
708
|
+
name = f"Check that field {columns[0]} has no values missing from {referenced_model}.{referenced[0]}"
|
|
709
|
+
else:
|
|
710
|
+
name = (
|
|
711
|
+
f"Check that ({', '.join(columns)}) has no values missing from "
|
|
712
|
+
f"{referenced_model} ({', '.join(referenced)})"
|
|
713
|
+
)
|
|
714
|
+
checks.append(
|
|
715
|
+
CheckSpec(
|
|
716
|
+
key=f"{model}__{'__'.join(columns)}__{referenced_model}__{'__'.join(referenced)}__field_relationships",
|
|
717
|
+
category="schema",
|
|
718
|
+
type="field_relationships",
|
|
719
|
+
name=name,
|
|
720
|
+
model=model,
|
|
721
|
+
field=columns[0] if len(columns) == 1 else None,
|
|
722
|
+
metric=MetricType.MISSING_REFERENCE_COUNT,
|
|
723
|
+
threshold=Threshold(Op.EQ, 0),
|
|
724
|
+
columns=columns,
|
|
725
|
+
referenced_model=referenced_model,
|
|
726
|
+
referenced_columns=referenced,
|
|
727
|
+
)
|
|
728
|
+
)
|
|
729
|
+
return checks
|
|
730
|
+
|
|
731
|
+
|
|
621
732
|
# ---------------------------------------------------------------------------
|
|
622
733
|
# metric-check builders (preserve legacy keys / types)
|
|
623
734
|
# ---------------------------------------------------------------------------
|
|
@@ -719,10 +830,11 @@ def _quality_checks(
|
|
|
719
830
|
quality_list: List[DataQuality],
|
|
720
831
|
server: Optional[Server],
|
|
721
832
|
variables: Optional[Mapping[str, str]] = None,
|
|
833
|
+
custom_quality_checks: Optional[str] = None,
|
|
722
834
|
) -> List[CheckSpec]:
|
|
723
835
|
checks: List[CheckSpec] = []
|
|
724
836
|
for count, quality in enumerate(quality_list):
|
|
725
|
-
rule_checks = _quality_rule_checks(model, field, quality, count, server, variables)
|
|
837
|
+
rule_checks = _quality_rule_checks(model, field, quality, count, server, variables, custom_quality_checks)
|
|
726
838
|
# Every check keeps a link back to the rule that declared it, so that
|
|
727
839
|
# `test --quality-id` / `test --tag` can select it.
|
|
728
840
|
for check in rule_checks:
|
|
@@ -782,6 +894,8 @@ def _unexecuted_check(
|
|
|
782
894
|
quality: DataQuality,
|
|
783
895
|
reason: str,
|
|
784
896
|
result: str = "warning",
|
|
897
|
+
name: Optional[str] = None,
|
|
898
|
+
dimension: Optional[str] = None,
|
|
785
899
|
) -> List[CheckSpec]:
|
|
786
900
|
"""A rule the engine cannot run, reported rather than dropped."""
|
|
787
901
|
return [
|
|
@@ -789,11 +903,11 @@ def _unexecuted_check(
|
|
|
789
903
|
key=check_key,
|
|
790
904
|
category="quality",
|
|
791
905
|
type=check_type,
|
|
792
|
-
name=quality.description or unexecuted_check_name(model, field),
|
|
906
|
+
name=name or quality.description or unexecuted_check_name(model, field),
|
|
793
907
|
model=model,
|
|
794
908
|
field=field,
|
|
795
909
|
metric=MetricType.UNSUPPORTED,
|
|
796
|
-
dimension=quality.dimension,
|
|
910
|
+
dimension=dimension or quality.dimension,
|
|
797
911
|
severity=quality.severity,
|
|
798
912
|
preset_result=result,
|
|
799
913
|
preset_reason=reason,
|
|
@@ -801,6 +915,14 @@ def _unexecuted_check(
|
|
|
801
915
|
]
|
|
802
916
|
|
|
803
917
|
|
|
918
|
+
def _array_item_reason(field: str) -> str:
|
|
919
|
+
return (
|
|
920
|
+
f"'{field}' is an array item, not a column, so it cannot be substituted into a query. "
|
|
921
|
+
f"Declare the rule on '{field.split('[]')[0]}' instead and match the elements with array "
|
|
922
|
+
f"functions, for example size(filter(...)) > 0."
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
|
|
804
926
|
def _quality_rule_checks(
|
|
805
927
|
model: str,
|
|
806
928
|
field: Optional[str],
|
|
@@ -808,6 +930,7 @@ def _quality_rule_checks(
|
|
|
808
930
|
count: int,
|
|
809
931
|
server: Optional[Server],
|
|
810
932
|
variables: Optional[Mapping[str, str]] = None,
|
|
933
|
+
custom_quality_checks: Optional[str] = None,
|
|
811
934
|
) -> List[CheckSpec]:
|
|
812
935
|
"""The checks of a single ODCS quality rule (``count`` is its index in the list)."""
|
|
813
936
|
if quality.type == "custom" and quality.engine == "soda" and quality.implementation:
|
|
@@ -828,6 +951,45 @@ def _quality_rule_checks(
|
|
|
828
951
|
),
|
|
829
952
|
)
|
|
830
953
|
]
|
|
954
|
+
if quality.type == "custom" and quality.engine == ENGINE:
|
|
955
|
+
if field is None:
|
|
956
|
+
check_key = f"{model}__quality_custom_check_{count}"
|
|
957
|
+
check_type = "model_quality_custom"
|
|
958
|
+
else:
|
|
959
|
+
check_key = f"{model}__{field}__quality_custom_check_{count}"
|
|
960
|
+
check_type = "field_quality_custom"
|
|
961
|
+
if field is not None and "[]" in field:
|
|
962
|
+
return _unexecuted_check(check_key, check_type, model, field, quality, _array_item_reason(field))
|
|
963
|
+
dialect = dialect_for_server_type(get_server_type(server))
|
|
964
|
+
try:
|
|
965
|
+
instance = instantiate(quality, model, field, dialect, custom_quality_checks)
|
|
966
|
+
query = prepare_query(instance.query, model, field, server, instance)
|
|
967
|
+
except CustomQualityCheckUnusable as e:
|
|
968
|
+
return _unexecuted_check(
|
|
969
|
+
check_key, check_type, model, field, quality, e.reason, e.result, e.name, e.dimension
|
|
970
|
+
)
|
|
971
|
+
rule = instance.quality
|
|
972
|
+
refusal = refusal_reason(query, dialect)
|
|
973
|
+
if refusal is not None:
|
|
974
|
+
return _unexecuted_check(
|
|
975
|
+
check_key, check_type, model, field, rule, refusal, "failed", instance.name, rule.dimension
|
|
976
|
+
)
|
|
977
|
+
return [
|
|
978
|
+
CheckSpec(
|
|
979
|
+
key=check_key,
|
|
980
|
+
category="quality",
|
|
981
|
+
type=check_type,
|
|
982
|
+
name=instance.name,
|
|
983
|
+
model=model,
|
|
984
|
+
field=field,
|
|
985
|
+
metric=MetricType.CUSTOM_SQL,
|
|
986
|
+
threshold=to_threshold(rule),
|
|
987
|
+
query=query,
|
|
988
|
+
severity=rule.severity,
|
|
989
|
+
dimension=rule.dimension,
|
|
990
|
+
diagnostics=instance.diagnostics,
|
|
991
|
+
)
|
|
992
|
+
]
|
|
831
993
|
if quality.type == "sql":
|
|
832
994
|
if field is None:
|
|
833
995
|
check_key = f"{model}__quality_sql_{count}"
|
|
@@ -836,8 +998,6 @@ def _quality_rule_checks(
|
|
|
836
998
|
check_key = f"{model}__{field}__quality_sql_{count}"
|
|
837
999
|
check_type = "field_quality_sql"
|
|
838
1000
|
if field is not None and "[]" in field:
|
|
839
|
-
# An array item is not a column, so substituting it into the query
|
|
840
|
-
# would produce SQL no backend can parse.
|
|
841
1001
|
return [
|
|
842
1002
|
CheckSpec(
|
|
843
1003
|
key=check_key,
|
|
@@ -850,15 +1010,11 @@ def _quality_rule_checks(
|
|
|
850
1010
|
dimension=quality.dimension,
|
|
851
1011
|
severity=quality.severity,
|
|
852
1012
|
preset_result="warning",
|
|
853
|
-
preset_reason=(
|
|
854
|
-
f"'{field}' is an array item, not a column, so it cannot be substituted into a query. "
|
|
855
|
-
f"Declare the rule on '{field.split('[]')[0]}' instead and match the elements with array "
|
|
856
|
-
f"functions, for example size(filter(...)) > 0."
|
|
857
|
-
),
|
|
1013
|
+
preset_reason=_array_item_reason(field),
|
|
858
1014
|
)
|
|
859
1015
|
]
|
|
860
1016
|
threshold = to_threshold(quality)
|
|
861
|
-
query = prepare_query(quality, model, field, server)
|
|
1017
|
+
query = prepare_query(quality.query, model, field, server)
|
|
862
1018
|
if query is None:
|
|
863
1019
|
return _unexecuted_check(check_key, check_type, model, field, quality, "The rule has no query.")
|
|
864
1020
|
if threshold is None:
|