datacontract-cli 1.2.0__tar.gz → 1.2.1__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.0 → datacontract_cli-1.2.1}/MANIFEST.in +1 -1
- {datacontract_cli-1.2.0/datacontract_cli.egg-info → datacontract_cli-1.2.1}/PKG-INFO +45 -38
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/README.md +30 -30
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/api.py +47 -72
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/breaking/detector.py +7 -5
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/breaking/rules.py +47 -2
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/catalog/catalog.py +3 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/changelog/changelog.py +13 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/changelog/normalize.py +8 -7
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/cli.py +57 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_api.py +1 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_breaking.py +2 -8
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_changelog.py +2 -8
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_ci.py +2 -7
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_export.py +28 -10
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_lint.py +9 -8
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_test.py +3 -46
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/config/settings.py +58 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/data_contract.py +23 -5
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/create_checks.py +111 -16
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/dimensions.py +2 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/physical_type_match.py +44 -4
- datacontract_cli-1.2.1/datacontract/engines/checks/severity.py +11 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/sql_guard.py +5 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/data_contract_test.py +19 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/fastjsonschema/check_jsonschema.py +6 -4
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +3 -1
- datacontract_cli-1.2.1/datacontract/engines/hana/check_hana_execute.py +105 -0
- datacontract_cli-1.2.1/datacontract/engines/hana/hana_check_selection.py +76 -0
- datacontract_cli-1.2.1/datacontract/engines/hana/hana_connection.py +63 -0
- datacontract_cli-1.2.1/datacontract/engines/hana/hana_quality_check.py +707 -0
- datacontract_cli-1.2.1/datacontract/engines/hana/hana_schema_check.py +607 -0
- datacontract_cli-1.2.1/datacontract/engines/hana/hana_type_mapping.py +205 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/connect.py +108 -11
- datacontract_cli-1.2.1/datacontract/engines/ibis/connections/exasol_patch.py +24 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/ibis_check_execute.py +267 -71
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/native_type.py +21 -0
- datacontract_cli-1.2.1/datacontract/export/excel_exporter.py +1119 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/great_expectations_exporter.py +58 -19
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/html_exporter.py +3 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/sodacl_check_builder.py +13 -2
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/sql_type_converter.py +8 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/athena_importer.py +2 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/avro_importer.py +6 -6
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/csv_importer.py +20 -6
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/dbml_importer.py +2 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/dbt_importer.py +10 -8
- datacontract_cli-1.2.1/datacontract/imports/excel_importer.py +1070 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/glue_importer.py +10 -4
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/iceberg_importer.py +2 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/mysql_importer.py +8 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/object_storage_importer.py +9 -2
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/odcs_helper.py +66 -37
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/oracle_importer.py +8 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/postgres_importer.py +8 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/powerbi_importer.py +15 -6
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/pydantic_importer.py +4 -4
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/redshift_importer.py +8 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/snowflake_importer.py +8 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/spark_importer.py +2 -2
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/spark_type_json.py +2 -2
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/sql_importer.py +61 -18
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/sqlserver_importer.py +8 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/trino_importer.py +8 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/unity_importer.py +5 -2
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/init/init_template.py +3 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/integration/dbt_sync.py +54 -13
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/lint/resolve.py +151 -47
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/lint/schema.py +5 -3
- datacontract_cli-1.2.1/datacontract/model/natural_keys.py +18 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/run.py +6 -3
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/server.py +0 -1
- datacontract_cli-1.2.1/datacontract/model/workbook.py +260 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/text_breaking_results.py +9 -5
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/text_changelog_results.py +8 -4
- datacontract_cli-1.2.0/datacontract/templates/excel/odcs-template.xlsx → datacontract_cli-1.2.1/datacontract/templates/excel/odcs-template-v3.0.xlsx +0 -0
- datacontract_cli-1.2.1/datacontract/templates/excel/odcs-template-v3.1.xlsx +0 -0
- datacontract_cli-1.2.1/datacontract/templates/excel/odcs-template-v3.2.xlsx +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1/datacontract_cli.egg-info}/PKG-INFO +45 -38
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract_cli.egg-info/SOURCES.txt +25 -2
- datacontract_cli-1.2.1/datacontract_cli.egg-info/dependency_links.txt +1 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract_cli.egg-info/requires.txt +16 -7
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/pyproject.toml +28 -8
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_api.py +112 -17
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_breaking.py +153 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_changelog.py +53 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_changelog_normalize.py +7 -7
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_changelog_output_text.py +25 -6
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_cli.py +10 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_command_api.py +14 -0
- datacontract_cli-1.2.1/tests/test_connect_exasol.py +117 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_sqlserver.py +85 -9
- datacontract_cli-1.2.1/tests/test_create_checks_nested.py +187 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_create_checks_nested_type.py +28 -3
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_create_checks_servicelevel.py +60 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_dbt_sync.py +116 -4
- datacontract_cli-1.2.1/tests/test_export_excel.py +465 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_great_expectations.py +108 -0
- datacontract_cli-1.2.1/tests/test_hana_connection.py +99 -0
- datacontract_cli-1.2.1/tests/test_hana_quality_check.py +422 -0
- datacontract_cli-1.2.1/tests/test_hana_schema_check.py +436 -0
- datacontract_cli-1.2.1/tests/test_hana_type_mapping.py +94 -0
- datacontract_cli-1.2.1/tests/test_ibis_check_execute.py +152 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_csv.py +9 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_dbt.py +10 -0
- datacontract_cli-1.2.1/tests/test_import_excel.py +124 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_iceberg.py +12 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_object_storage.py +47 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_postgres.py +1 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_powerbi.py +0 -1
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_pydantic_model.py +12 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_redshift.py +1 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_spark_type_json.py +2 -2
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_sql_oracle.py +5 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_sql_postgres.py +30 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_sql_snowflake.py +16 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_sql_sqlserver.py +2 -0
- datacontract_cli-1.2.1/tests/test_import_unmapped_types.py +94 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_install_extras.py +2 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_lint.py +54 -0
- datacontract_cli-1.2.1/tests/test_nested_path_checks.py +102 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_physical_type_match.py +38 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_resolve_definitions.py +18 -1
- datacontract_cli-1.2.1/tests/test_row_filter_duplicate_count.py +61 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_servers_3_2_0.py +3 -3
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_snowflake_structured_types.py +1 -3
- datacontract_cli-1.2.1/tests/test_test_hana.py +415 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_untrusted_contract.py +17 -0
- datacontract_cli-1.2.0/datacontract/export/excel_exporter.py +0 -993
- datacontract_cli-1.2.0/datacontract/imports/excel_importer.py +0 -1134
- datacontract_cli-1.2.0/datacontract/schemas/odcs-3.0.1.schema.json +0 -2634
- datacontract_cli-1.2.0/tests/test_export_excel.py +0 -164
- datacontract_cli-1.2.0/tests/test_import_excel.py +0 -49
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/LICENSE +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/breaking/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/changelog/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_catalog.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_dbt.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_edit.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_import.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_init.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/command_publish.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/config/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/config/cli_context.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/config/variables.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/VERSION +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/datacontract-editor.css +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/datacontract-editor.es.js +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/index.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/monaco-4.7.0.js +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/odcs.svg +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/robots.txt +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/rolldown-runtime-DY7j01NX.js +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/editor_assets/sitemap.xml +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/check_filter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/check_spec.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/checks/type_normalize.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- /datacontract_cli-1.2.0/datacontract_cli.egg-info/dependency_links.txt → /datacontract_cli-1.2.1/datacontract/engines/hana/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/aws_credentials.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/databricks_patch.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/duckdb_connection.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/iceberg.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/kafka.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/redshift_credentials.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/connections/redshift_patch.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/dtype_category.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/engines/ibis/snowflake_structured_types.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/avro_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/avro_idl_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/bigquery_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/data_caterer_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/dbml_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/dbt_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/dqx_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/iceberg_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/markdown_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/mermaid_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/protobuf_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/pydantic_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/rdf_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/sql_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/export/sqlalchemy_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/dcs_importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/json_importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/integration/dbt_test_mapping.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/lint/constraints.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/lint/files.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/lint/s3.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/breaking.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/changelog.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/enum_values.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/map_type.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/model/vector_type.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/__init__.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/ci_output.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/json_test_results.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/junit_test_results.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/output/test_results_writer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/py.typed +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/odcs-3.2.0.init.yaml +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/schemas/odcs-3.2.0.schema.json +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/index.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/macros/authoritative_definitions.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/macros/context.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/macros/schema.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/macros/server.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/macros/support.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/model_field.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/context.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/custom_properties.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/diagram.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/dialog_yaml.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/footer.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/fundamentals.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/header.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/pricing.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/roles.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/schema.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/servers.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/sla.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/support.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/team.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/term_of_use.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/partials_odcs/title.html +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/setup.cfg +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_api_openapi.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_breaking_odcs_3_2.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_catalog.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_changelog_engine.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_check_quality_provenance.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_ci_output.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_config.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_config_file.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_config_require.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_config_threading.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_athena.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_bigquery.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_databricks.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_impala.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_mysql.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_oracle.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_postgres.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_redshift.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_s3_credentials.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_snowflake.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_connect_trino.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_create_checks_array_items.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_create_checks_physical_type.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_create_checks_primary_key.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_create_checks_retention_period.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_create_checks_sql_placeholders.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_data_contract.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_data_contract_checks.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_dbt_test_mapping.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_description_linter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_docs_commands.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_docs_config_options.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_docs_ordering.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_dtype_category.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_edit.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_enum_values.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_avro.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_custom.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_custom_model.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_dcs.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_go.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_html.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_large_contract.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_spark.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_sql.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_sql_clickhouse.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_ibis_mssql_pattern.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_ibis_mssql_schema.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_ibis_oracle_schema.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_athena.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_avro.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_glue.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_json.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_mysql.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_oracle.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_snowflake.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_sqlserver.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_trino.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_lint_odcs_3_2_constraints.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_lint_urls.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_map_type.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_metadata_fields.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_native_type_schema_scope.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_oracle_patch.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_publish_test_results.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_publish_test_results_payload.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_quality_sql_dialects.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_redshift_credentials.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_redshift_patch.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_resolve.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_resolve_local_definitions.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_roundtrip_pydantic_model.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_run_check_deprecated_fields.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_run_check_engine.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_server_overrides.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_server_type_mssql.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_server_type_synonyms.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_sql_type_converter_physicaltype.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_api.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_array_items.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_azure_blob_file.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_checks_filter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_delta.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_diagnostics.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_dimension_filter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_dry_run.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_duckdb.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_failed_samples.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_iceberg.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_iceberg_rest.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_iceberg_s3tables.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_kafka_decoding.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_metadata_only.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_mysql.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_oracle_xe.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_output_json.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_output_junit.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_quality.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_quality_id_and_tag_filter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_quality_local_fallback.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_quality_percent_severity.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_redshift.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_row_filter.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_schema_evolution.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_server_not_found.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_soda_connection_error.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_trino.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_test_variables.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_type_normalize.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_variables.py +0 -0
- {datacontract_cli-1.2.0 → datacontract_cli-1.2.1}/tests/test_vector_type.py +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
include datacontract/templates/style/output.css
|
|
2
|
-
include datacontract/templates/excel
|
|
2
|
+
include datacontract/templates/excel/*.xlsx
|
|
3
3
|
recursive-include datacontract/templates/ **/*.html
|
|
4
4
|
recursive-include datacontract/schemas/ **/*.json **/*.yaml
|
|
5
5
|
recursive-include datacontract/editor_assets/ *
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
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
|
|
@@ -53,7 +53,7 @@ Requires-Dist: avro==1.12.2; extra == "avro"
|
|
|
53
53
|
Provides-Extra: bigquery
|
|
54
54
|
Requires-Dist: ibis-framework[bigquery]<13.0.0,>=10.0.0; extra == "bigquery"
|
|
55
55
|
Provides-Extra: csv
|
|
56
|
-
Requires-Dist:
|
|
56
|
+
Requires-Dist: datacontract-cli[duckdb]; extra == "csv"
|
|
57
57
|
Provides-Extra: excel
|
|
58
58
|
Requires-Dist: openpyxl<4.0.0,>=3.1.5; extra == "excel"
|
|
59
59
|
Provides-Extra: dataframe
|
|
@@ -66,8 +66,8 @@ Requires-Dist: pyarrow-hotfix>=0.4; extra == "dataframe"
|
|
|
66
66
|
Requires-Dist: rich>=12.4.4; extra == "dataframe"
|
|
67
67
|
Provides-Extra: databricks
|
|
68
68
|
Requires-Dist: ibis-framework[databricks]<13.0.0,>=10.0.0; extra == "databricks"
|
|
69
|
-
Requires-Dist: databricks-sql-connector<4.
|
|
70
|
-
Requires-Dist: databricks-sdk<0.
|
|
69
|
+
Requires-Dist: databricks-sql-connector<4.6.0,>=3.7.0; extra == "databricks"
|
|
70
|
+
Requires-Dist: databricks-sdk<0.140.0; extra == "databricks"
|
|
71
71
|
Requires-Dist: packaging<27.0,>=21.3; extra == "databricks"
|
|
72
72
|
Provides-Extra: databricks-runtime
|
|
73
73
|
Requires-Dist: datacontract-cli[databricks]; extra == "databricks-runtime"
|
|
@@ -112,6 +112,13 @@ Requires-Dist: packaging<27.0,>=21.3; extra == "oracle"
|
|
|
112
112
|
Provides-Extra: athena
|
|
113
113
|
Requires-Dist: ibis-framework[athena]<13.0.0,>=10.0.0; extra == "athena"
|
|
114
114
|
Requires-Dist: packaging<27.0,>=21.3; extra == "athena"
|
|
115
|
+
Provides-Extra: hana
|
|
116
|
+
Requires-Dist: hdbcli<3.0.0,>=2.20.0; extra == "hana"
|
|
117
|
+
Provides-Extra: exasol
|
|
118
|
+
Requires-Dist: ibis-framework[exasol]<13.0.0,>=10.0.0; extra == "exasol"
|
|
119
|
+
Requires-Dist: pyexasol>=1.1.0; extra == "exasol"
|
|
120
|
+
Requires-Dist: packaging<27.0,>=21.3; extra == "exasol"
|
|
121
|
+
Requires-Dist: sqlglot>=26.31.0; extra == "exasol"
|
|
115
122
|
Provides-Extra: trino
|
|
116
123
|
Requires-Dist: ibis-framework[trino]<13.0.0,>=10.0.0; extra == "trino"
|
|
117
124
|
Requires-Dist: packaging<27.0,>=21.3; extra == "trino"
|
|
@@ -129,11 +136,11 @@ Provides-Extra: rdf
|
|
|
129
136
|
Requires-Dist: rdflib==7.6.0; extra == "rdf"
|
|
130
137
|
Provides-Extra: api
|
|
131
138
|
Requires-Dist: fastapi<0.142.0,>=0.115.0; extra == "api"
|
|
132
|
-
Requires-Dist: uvicorn<0.
|
|
139
|
+
Requires-Dist: uvicorn<0.54.0,>=0.44.0; extra == "api"
|
|
133
140
|
Provides-Extra: protobuf
|
|
134
141
|
Requires-Dist: proto-schema-parser<3.0,>=1.0; extra == "protobuf"
|
|
135
142
|
Provides-Extra: all
|
|
136
|
-
Requires-Dist: datacontract-cli[api,athena,avro,azure,bigquery,csv,databricks,dataframe,dbml,duckdb,excel,gcs,iceberg,impala,kafka,mysql,oracle,parquet,postgres,protobuf,rdf,redshift,s3,snowflake,sqlserver,trino]; extra == "all"
|
|
143
|
+
Requires-Dist: datacontract-cli[api,athena,avro,azure,bigquery,csv,databricks,dataframe,dbml,duckdb,exasol,excel,gcs,iceberg,impala,kafka,mysql,oracle,parquet,postgres,protobuf,rdf,redshift,s3,snowflake,sqlserver,trino]; extra == "all"
|
|
137
144
|
Provides-Extra: dev
|
|
138
145
|
Requires-Dist: datacontract-cli[all]; extra == "dev"
|
|
139
146
|
Requires-Dist: httpx==0.28.1; extra == "dev"
|
|
@@ -146,10 +153,10 @@ Requires-Dist: pre-commit<4.7.0,>=3.7.1; extra == "dev"
|
|
|
146
153
|
Requires-Dist: pytest; extra == "dev"
|
|
147
154
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
148
155
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
149
|
-
Requires-Dist: pymssql==2.4.
|
|
156
|
+
Requires-Dist: pymssql==2.4.1; extra == "dev"
|
|
150
157
|
Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == "dev"
|
|
151
158
|
Requires-Dist: mysql-connector-python<26.8.0,>=8.0.30; extra == "dev"
|
|
152
|
-
Requires-Dist: ruff==0.16.
|
|
159
|
+
Requires-Dist: ruff==0.16.8; extra == "dev"
|
|
153
160
|
Requires-Dist: testcontainers[kafka,minio,mssql,mysql,postgres]==4.15.0; extra == "dev"
|
|
154
161
|
Requires-Dist: trino==0.339.0; extra == "dev"
|
|
155
162
|
Dynamic: license-file
|
|
@@ -412,7 +419,7 @@ Released images are signed with [cosign](https://docs.sigstore.dev/cosign/signin
|
|
|
412
419
|
## Optional Dependencies (Extras)
|
|
413
420
|
|
|
414
421
|
The CLI tool defines several optional dependencies (also known as extras) that can be installed for using with specific servers types.
|
|
415
|
-
With _all_, all server dependencies are included.
|
|
422
|
+
With _all_, all server dependencies except `hana` are included.
|
|
416
423
|
|
|
417
424
|
```bash
|
|
418
425
|
uv tool install --python python3.11 --upgrade 'datacontract-cli[all]'
|
|
@@ -420,35 +427,35 @@ uv tool install --python python3.11 --upgrade 'datacontract-cli[all]'
|
|
|
420
427
|
|
|
421
428
|
A list of available extras:
|
|
422
429
|
|
|
423
|
-
| Dependency
|
|
424
|
-
|
|
425
|
-
|
|
|
426
|
-
|
|
|
427
|
-
|
|
|
428
|
-
|
|
|
429
|
-
|
|
|
430
|
-
| Databricks
|
|
431
|
-
|
|
|
432
|
-
|
|
|
433
|
-
|
|
|
434
|
-
|
|
|
435
|
-
| Excel
|
|
436
|
-
| GCS
|
|
437
|
-
|
|
|
438
|
-
|
|
|
439
|
-
|
|
|
440
|
-
|
|
|
441
|
-
|
|
|
442
|
-
|
|
|
443
|
-
|
|
|
444
|
-
|
|
|
445
|
-
|
|
|
446
|
-
|
|
|
447
|
-
|
|
|
448
|
-
|
|
|
449
|
-
|
|
|
450
|
-
|
|
|
451
|
-
|
|
|
430
|
+
| Dependency | Installation command |
|
|
431
|
+
|---|---|
|
|
432
|
+
| API (run as web server) | `pip install datacontract-cli[api]` |
|
|
433
|
+
| Amazon Athena | `pip install datacontract-cli[athena]` |
|
|
434
|
+
| Avro | `pip install datacontract-cli[avro]` |
|
|
435
|
+
| Azure | `pip install datacontract-cli[azure]` |
|
|
436
|
+
| Google BigQuery | `pip install datacontract-cli[bigquery]` |
|
|
437
|
+
| Databricks | `pip install datacontract-cli[databricks]` (also inside a Databricks Runtime, using the cluster's own Spark session) |
|
|
438
|
+
| DataFrame (Spark) | `pip install datacontract-cli[dataframe]` (PySpark not included — you supply the Spark session) |
|
|
439
|
+
| DBML | `pip install datacontract-cli[dbml]` |
|
|
440
|
+
| DuckDB (local file, CSV import and API response testing) | `pip install datacontract-cli[duckdb]` |
|
|
441
|
+
| Exasol | `pip install datacontract-cli[exasol]` |
|
|
442
|
+
| Excel | `pip install datacontract-cli[excel]` |
|
|
443
|
+
| GCS | `pip install datacontract-cli[gcs]` |
|
|
444
|
+
| SAP HANA / Datasphere | `pip install datacontract-cli[hana]` (not part of `all`: `hdbcli` is proprietary) |
|
|
445
|
+
| Apache Iceberg (schema import and export, REST catalog testing) | `pip install datacontract-cli[iceberg]` |
|
|
446
|
+
| Impala | `pip install datacontract-cli[impala]` |
|
|
447
|
+
| Kafka | `pip install datacontract-cli[kafka]` |
|
|
448
|
+
| MySQL | `pip install datacontract-cli[mysql]` |
|
|
449
|
+
| Oracle | `pip install datacontract-cli[oracle]` |
|
|
450
|
+
| Parquet | `pip install datacontract-cli[parquet]` |
|
|
451
|
+
| PostgreSQL | `pip install datacontract-cli[postgres]` |
|
|
452
|
+
| Protobuf | `pip install datacontract-cli[protobuf]` |
|
|
453
|
+
| RDF | `pip install datacontract-cli[rdf]` |
|
|
454
|
+
| Amazon Redshift | `pip install datacontract-cli[redshift]` |
|
|
455
|
+
| S3 | `pip install datacontract-cli[s3]` |
|
|
456
|
+
| Snowflake | `pip install datacontract-cli[snowflake]` |
|
|
457
|
+
| Microsoft SQL Server | `pip install datacontract-cli[sqlserver]` |
|
|
458
|
+
| Trino | `pip install datacontract-cli[trino]` |
|
|
452
459
|
|
|
453
460
|
|
|
454
461
|
## Documentation
|
|
@@ -256,7 +256,7 @@ Released images are signed with [cosign](https://docs.sigstore.dev/cosign/signin
|
|
|
256
256
|
## Optional Dependencies (Extras)
|
|
257
257
|
|
|
258
258
|
The CLI tool defines several optional dependencies (also known as extras) that can be installed for using with specific servers types.
|
|
259
|
-
With _all_, all server dependencies are included.
|
|
259
|
+
With _all_, all server dependencies except `hana` are included.
|
|
260
260
|
|
|
261
261
|
```bash
|
|
262
262
|
uv tool install --python python3.11 --upgrade 'datacontract-cli[all]'
|
|
@@ -264,35 +264,35 @@ uv tool install --python python3.11 --upgrade 'datacontract-cli[all]'
|
|
|
264
264
|
|
|
265
265
|
A list of available extras:
|
|
266
266
|
|
|
267
|
-
| Dependency
|
|
268
|
-
|
|
269
|
-
|
|
|
270
|
-
|
|
|
271
|
-
|
|
|
272
|
-
|
|
|
273
|
-
|
|
|
274
|
-
| Databricks
|
|
275
|
-
|
|
|
276
|
-
|
|
|
277
|
-
|
|
|
278
|
-
|
|
|
279
|
-
| Excel
|
|
280
|
-
| GCS
|
|
281
|
-
|
|
|
282
|
-
|
|
|
283
|
-
|
|
|
284
|
-
|
|
|
285
|
-
|
|
|
286
|
-
|
|
|
287
|
-
|
|
|
288
|
-
|
|
|
289
|
-
|
|
|
290
|
-
|
|
|
291
|
-
|
|
|
292
|
-
|
|
|
293
|
-
|
|
|
294
|
-
|
|
|
295
|
-
|
|
|
267
|
+
| Dependency | Installation command |
|
|
268
|
+
|---|---|
|
|
269
|
+
| API (run as web server) | `pip install datacontract-cli[api]` |
|
|
270
|
+
| Amazon Athena | `pip install datacontract-cli[athena]` |
|
|
271
|
+
| Avro | `pip install datacontract-cli[avro]` |
|
|
272
|
+
| Azure | `pip install datacontract-cli[azure]` |
|
|
273
|
+
| Google BigQuery | `pip install datacontract-cli[bigquery]` |
|
|
274
|
+
| Databricks | `pip install datacontract-cli[databricks]` (also inside a Databricks Runtime, using the cluster's own Spark session) |
|
|
275
|
+
| DataFrame (Spark) | `pip install datacontract-cli[dataframe]` (PySpark not included — you supply the Spark session) |
|
|
276
|
+
| DBML | `pip install datacontract-cli[dbml]` |
|
|
277
|
+
| DuckDB (local file, CSV import and API response testing) | `pip install datacontract-cli[duckdb]` |
|
|
278
|
+
| Exasol | `pip install datacontract-cli[exasol]` |
|
|
279
|
+
| Excel | `pip install datacontract-cli[excel]` |
|
|
280
|
+
| GCS | `pip install datacontract-cli[gcs]` |
|
|
281
|
+
| SAP HANA / Datasphere | `pip install datacontract-cli[hana]` (not part of `all`: `hdbcli` is proprietary) |
|
|
282
|
+
| Apache Iceberg (schema import and export, REST catalog testing) | `pip install datacontract-cli[iceberg]` |
|
|
283
|
+
| Impala | `pip install datacontract-cli[impala]` |
|
|
284
|
+
| Kafka | `pip install datacontract-cli[kafka]` |
|
|
285
|
+
| MySQL | `pip install datacontract-cli[mysql]` |
|
|
286
|
+
| Oracle | `pip install datacontract-cli[oracle]` |
|
|
287
|
+
| Parquet | `pip install datacontract-cli[parquet]` |
|
|
288
|
+
| PostgreSQL | `pip install datacontract-cli[postgres]` |
|
|
289
|
+
| Protobuf | `pip install datacontract-cli[protobuf]` |
|
|
290
|
+
| RDF | `pip install datacontract-cli[rdf]` |
|
|
291
|
+
| Amazon Redshift | `pip install datacontract-cli[redshift]` |
|
|
292
|
+
| S3 | `pip install datacontract-cli[s3]` |
|
|
293
|
+
| Snowflake | `pip install datacontract-cli[snowflake]` |
|
|
294
|
+
| Microsoft SQL Server | `pip install datacontract-cli[sqlserver]` |
|
|
295
|
+
| Trino | `pip install datacontract-cli[trino]` |
|
|
296
296
|
|
|
297
297
|
|
|
298
298
|
## Documentation
|
|
@@ -2,14 +2,12 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import secrets
|
|
5
|
-
import tempfile
|
|
6
5
|
from importlib import metadata
|
|
7
6
|
from typing import Annotated, Optional
|
|
8
7
|
|
|
9
8
|
import pydantic
|
|
10
|
-
import yaml
|
|
11
9
|
from fastapi import Body, Depends, FastAPI, HTTPException, Query, Request, status
|
|
12
|
-
from fastapi.responses import PlainTextResponse
|
|
10
|
+
from fastapi.responses import JSONResponse, PlainTextResponse
|
|
13
11
|
from fastapi.security.api_key import APIKeyHeader
|
|
14
12
|
from pydantic import BaseModel, Field, ValidationError
|
|
15
13
|
|
|
@@ -20,6 +18,8 @@ from datacontract.model.changelog import ChangelogEntry
|
|
|
20
18
|
from datacontract.model.exceptions import DataContractException, DefinitionResolutionError
|
|
21
19
|
from datacontract.model.run import Check, ResultEnum, Run
|
|
22
20
|
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
23
|
DATA_CONTRACT_EXAMPLE_PAYLOAD = """apiVersion: v3.2.0
|
|
24
24
|
kind: DataContract
|
|
25
25
|
id: orders
|
|
@@ -335,6 +335,25 @@ app = FastAPI(
|
|
|
335
335
|
],
|
|
336
336
|
)
|
|
337
337
|
|
|
338
|
+
|
|
339
|
+
@app.exception_handler(pydantic.ValidationError)
|
|
340
|
+
def _validation_error(request: Request, e: pydantic.ValidationError):
|
|
341
|
+
return JSONResponse(status_code=422, content={"detail": f"Invalid data contract: {e}"})
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
@app.exception_handler(DataContractException)
|
|
345
|
+
def _data_contract_exception(request: Request, e: DataContractException):
|
|
346
|
+
return JSONResponse(status_code=422, content={"detail": f"Data Contract Validation Failure: {e}"})
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@app.exception_handler(DefinitionResolutionError)
|
|
350
|
+
def _definition_resolution_error(request: Request, e: DefinitionResolutionError):
|
|
351
|
+
# The reason names the host that was contacted and what it answered.
|
|
352
|
+
# Omit for security reasons.
|
|
353
|
+
logger.warning("Definition resolution failed: %s", e)
|
|
354
|
+
return JSONResponse(status_code=422, content={"detail": f"Could not resolve authoritative definition '{e.url}'."})
|
|
355
|
+
|
|
356
|
+
|
|
338
357
|
_fastapi_openapi = app.openapi
|
|
339
358
|
|
|
340
359
|
|
|
@@ -481,6 +500,7 @@ _ENVIRONMENT_CREDENTIAL_TARGETS: dict[str, tuple[str, str | None, tuple[str, ...
|
|
|
481
500
|
"oracle": ("host", "oracle_host", ("oracle_password",)),
|
|
482
501
|
"impala": ("host", "impala_host", ("impala_password",)),
|
|
483
502
|
"trino": ("host", "trino_host", ("trino_password",)),
|
|
503
|
+
"exasol": ("host", "exasol_host", ("exasol_password",)),
|
|
484
504
|
"redshift": ("host", "redshift_host", ("redshift_password",)),
|
|
485
505
|
"sqlserver": ("host", "sqlserver_host", ("sqlserver_password",)),
|
|
486
506
|
"snowflake": (
|
|
@@ -665,21 +685,21 @@ def _reject_request_platform_host_with_environment_key(config) -> None:
|
|
|
665
685
|
def check_api_key(api_key_header: str | None):
|
|
666
686
|
correct_api_key = os.getenv("DATACONTRACT_CLI_API_KEY")
|
|
667
687
|
if correct_api_key is None or correct_api_key == "":
|
|
668
|
-
|
|
688
|
+
logger.info("Environment variable DATACONTRACT_CLI_API_KEY is not set. Skip API key check.")
|
|
669
689
|
return
|
|
670
690
|
if api_key_header is None or api_key_header == "":
|
|
671
|
-
|
|
691
|
+
logger.warning("The API key is missing.")
|
|
672
692
|
raise HTTPException(
|
|
673
693
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
674
694
|
detail="Missing API key. Use Header 'x-api-key' to provide the API key.",
|
|
675
695
|
)
|
|
676
|
-
if not secrets.compare_digest(api_key_header, correct_api_key):
|
|
677
|
-
|
|
696
|
+
if not secrets.compare_digest(api_key_header.encode(), correct_api_key.encode()):
|
|
697
|
+
logger.warning("The provided API key is not correct.")
|
|
678
698
|
raise HTTPException(
|
|
679
699
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
680
700
|
detail="The provided API key is not correct.",
|
|
681
701
|
)
|
|
682
|
-
|
|
702
|
+
logger.info("Request authenticated with API key.")
|
|
683
703
|
pass
|
|
684
704
|
|
|
685
705
|
|
|
@@ -777,8 +797,7 @@ async def test(
|
|
|
777
797
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
778
798
|
detail="Use either the filter or the filters parameter, not both.",
|
|
779
799
|
)
|
|
780
|
-
|
|
781
|
-
logging.info(body)
|
|
800
|
+
logger.info("Testing data contract...")
|
|
782
801
|
config = config_from_headers(request.headers)
|
|
783
802
|
untrusted_contract = getattr(request.app.state, "untrusted_contracts", False)
|
|
784
803
|
if untrusted_contract:
|
|
@@ -857,7 +876,10 @@ async def lint(
|
|
|
857
876
|
) -> LintResponse:
|
|
858
877
|
check_api_key(api_key)
|
|
859
878
|
data_contract = DataContract(
|
|
860
|
-
data_contract_str=body,
|
|
879
|
+
data_contract_str=body,
|
|
880
|
+
schema_location=_require_schema_url(schema),
|
|
881
|
+
all_errors=all_errors,
|
|
882
|
+
untrusted_contract=True,
|
|
861
883
|
)
|
|
862
884
|
lint_result = data_contract.lint()
|
|
863
885
|
return LintResponse(result=lint_result.result, checks=lint_result.checks)
|
|
@@ -933,30 +955,10 @@ async def changelog_endpoint(
|
|
|
933
955
|
) -> ChangelogResponse:
|
|
934
956
|
check_api_key(api_key)
|
|
935
957
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
f2.write(body.v2)
|
|
941
|
-
v2_path = f2.name
|
|
942
|
-
|
|
943
|
-
try:
|
|
944
|
-
result = DataContract(data_contract_file=v1_path).changelog(DataContract(data_contract_file=v2_path))
|
|
945
|
-
return ChangelogResponse(summary=result.summary, entries=result.entries)
|
|
946
|
-
except yaml.YAMLError as e:
|
|
947
|
-
raise HTTPException(status_code=422, detail=f"Invalid YAML: {e}")
|
|
948
|
-
except pydantic.ValidationError as e:
|
|
949
|
-
raise HTTPException(status_code=422, detail=f"Invalid data contract: {e}")
|
|
950
|
-
except DefinitionResolutionError as e:
|
|
951
|
-
# The reason names the host that was contacted and what it answered.
|
|
952
|
-
# Omit for security reasons.
|
|
953
|
-
logging.warning("Definition resolution failed: %s", e)
|
|
954
|
-
raise HTTPException(status_code=422, detail=f"Could not resolve authoritative definition '{e.url}'.")
|
|
955
|
-
except DataContractException as e:
|
|
956
|
-
raise HTTPException(status_code=422, detail=f"Data Contract Validation Failure: {e}")
|
|
957
|
-
finally:
|
|
958
|
-
os.unlink(v1_path)
|
|
959
|
-
os.unlink(v2_path)
|
|
958
|
+
result = DataContract(data_contract_str=body.v1, untrusted_contract=True).changelog(
|
|
959
|
+
DataContract(data_contract_str=body.v2, untrusted_contract=True)
|
|
960
|
+
)
|
|
961
|
+
return ChangelogResponse(summary=result.summary, entries=result.entries)
|
|
960
962
|
|
|
961
963
|
|
|
962
964
|
@app.post(
|
|
@@ -986,25 +988,10 @@ def breaking_endpoint(
|
|
|
986
988
|
) -> BreakingChangesResponse:
|
|
987
989
|
check_api_key(api_key)
|
|
988
990
|
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
f2.write(body.v2)
|
|
994
|
-
v2_path = f2.name
|
|
995
|
-
|
|
996
|
-
try:
|
|
997
|
-
result = DataContract(data_contract_file=v1_path).breaking(DataContract(data_contract_file=v2_path))
|
|
998
|
-
return BreakingChangesResponse(summary=result.summary, entries=result.entries, is_breaking=result.is_breaking)
|
|
999
|
-
except yaml.YAMLError as e:
|
|
1000
|
-
raise HTTPException(status_code=422, detail=f"Invalid YAML: {e}")
|
|
1001
|
-
except pydantic.ValidationError as e:
|
|
1002
|
-
raise HTTPException(status_code=422, detail=f"Invalid data contract: {e}")
|
|
1003
|
-
except DataContractException as e:
|
|
1004
|
-
raise HTTPException(status_code=422, detail=f"Data Contract Validation Failure: {e}")
|
|
1005
|
-
finally:
|
|
1006
|
-
os.unlink(v1_path)
|
|
1007
|
-
os.unlink(v2_path)
|
|
991
|
+
result = DataContract(data_contract_str=body.v1, untrusted_contract=True).breaking(
|
|
992
|
+
DataContract(data_contract_str=body.v2, untrusted_contract=True)
|
|
993
|
+
)
|
|
994
|
+
return BreakingChangesResponse(summary=result.summary, entries=result.entries, is_breaking=result.is_breaking)
|
|
1008
995
|
|
|
1009
996
|
|
|
1010
997
|
@app.post(
|
|
@@ -1107,21 +1094,9 @@ def export(
|
|
|
1107
1094
|
] = None,
|
|
1108
1095
|
):
|
|
1109
1096
|
check_api_key(api_key)
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
)
|
|
1117
|
-
except yaml.YAMLError as e:
|
|
1118
|
-
raise HTTPException(status_code=422, detail=f"Invalid YAML: {e}")
|
|
1119
|
-
except pydantic.ValidationError as e:
|
|
1120
|
-
raise HTTPException(status_code=422, detail=f"Invalid data contract: {e}")
|
|
1121
|
-
except DefinitionResolutionError as e:
|
|
1122
|
-
# The reason names the host that was contacted and what it answered.
|
|
1123
|
-
# Omit for security reasons.
|
|
1124
|
-
logging.warning("Definition resolution failed: %s", e)
|
|
1125
|
-
raise HTTPException(status_code=422, detail=f"Could not resolve authoritative definition '{e.url}'.")
|
|
1126
|
-
except DataContractException as e:
|
|
1127
|
-
raise HTTPException(status_code=422, detail=f"Data Contract Validation Failure: {e}")
|
|
1097
|
+
return DataContract(data_contract_str=body, server=server, untrusted_contract=True).export(
|
|
1098
|
+
export_format=format,
|
|
1099
|
+
model=model,
|
|
1100
|
+
rdf_base=rdf_base,
|
|
1101
|
+
sql_server_type=sql_server_type,
|
|
1102
|
+
)
|
|
@@ -22,14 +22,16 @@ class BreakingChangeDetector:
|
|
|
22
22
|
|
|
23
23
|
def detect(self, changelog: ChangelogResult) -> BreakingChangeResult:
|
|
24
24
|
entries = [self._classify(entry) for entry in changelog.entries]
|
|
25
|
-
# Nothing inside
|
|
26
|
-
|
|
25
|
+
# Nothing inside an added element can break a consumer: it did not exist before.
|
|
26
|
+
# Inside a removed one, the element's own entry carries the grade; its former
|
|
27
|
+
# constraints are gone, which is a relaxation.
|
|
28
|
+
added_or_removed = {
|
|
27
29
|
entry.path
|
|
28
30
|
for entry in entries
|
|
29
|
-
if entry.change_type
|
|
31
|
+
if entry.change_type in (ChangelogType.added, ChangelogType.removed)
|
|
30
32
|
and (
|
|
31
33
|
entry.path.startswith("schema.")
|
|
32
|
-
and (len(entry.path.split(".")) == 2 or entry.path.split(".")[-2]
|
|
34
|
+
and (len(entry.path.split(".")) == 2 or entry.path.split(".")[-2] in ("properties", "quality"))
|
|
33
35
|
)
|
|
34
36
|
}
|
|
35
37
|
removed_enums = {
|
|
@@ -46,7 +48,7 @@ class BreakingChangeDetector:
|
|
|
46
48
|
added_values[entry.path.rsplit(".enum.", 1)[0]].add(entry.new_value)
|
|
47
49
|
for entry in entries:
|
|
48
50
|
segments = entry.path.split(".")
|
|
49
|
-
if any(".".join(segments[:i]) in
|
|
51
|
+
if any(".".join(segments[:i]) in added_or_removed for i in range(1, len(segments))):
|
|
50
52
|
entry.level = BreakingChangeLevel.INFO
|
|
51
53
|
if entry.rule_id == "enum-constraint-changed":
|
|
52
54
|
if any(entry.path.startswith(path + ".") for path in removed_enums):
|
|
@@ -160,6 +160,50 @@ class EnumConstraintRule(BreakingChangeRule):
|
|
|
160
160
|
return RuleEvaluation(self.rule_id, level, _change_message("allowed values", entry))
|
|
161
161
|
|
|
162
162
|
|
|
163
|
+
class QualityConstraintRule(BreakingChangeRule):
|
|
164
|
+
rule_id = "quality-constraint-changed"
|
|
165
|
+
_thresholds = (
|
|
166
|
+
".mustBeLessThan",
|
|
167
|
+
".mustBeLessOrEqualTo",
|
|
168
|
+
".mustBeGreaterThan",
|
|
169
|
+
".mustBeGreaterOrEqualTo",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
|
|
173
|
+
if not entry.path.startswith("schema.") or ".quality." not in entry.path:
|
|
174
|
+
return None
|
|
175
|
+
rule_path = entry.path.rsplit(".quality.", 1)[1]
|
|
176
|
+
if rule_path.endswith(".arguments.validValues"):
|
|
177
|
+
# The diff emits one entry per list element.
|
|
178
|
+
level = BreakingChangeLevel.INFO if entry.type == ChangelogType.added else BreakingChangeLevel.ERROR
|
|
179
|
+
elif rule_path.endswith(".arguments.invalidValues"):
|
|
180
|
+
level = BreakingChangeLevel.INFO if entry.type == ChangelogType.removed else BreakingChangeLevel.ERROR
|
|
181
|
+
elif rule_path.endswith(self._thresholds):
|
|
182
|
+
old = _parse_number(entry.old_value)
|
|
183
|
+
new = _parse_number(entry.new_value)
|
|
184
|
+
if entry.type == ChangelogType.removed:
|
|
185
|
+
level = BreakingChangeLevel.INFO
|
|
186
|
+
elif old is None or new is None:
|
|
187
|
+
level = BreakingChangeLevel.WARNING
|
|
188
|
+
elif _is_tightening(entry.path, old, new):
|
|
189
|
+
level = BreakingChangeLevel.ERROR
|
|
190
|
+
else:
|
|
191
|
+
level = BreakingChangeLevel.INFO
|
|
192
|
+
elif "." not in rule_path:
|
|
193
|
+
# A new rule is a constraint existing data may not satisfy; a removed one is a relaxation.
|
|
194
|
+
level = BreakingChangeLevel.ERROR if entry.type == ChangelogType.added else BreakingChangeLevel.INFO
|
|
195
|
+
elif rule_path.endswith((".description", ".dimension", ".businessImpact", ".severity")):
|
|
196
|
+
level = BreakingChangeLevel.INFO
|
|
197
|
+
elif ".customProperties." in rule_path or ".authoritativeDefinitions." in rule_path or ".tags" in rule_path:
|
|
198
|
+
level = BreakingChangeLevel.INFO
|
|
199
|
+
else:
|
|
200
|
+
# What the rule checks changed (type, metric, query, other arguments, thresholds we cannot order).
|
|
201
|
+
level = BreakingChangeLevel.WARNING
|
|
202
|
+
name, _, field = rule_path.partition(".")
|
|
203
|
+
subject = f"{field} of quality rule '{name}'" if field else "quality rule"
|
|
204
|
+
return RuleEvaluation(self.rule_id, level, _change_message(subject, entry))
|
|
205
|
+
|
|
206
|
+
|
|
163
207
|
class VectorShapeRule(BreakingChangeRule):
|
|
164
208
|
rule_id = "vector-shape-changed"
|
|
165
209
|
|
|
@@ -206,9 +250,9 @@ def _parse_number(value: str | None) -> float | None:
|
|
|
206
250
|
|
|
207
251
|
|
|
208
252
|
def _is_tightening(path: str, old: float, new: float) -> bool:
|
|
209
|
-
if path.endswith((".minLength", ".minimum", ".exclusiveMinimum")):
|
|
253
|
+
if path.endswith((".minLength", ".minimum", ".exclusiveMinimum", ".mustBeGreaterThan", ".mustBeGreaterOrEqualTo")):
|
|
210
254
|
return new > old
|
|
211
|
-
if path.endswith((".maxLength", ".maximum", ".exclusiveMaximum")):
|
|
255
|
+
if path.endswith((".maxLength", ".maximum", ".exclusiveMaximum", ".mustBeLessThan", ".mustBeLessOrEqualTo")):
|
|
212
256
|
return new < old
|
|
213
257
|
return True
|
|
214
258
|
|
|
@@ -222,6 +266,7 @@ def _change_message(subject: str, entry: ChangelogEntry) -> str:
|
|
|
222
266
|
|
|
223
267
|
|
|
224
268
|
DEFAULT_RULES: tuple[BreakingChangeRule, ...] = (
|
|
269
|
+
QualityConstraintRule(),
|
|
225
270
|
RequiredChangedRule(),
|
|
226
271
|
SchemaRemovedRule(),
|
|
227
272
|
FieldRemovedRule(),
|
|
@@ -12,6 +12,8 @@ from datacontract.config import cli_config
|
|
|
12
12
|
from datacontract.data_contract import DataContract
|
|
13
13
|
from datacontract.export.html_exporter import get_version
|
|
14
14
|
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
def _get_owner(odcs: OpenDataContractStandard) -> Optional[str]:
|
|
17
19
|
"""Get the owner from ODCS customProperties or team."""
|
|
@@ -25,7 +27,7 @@ def _get_owner(odcs: OpenDataContractStandard) -> Optional[str]:
|
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def create_data_contract_html(contracts, file: Path, path: Path, schema: str):
|
|
28
|
-
|
|
30
|
+
logger.debug(f"Creating data contract html for file {file} and schema {schema}")
|
|
29
31
|
data_contract = DataContract(
|
|
30
32
|
data_contract_file=f"{file.absolute()}", inline_references=True, schema_location=schema, config=cli_config()
|
|
31
33
|
)
|
|
@@ -26,7 +26,19 @@ def diff(v1: dict, v2: dict) -> dict:
|
|
|
26
26
|
n1 = normalize(v1)
|
|
27
27
|
n2 = normalize(v2)
|
|
28
28
|
result = DeepDiff(n1, n2, ignore_order=True, verbose_level=2)
|
|
29
|
-
|
|
29
|
+
result = json.loads(result.to_json())
|
|
30
|
+
# DeepDiff reports two dicts that share no key as one value change of the whole
|
|
31
|
+
# dict (e.g. the only schema renamed). Split it into per-key removals and additions.
|
|
32
|
+
for path, change in list(result.get("values_changed", {}).items()):
|
|
33
|
+
old, new = change.get("old_value"), change.get("new_value")
|
|
34
|
+
if not (isinstance(old, dict) and isinstance(new, dict)):
|
|
35
|
+
continue
|
|
36
|
+
del result["values_changed"][path]
|
|
37
|
+
for key, value in old.items():
|
|
38
|
+
result.setdefault("dictionary_item_removed", {})[f"{path}['{key}']"] = value
|
|
39
|
+
for key, value in new.items():
|
|
40
|
+
result.setdefault("dictionary_item_added", {})[f"{path}['{key}']"] = value
|
|
41
|
+
return result
|
|
30
42
|
|
|
31
43
|
|
|
32
44
|
_CHANGE_TYPE_MAP = {
|
|
@@ -66,11 +66,12 @@ description.customProperties[] CustomProperty -> .property
|
|
|
66
66
|
def _normalize_by(items: list[dict], key_field: str) -> dict:
|
|
67
67
|
"""Key a list of dicts by a named field, omitting the key field from the value.
|
|
68
68
|
|
|
69
|
-
Falls back to the list index if the key field is absent on an item.
|
|
69
|
+
Falls back to the list index, as `[i]`, if the key field is absent on an item.
|
|
70
|
+
(Not `__pos_i__`: DeepDiff skips `__*__` keys as private by default.)
|
|
70
71
|
"""
|
|
71
72
|
result = {}
|
|
72
73
|
for i, item in enumerate(items):
|
|
73
|
-
key = item.get(key_field, f"
|
|
74
|
+
key = item.get(key_field, f"[{i}]")
|
|
74
75
|
result[key] = {k: v for k, v in item.items() if k != key_field}
|
|
75
76
|
return result
|
|
76
77
|
|
|
@@ -84,7 +85,7 @@ def _normalize_auth_defs(items: list[dict]) -> dict:
|
|
|
84
85
|
"""
|
|
85
86
|
result = {}
|
|
86
87
|
for i, item in enumerate(items):
|
|
87
|
-
key = item.get("url") or item.get("id") or f"
|
|
88
|
+
key = item.get("url") or item.get("id") or f"[{i}]"
|
|
88
89
|
result[key] = item
|
|
89
90
|
return result
|
|
90
91
|
|
|
@@ -96,7 +97,7 @@ def _normalize_keyed(items: list[dict], *keys: str) -> dict:
|
|
|
96
97
|
"""
|
|
97
98
|
result = {}
|
|
98
99
|
for i, item in enumerate(items):
|
|
99
|
-
key = next((str(item[k]) for k in keys if item.get(k) is not None), None) or f"
|
|
100
|
+
key = next((str(item[k]) for k in keys if item.get(k) is not None), None) or f"[{i}]"
|
|
100
101
|
result[key] = item
|
|
101
102
|
return result
|
|
102
103
|
|
|
@@ -126,10 +127,10 @@ def _normalize_relationships(items: list[dict], schema_level: bool = True) -> di
|
|
|
126
127
|
elif schema_level:
|
|
127
128
|
from_val = str(item.get("from", ""))
|
|
128
129
|
to_val = str(item.get("to", ""))
|
|
129
|
-
key = f"{from_val}:{to_val}" if (from_val or to_val) else f"
|
|
130
|
+
key = f"{from_val}:{to_val}" if (from_val or to_val) else f"[{i}]"
|
|
130
131
|
else:
|
|
131
132
|
to_val = item.get("to")
|
|
132
|
-
key = str(to_val) if to_val else f"
|
|
133
|
+
key = str(to_val) if to_val else f"[{i}]"
|
|
133
134
|
result[key] = item
|
|
134
135
|
return result
|
|
135
136
|
|
|
@@ -138,7 +139,7 @@ def _normalize_quality(items: list[dict]) -> dict:
|
|
|
138
139
|
"""Key DataQuality items by name (with positional fallback)."""
|
|
139
140
|
result = {}
|
|
140
141
|
for i, item in enumerate(items):
|
|
141
|
-
key = item.get("name") or f"
|
|
142
|
+
key = item.get("name") or f"[{i}]"
|
|
142
143
|
entry = {k: v for k, v in item.items() if k != "name"}
|
|
143
144
|
if "customProperties" in entry and isinstance(entry["customProperties"], list):
|
|
144
145
|
entry["customProperties"] = _normalize_by(entry["customProperties"], "property")
|