datacontract-cli 0.11.4__tar.gz → 0.11.6__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-0.11.4/datacontract_cli.egg-info → datacontract_cli-0.11.6}/PKG-INFO +28 -24
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/README.md +16 -12
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/catalog/catalog.py +7 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/cli.py +6 -5
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/data_contract.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/data_contract_checks.py +84 -69
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/data_contract_test.py +1 -5
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/check_soda_execute.py +2 -3
- datacontract_cli-0.11.6/datacontract/engines/soda/connections/bigquery.py +24 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/duckdb_connection.py +14 -9
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/impala.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/sqlserver.py +23 -2
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/avro_exporter.py +5 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/avro_idl_exporter.py +3 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/bigquery_exporter.py +31 -15
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/data_caterer_exporter.py +1 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/dbml_exporter.py +4 -6
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/dbt_exporter.py +4 -7
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/dcs_exporter.py +4 -4
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/dqx_exporter.py +3 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/excel_exporter.py +13 -5
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/exporter.py +3 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/great_expectations_exporter.py +8 -2
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/iceberg_exporter.py +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/markdown_exporter.py +6 -6
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/mermaid_exporter.py +4 -2
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/odcs_export_helper.py +6 -11
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/protobuf_exporter.py +3 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/rdf_exporter.py +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/sql_exporter.py +1 -4
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/sql_type_converter.py +12 -8
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/sqlalchemy_exporter.py +5 -4
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/avro_importer.py +8 -9
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/bigquery_importer.py +75 -30
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/csv_importer.py +3 -6
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/dbml_importer.py +2 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/dbt_importer.py +1 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/excel_importer.py +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/glue_importer.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/iceberg_importer.py +4 -5
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/json_importer.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/jsonschema_importer.py +3 -9
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/odcs_helper.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/odcs_importer.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/parquet_importer.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/sql_importer.py +2 -6
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/lint/resolve.py +1 -3
- datacontract_cli-0.11.6/datacontract/output/json_test_results.py +13 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/output/junit_test_results.py +10 -7
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/output/output_format.py +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/output/test_results_writer.py +9 -2
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/model_field.html +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6/datacontract_cli.egg-info}/PKG-INFO +28 -24
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract_cli.egg-info/SOURCES.txt +4 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract_cli.egg-info/requires.txt +11 -11
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/pyproject.toml +12 -12
- datacontract_cli-0.11.6/tests/test_bigquery_soda_connection.py +61 -0
- datacontract_cli-0.11.6/tests/test_data_contract_checks.py +222 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_dbml.py +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_dbt_models.py +9 -4
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_great_expectations.py +1 -3
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_odcs_v3.py +0 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_sodacl.py +52 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_sql_query.py +3 -1
- datacontract_cli-0.11.6/tests/test_sqlserver_soda_connection.py +126 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_kafka.py +1 -3
- datacontract_cli-0.11.6/tests/test_test_output_json.py +30 -0
- datacontract_cli-0.11.6/tests/test_test_output_junit.py +57 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_schema_evolution.py +29 -9
- datacontract_cli-0.11.4/datacontract/engines/soda/connections/bigquery.py +0 -27
- datacontract_cli-0.11.4/tests/test_data_contract_checks.py +0 -74
- datacontract_cli-0.11.4/tests/test_test_output_junit.py +0 -22
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/LICENSE +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/MANIFEST.in +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/api.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/athena.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/databricks.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/kafka.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/oracle.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/postgres.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/snowflake.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/connections/trino.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/html_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/pydantic_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/dcs_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/lint/files.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/model/run.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/output/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/py.typed +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/odcs-3.1.0.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/index.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/setup.cfg +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_api.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_catalog.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_cli.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_description_linter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_avro.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_custom.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_excel.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_go.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_html.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_spark.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_sql.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_avro.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_csv.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_excel.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_glue.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_spark.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_sql_oracle.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_lint.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_resolve.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_api.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_delta.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_quality.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/tests/test_test_trino.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.6
|
|
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@innoq.com>, Stefan Negele <stefan.negele@innoq.com>, Simon Harrer <simon.harrer@innoq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -11,7 +11,7 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: <3.13,>=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: typer<0.
|
|
14
|
+
Requires-Dist: typer<0.25,>=0.18.0
|
|
15
15
|
Requires-Dist: pydantic<2.13.0,>=2.8.2
|
|
16
16
|
Requires-Dist: pyyaml~=6.0.1
|
|
17
17
|
Requires-Dist: requests<2.33,>=2.31
|
|
@@ -39,7 +39,7 @@ Provides-Extra: databricks
|
|
|
39
39
|
Requires-Dist: soda-core-spark-df<3.6.0,>=3.3.20; extra == "databricks"
|
|
40
40
|
Requires-Dist: soda-core-spark[databricks]<3.6.0,>=3.3.20; extra == "databricks"
|
|
41
41
|
Requires-Dist: databricks-sql-connector<4.3.0,>=3.7.0; extra == "databricks"
|
|
42
|
-
Requires-Dist: databricks-sdk<0.
|
|
42
|
+
Requires-Dist: databricks-sdk<0.86.0; extra == "databricks"
|
|
43
43
|
Requires-Dist: pyspark<5.0.0,>=3.5.0; extra == "databricks"
|
|
44
44
|
Requires-Dist: numpy<2.0.0,>=1.26.4; extra == "databricks"
|
|
45
45
|
Provides-Extra: iceberg
|
|
@@ -52,10 +52,10 @@ Requires-Dist: numpy<2.0.0,>=1.26.4; extra == "kafka"
|
|
|
52
52
|
Provides-Extra: postgres
|
|
53
53
|
Requires-Dist: soda-core-postgres<3.6.0,>=3.3.20; extra == "postgres"
|
|
54
54
|
Provides-Extra: s3
|
|
55
|
-
Requires-Dist: s3fs<
|
|
55
|
+
Requires-Dist: s3fs<2027.0.0,>=2025.2.0; extra == "s3"
|
|
56
56
|
Requires-Dist: aiobotocore<3.2.0,>=2.17.0; extra == "s3"
|
|
57
57
|
Provides-Extra: snowflake
|
|
58
|
-
Requires-Dist: snowflake-connector-python[pandas]<4.
|
|
58
|
+
Requires-Dist: snowflake-connector-python[pandas]<4.3,>=3.6; extra == "snowflake"
|
|
59
59
|
Requires-Dist: soda-core-snowflake<3.6.0,>=3.3.20; extra == "snowflake"
|
|
60
60
|
Provides-Extra: sqlserver
|
|
61
61
|
Requires-Dist: soda-core-sqlserver<3.6.0,>=3.3.20; extra == "sqlserver"
|
|
@@ -75,9 +75,9 @@ Requires-Dist: soda-core-duckdb<3.6.0,>=3.3.20; extra == "duckdb"
|
|
|
75
75
|
Provides-Extra: parquet
|
|
76
76
|
Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
|
|
77
77
|
Provides-Extra: rdf
|
|
78
|
-
Requires-Dist: rdflib==7.
|
|
78
|
+
Requires-Dist: rdflib==7.6.0; extra == "rdf"
|
|
79
79
|
Provides-Extra: api
|
|
80
|
-
Requires-Dist: fastapi==0.
|
|
80
|
+
Requires-Dist: fastapi==0.129.0; extra == "api"
|
|
81
81
|
Requires-Dist: uvicorn==0.40.0; extra == "api"
|
|
82
82
|
Provides-Extra: protobuf
|
|
83
83
|
Requires-Dist: grpcio-tools>=1.53; extra == "protobuf"
|
|
@@ -87,15 +87,15 @@ Provides-Extra: dev
|
|
|
87
87
|
Requires-Dist: datacontract-cli[all]; extra == "dev"
|
|
88
88
|
Requires-Dist: httpx==0.28.1; extra == "dev"
|
|
89
89
|
Requires-Dist: kafka-python; extra == "dev"
|
|
90
|
-
Requires-Dist: minio==7.2.
|
|
91
|
-
Requires-Dist: moto==5.1.
|
|
90
|
+
Requires-Dist: minio==7.2.20; extra == "dev"
|
|
91
|
+
Requires-Dist: moto==5.1.21; extra == "dev"
|
|
92
92
|
Requires-Dist: pandas>=2.1.0; extra == "dev"
|
|
93
93
|
Requires-Dist: pre-commit<4.6.0,>=3.7.1; extra == "dev"
|
|
94
94
|
Requires-Dist: pytest; extra == "dev"
|
|
95
95
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
96
|
-
Requires-Dist: pymssql==2.3.
|
|
97
|
-
Requires-Dist: ruff; extra == "dev"
|
|
98
|
-
Requires-Dist: testcontainers[kafka,minio,mssql,postgres]==4.
|
|
96
|
+
Requires-Dist: pymssql==2.3.13; extra == "dev"
|
|
97
|
+
Requires-Dist: ruff==0.14.3; extra == "dev"
|
|
98
|
+
Requires-Dist: testcontainers[kafka,minio,mssql,postgres]==4.14.1; extra == "dev"
|
|
99
99
|
Requires-Dist: trino==0.336.0; extra == "dev"
|
|
100
100
|
Dynamic: license-file
|
|
101
101
|
|
|
@@ -622,10 +622,11 @@ servers:
|
|
|
622
622
|
|
|
623
623
|
#### BigQuery
|
|
624
624
|
|
|
625
|
-
We support authentication to BigQuery using Service Account Key. The used Service Account should include the roles:
|
|
625
|
+
We support authentication to BigQuery using Service Account Key or Application Default Credentials (ADC). ADC supports Workload Identity Federation (WIF), GCE metadata server, and `gcloud auth application-default login`. The used Service Account should include the roles:
|
|
626
626
|
* BigQuery Job User
|
|
627
627
|
* BigQuery Data Viewer
|
|
628
628
|
|
|
629
|
+
When no `DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH` is set, the CLI falls back to ADC/WIF automatically via Soda's `use_context_auth`.
|
|
629
630
|
|
|
630
631
|
##### Example
|
|
631
632
|
|
|
@@ -646,7 +647,8 @@ models:
|
|
|
646
647
|
|
|
647
648
|
| Environment Variable | Example | Description |
|
|
648
649
|
|----------------------------------------------|---------------------------|---------------------------------------------------------|
|
|
649
|
-
| `DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH` | `~/service-access-key.json` | Service
|
|
650
|
+
| `DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH` | `~/service-access-key.json` | Service Account key JSON file. If not set, ADC/WIF is used automatically. |
|
|
651
|
+
| `DATACONTRACT_BIGQUERY_IMPERSONATION_ACCOUNT` | `sa@project.iam.gserviceaccount.com` | Optional. Service account to impersonate. Works with both key file and ADC auth. |
|
|
650
652
|
|
|
651
653
|
|
|
652
654
|
#### Azure
|
|
@@ -678,7 +680,7 @@ Authentication works with an Azure Service Principal (SPN) aka App Registration
|
|
|
678
680
|
|
|
679
681
|
#### Sqlserver
|
|
680
682
|
|
|
681
|
-
Data Contract CLI can test data in MS SQL Server (including Azure SQL, Synapse Analytics SQL Pool).
|
|
683
|
+
Data Contract CLI can test data in MS SQL Server (including Azure SQL, Synapse Analytics SQL Pool, and Microsoft Fabric).
|
|
682
684
|
|
|
683
685
|
##### Example
|
|
684
686
|
|
|
@@ -702,14 +704,17 @@ models:
|
|
|
702
704
|
|
|
703
705
|
##### Environment Variables
|
|
704
706
|
|
|
705
|
-
| Environment Variable | Example| Description
|
|
706
|
-
|
|
707
|
-
| `
|
|
708
|
-
| `
|
|
709
|
-
| `
|
|
710
|
-
| `
|
|
711
|
-
| `
|
|
712
|
-
| `
|
|
707
|
+
| Environment Variable | Example | Description |
|
|
708
|
+
|---------------------------------------------------|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
709
|
+
| `DATACONTRACT_SQLSERVER_AUTHENTICATION` | `sql` | Supported: `sql` (default), `cli` (uses `az login` session), `windows`, `ActiveDirectoryPassword`, `ActiveDirectoryServicePrincipal`, `ActiveDirectoryInteractive` |
|
|
710
|
+
| `DATACONTRACT_SQLSERVER_USERNAME` | `root` | Username (for `sql`, `ActiveDirectoryPassword`, `ActiveDirectoryInteractive`) |
|
|
711
|
+
| `DATACONTRACT_SQLSERVER_PASSWORD` | `toor` | Password (for `sql` and `ActiveDirectoryPassword`) |
|
|
712
|
+
| `DATACONTRACT_SQLSERVER_CLIENT_ID` | `a3cf5d29-b1a7-...` | Application/Client ID (for `ActiveDirectoryServicePrincipal`) |
|
|
713
|
+
| `DATACONTRACT_SQLSERVER_CLIENT_SECRET` | `kX9~Qr2Lm.Tz4W...` | Client secret (for `ActiveDirectoryServicePrincipal`) |
|
|
714
|
+
| `DATACONTRACT_SQLSERVER_TRUST_SERVER_CERTIFICATE` | `True` | Trust self-signed certificate |
|
|
715
|
+
| `DATACONTRACT_SQLSERVER_ENCRYPTED_CONNECTION` | `True` | Use SSL |
|
|
716
|
+
| `DATACONTRACT_SQLSERVER_DRIVER` | `ODBC Driver 18 for SQL Server` | ODBC driver name |
|
|
717
|
+
| `DATACONTRACT_SQLSERVER_TRUSTED_CONNECTION` | `True` | Deprecated. Equivalent to `AUTHENTICATION=windows` |
|
|
713
718
|
|
|
714
719
|
|
|
715
720
|
|
|
@@ -1636,7 +1641,6 @@ Available import options:
|
|
|
1636
1641
|
| `spark` | Import from Spark StructTypes, Variant | ✅ |
|
|
1637
1642
|
| `sql` | Import from SQL DDL | ✅ |
|
|
1638
1643
|
| `unity` | Import from Databricks Unity Catalog | partial |
|
|
1639
|
-
| `excel` | Import from ODCS Excel Template | ✅ |
|
|
1640
1644
|
| Missing something? | Please create an issue on GitHub | TBD |
|
|
1641
1645
|
|
|
1642
1646
|
|
|
@@ -521,10 +521,11 @@ servers:
|
|
|
521
521
|
|
|
522
522
|
#### BigQuery
|
|
523
523
|
|
|
524
|
-
We support authentication to BigQuery using Service Account Key. The used Service Account should include the roles:
|
|
524
|
+
We support authentication to BigQuery using Service Account Key or Application Default Credentials (ADC). ADC supports Workload Identity Federation (WIF), GCE metadata server, and `gcloud auth application-default login`. The used Service Account should include the roles:
|
|
525
525
|
* BigQuery Job User
|
|
526
526
|
* BigQuery Data Viewer
|
|
527
527
|
|
|
528
|
+
When no `DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH` is set, the CLI falls back to ADC/WIF automatically via Soda's `use_context_auth`.
|
|
528
529
|
|
|
529
530
|
##### Example
|
|
530
531
|
|
|
@@ -545,7 +546,8 @@ models:
|
|
|
545
546
|
|
|
546
547
|
| Environment Variable | Example | Description |
|
|
547
548
|
|----------------------------------------------|---------------------------|---------------------------------------------------------|
|
|
548
|
-
| `DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH` | `~/service-access-key.json` | Service
|
|
549
|
+
| `DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH` | `~/service-access-key.json` | Service Account key JSON file. If not set, ADC/WIF is used automatically. |
|
|
550
|
+
| `DATACONTRACT_BIGQUERY_IMPERSONATION_ACCOUNT` | `sa@project.iam.gserviceaccount.com` | Optional. Service account to impersonate. Works with both key file and ADC auth. |
|
|
549
551
|
|
|
550
552
|
|
|
551
553
|
#### Azure
|
|
@@ -577,7 +579,7 @@ Authentication works with an Azure Service Principal (SPN) aka App Registration
|
|
|
577
579
|
|
|
578
580
|
#### Sqlserver
|
|
579
581
|
|
|
580
|
-
Data Contract CLI can test data in MS SQL Server (including Azure SQL, Synapse Analytics SQL Pool).
|
|
582
|
+
Data Contract CLI can test data in MS SQL Server (including Azure SQL, Synapse Analytics SQL Pool, and Microsoft Fabric).
|
|
581
583
|
|
|
582
584
|
##### Example
|
|
583
585
|
|
|
@@ -601,14 +603,17 @@ models:
|
|
|
601
603
|
|
|
602
604
|
##### Environment Variables
|
|
603
605
|
|
|
604
|
-
| Environment Variable | Example| Description
|
|
605
|
-
|
|
606
|
-
| `
|
|
607
|
-
| `
|
|
608
|
-
| `
|
|
609
|
-
| `
|
|
610
|
-
| `
|
|
611
|
-
| `
|
|
606
|
+
| Environment Variable | Example | Description |
|
|
607
|
+
|---------------------------------------------------|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
608
|
+
| `DATACONTRACT_SQLSERVER_AUTHENTICATION` | `sql` | Supported: `sql` (default), `cli` (uses `az login` session), `windows`, `ActiveDirectoryPassword`, `ActiveDirectoryServicePrincipal`, `ActiveDirectoryInteractive` |
|
|
609
|
+
| `DATACONTRACT_SQLSERVER_USERNAME` | `root` | Username (for `sql`, `ActiveDirectoryPassword`, `ActiveDirectoryInteractive`) |
|
|
610
|
+
| `DATACONTRACT_SQLSERVER_PASSWORD` | `toor` | Password (for `sql` and `ActiveDirectoryPassword`) |
|
|
611
|
+
| `DATACONTRACT_SQLSERVER_CLIENT_ID` | `a3cf5d29-b1a7-...` | Application/Client ID (for `ActiveDirectoryServicePrincipal`) |
|
|
612
|
+
| `DATACONTRACT_SQLSERVER_CLIENT_SECRET` | `kX9~Qr2Lm.Tz4W...` | Client secret (for `ActiveDirectoryServicePrincipal`) |
|
|
613
|
+
| `DATACONTRACT_SQLSERVER_TRUST_SERVER_CERTIFICATE` | `True` | Trust self-signed certificate |
|
|
614
|
+
| `DATACONTRACT_SQLSERVER_ENCRYPTED_CONNECTION` | `True` | Use SSL |
|
|
615
|
+
| `DATACONTRACT_SQLSERVER_DRIVER` | `ODBC Driver 18 for SQL Server` | ODBC driver name |
|
|
616
|
+
| `DATACONTRACT_SQLSERVER_TRUSTED_CONNECTION` | `True` | Deprecated. Equivalent to `AUTHENTICATION=windows` |
|
|
612
617
|
|
|
613
618
|
|
|
614
619
|
|
|
@@ -1535,7 +1540,6 @@ Available import options:
|
|
|
1535
1540
|
| `spark` | Import from Spark StructTypes, Variant | ✅ |
|
|
1536
1541
|
| `sql` | Import from SQL DDL | ✅ |
|
|
1537
1542
|
| `unity` | Import from Databricks Unity Catalog | partial |
|
|
1538
|
-
| `excel` | Import from ODCS Excel Template | ✅ |
|
|
1539
1543
|
| Missing something? | Please create an issue on GitHub | TBD |
|
|
1540
1544
|
|
|
1541
1545
|
|
|
@@ -32,7 +32,11 @@ def create_data_contract_html(contracts, file: Path, path: Path, schema: str):
|
|
|
32
32
|
odcs = data_contract.get_data_contract()
|
|
33
33
|
file_without_suffix = file.with_suffix(".html")
|
|
34
34
|
html_filepath = path / file_without_suffix
|
|
35
|
-
|
|
35
|
+
try:
|
|
36
|
+
html_filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
except FileExistsError:
|
|
38
|
+
if not html_filepath.parent.is_dir():
|
|
39
|
+
raise
|
|
36
40
|
with open(html_filepath, "w", encoding="utf-8") as f:
|
|
37
41
|
f.write(html)
|
|
38
42
|
contracts.append(
|
|
@@ -48,6 +52,7 @@ def create_data_contract_html(contracts, file: Path, path: Path, schema: str):
|
|
|
48
52
|
@dataclass
|
|
49
53
|
class _InfoView:
|
|
50
54
|
"""Unified info view for templates."""
|
|
55
|
+
|
|
51
56
|
title: str
|
|
52
57
|
version: str
|
|
53
58
|
owner: Optional[str]
|
|
@@ -57,6 +62,7 @@ class _InfoView:
|
|
|
57
62
|
@dataclass
|
|
58
63
|
class _SpecView:
|
|
59
64
|
"""Unified spec view for templates, compatible with DCS template structure."""
|
|
65
|
+
|
|
60
66
|
info: _InfoView
|
|
61
67
|
models: dict
|
|
62
68
|
|
|
@@ -199,10 +199,7 @@ def export(
|
|
|
199
199
|
server: Annotated[str, typer.Option(help="The server name to export.")] = None,
|
|
200
200
|
schema_name: Annotated[
|
|
201
201
|
str,
|
|
202
|
-
typer.Option(
|
|
203
|
-
help="The name of the schema to export, e.g., `orders`, or `all` for all "
|
|
204
|
-
"schemas (default)."
|
|
205
|
-
),
|
|
202
|
+
typer.Option(help="The name of the schema to export, e.g., `orders`, or `all` for all schemas (default)."),
|
|
206
203
|
] = "all",
|
|
207
204
|
# TODO: this should be a subcommand
|
|
208
205
|
rdf_base: Annotated[
|
|
@@ -431,7 +428,11 @@ def catalog(
|
|
|
431
428
|
enable_debug_logging(debug)
|
|
432
429
|
|
|
433
430
|
path = Path(output)
|
|
434
|
-
|
|
431
|
+
try:
|
|
432
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
433
|
+
except FileExistsError:
|
|
434
|
+
if not path.is_dir():
|
|
435
|
+
raise
|
|
435
436
|
console.print(f"Created {output}")
|
|
436
437
|
|
|
437
438
|
contracts = []
|
|
@@ -202,9 +202,7 @@ class DataContract:
|
|
|
202
202
|
id = kwargs.get("id")
|
|
203
203
|
owner = kwargs.get("owner")
|
|
204
204
|
|
|
205
|
-
odcs_imported = importer_factory.create(format).import_source(
|
|
206
|
-
source=source, import_args=kwargs
|
|
207
|
-
)
|
|
205
|
+
odcs_imported = importer_factory.create(format).import_source(source=source, import_args=kwargs)
|
|
208
206
|
|
|
209
207
|
cls._overwrite_id_in_odcs(odcs_imported, id)
|
|
210
208
|
cls._overwrite_owner_in_odcs(odcs_imported, owner)
|
{datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/data_contract_checks.py
RENAMED
|
@@ -20,10 +20,22 @@ from datacontract.model.run import Check
|
|
|
20
20
|
@dataclass
|
|
21
21
|
class QuotingConfig:
|
|
22
22
|
quote_field_name: bool = False
|
|
23
|
+
quote_field_name_with_backticks: bool = False
|
|
23
24
|
quote_model_name: bool = False
|
|
24
25
|
quote_model_name_with_backticks: bool = False
|
|
25
26
|
|
|
26
27
|
|
|
28
|
+
def _quote_field_name(field_name: str, quoting_config: QuotingConfig) -> str:
|
|
29
|
+
"""Quote a field name according to the quoting configuration."""
|
|
30
|
+
if field_name is None:
|
|
31
|
+
return field_name
|
|
32
|
+
if quoting_config.quote_field_name:
|
|
33
|
+
return f'"{field_name}"'
|
|
34
|
+
elif quoting_config.quote_field_name_with_backticks:
|
|
35
|
+
return f"`{field_name}`"
|
|
36
|
+
return field_name
|
|
37
|
+
|
|
38
|
+
|
|
27
39
|
def _get_logical_type_option(prop: SchemaProperty, key: str):
|
|
28
40
|
"""Get a logical type option value."""
|
|
29
41
|
if prop.logicalTypeOptions is None:
|
|
@@ -72,8 +84,9 @@ def to_schema_checks(schema_object: SchemaObject, server: Server) -> List[Check]
|
|
|
72
84
|
|
|
73
85
|
type1 = server.type if server and server.type else None
|
|
74
86
|
config = QuotingConfig(
|
|
75
|
-
quote_field_name=type1 in ["postgres", "sqlserver"],
|
|
76
|
-
|
|
87
|
+
quote_field_name=type1 in ["postgres", "sqlserver", "snowflake", "azure", "s3", "gcs", "local"],
|
|
88
|
+
quote_field_name_with_backticks=type1 in ["databricks"],
|
|
89
|
+
quote_model_name=type1 in ["postgres", "sqlserver", "snowflake", "azure", "s3", "gcs", "local"],
|
|
77
90
|
quote_model_name_with_backticks=type1 == "bigquery",
|
|
78
91
|
)
|
|
79
92
|
quoting_config = config
|
|
@@ -165,7 +178,6 @@ def to_schema_name(schema_object: SchemaObject, server_type: str) -> str:
|
|
|
165
178
|
return schema_object.name
|
|
166
179
|
|
|
167
180
|
|
|
168
|
-
|
|
169
181
|
def check_property_is_present(model_name, field_name, quoting_config: QuotingConfig = QuotingConfig()) -> Check:
|
|
170
182
|
check_type = "field_is_present"
|
|
171
183
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -229,10 +241,7 @@ def check_property_type(
|
|
|
229
241
|
|
|
230
242
|
|
|
231
243
|
def check_property_required(model_name: str, field_name: str, quoting_config: QuotingConfig = QuotingConfig()):
|
|
232
|
-
|
|
233
|
-
field_name_for_soda = f'"{field_name}"'
|
|
234
|
-
else:
|
|
235
|
-
field_name_for_soda = field_name
|
|
244
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
236
245
|
|
|
237
246
|
check_type = "field_required"
|
|
238
247
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -260,10 +269,7 @@ def check_property_required(model_name: str, field_name: str, quoting_config: Qu
|
|
|
260
269
|
|
|
261
270
|
|
|
262
271
|
def check_property_unique(model_name: str, field_name: str, quoting_config: QuotingConfig = QuotingConfig()):
|
|
263
|
-
|
|
264
|
-
field_name_for_soda = f'"{field_name}"'
|
|
265
|
-
else:
|
|
266
|
-
field_name_for_soda = field_name
|
|
272
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
267
273
|
|
|
268
274
|
check_type = "field_unique"
|
|
269
275
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -293,10 +299,7 @@ def check_property_unique(model_name: str, field_name: str, quoting_config: Quot
|
|
|
293
299
|
def check_property_min_length(
|
|
294
300
|
model_name: str, field_name: str, min_length: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
295
301
|
):
|
|
296
|
-
|
|
297
|
-
field_name_for_soda = f'"{field_name}"'
|
|
298
|
-
else:
|
|
299
|
-
field_name_for_soda = field_name
|
|
302
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
300
303
|
|
|
301
304
|
check_type = "field_min_length"
|
|
302
305
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -327,10 +330,7 @@ def check_property_min_length(
|
|
|
327
330
|
def check_property_max_length(
|
|
328
331
|
model_name: str, field_name: str, max_length: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
329
332
|
):
|
|
330
|
-
|
|
331
|
-
field_name_for_soda = f'"{field_name}"'
|
|
332
|
-
else:
|
|
333
|
-
field_name_for_soda = field_name
|
|
333
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
334
334
|
|
|
335
335
|
check_type = "field_max_length"
|
|
336
336
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -361,10 +361,7 @@ def check_property_max_length(
|
|
|
361
361
|
def check_property_minimum(
|
|
362
362
|
model_name: str, field_name: str, minimum: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
363
363
|
):
|
|
364
|
-
|
|
365
|
-
field_name_for_soda = f'"{field_name}"'
|
|
366
|
-
else:
|
|
367
|
-
field_name_for_soda = field_name
|
|
364
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
368
365
|
|
|
369
366
|
check_type = "field_minimum"
|
|
370
367
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -395,10 +392,7 @@ def check_property_minimum(
|
|
|
395
392
|
def check_property_maximum(
|
|
396
393
|
model_name: str, field_name: str, maximum: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
397
394
|
):
|
|
398
|
-
|
|
399
|
-
field_name_for_soda = f'"{field_name}"'
|
|
400
|
-
else:
|
|
401
|
-
field_name_for_soda = field_name
|
|
395
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
402
396
|
|
|
403
397
|
check_type = "field_maximum"
|
|
404
398
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -429,10 +423,7 @@ def check_property_maximum(
|
|
|
429
423
|
def check_property_not_equal(
|
|
430
424
|
model_name: str, field_name: str, value: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
431
425
|
):
|
|
432
|
-
|
|
433
|
-
field_name_for_soda = f'"{field_name}"'
|
|
434
|
-
else:
|
|
435
|
-
field_name_for_soda = field_name
|
|
426
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
436
427
|
|
|
437
428
|
check_type = "field_not_equal"
|
|
438
429
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -461,10 +452,7 @@ def check_property_not_equal(
|
|
|
461
452
|
|
|
462
453
|
|
|
463
454
|
def check_property_enum(model_name: str, field_name: str, enum: list, quoting_config: QuotingConfig = QuotingConfig()):
|
|
464
|
-
|
|
465
|
-
field_name_for_soda = f'"{field_name}"'
|
|
466
|
-
else:
|
|
467
|
-
field_name_for_soda = field_name
|
|
455
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
468
456
|
|
|
469
457
|
check_type = "field_enum"
|
|
470
458
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -492,11 +480,10 @@ def check_property_enum(model_name: str, field_name: str, enum: list, quoting_co
|
|
|
492
480
|
)
|
|
493
481
|
|
|
494
482
|
|
|
495
|
-
def check_property_regex(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
field_name_for_soda = field_name
|
|
483
|
+
def check_property_regex(
|
|
484
|
+
model_name: str, field_name: str, pattern: str, quoting_config: QuotingConfig = QuotingConfig()
|
|
485
|
+
):
|
|
486
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
500
487
|
|
|
501
488
|
check_type = "field_regex"
|
|
502
489
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -553,7 +540,7 @@ def check_model_duplicate_values(
|
|
|
553
540
|
):
|
|
554
541
|
check_type = "model_duplicate_values"
|
|
555
542
|
check_key = f"{model_name}__{check_type}"
|
|
556
|
-
col_joined = ", ".join(cols)
|
|
543
|
+
col_joined = ", ".join(_quote_field_name(col, quoting_config) for col in cols)
|
|
557
544
|
sodacl_check_dict = {
|
|
558
545
|
checks_for(model_name, quoting_config, check_type): [
|
|
559
546
|
{
|
|
@@ -578,10 +565,7 @@ def check_model_duplicate_values(
|
|
|
578
565
|
def check_property_duplicate_values(
|
|
579
566
|
model_name: str, field_name: str, threshold: str, quoting_config: QuotingConfig = QuotingConfig()
|
|
580
567
|
):
|
|
581
|
-
|
|
582
|
-
field_name_for_soda = f'"{field_name}"'
|
|
583
|
-
else:
|
|
584
|
-
field_name_for_soda = field_name
|
|
568
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
585
569
|
|
|
586
570
|
check_type = "field_duplicate_values"
|
|
587
571
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -611,10 +595,7 @@ def check_property_duplicate_values(
|
|
|
611
595
|
def check_property_null_values(
|
|
612
596
|
model_name: str, field_name: str, threshold: str, quoting_config: QuotingConfig = QuotingConfig()
|
|
613
597
|
):
|
|
614
|
-
|
|
615
|
-
field_name_for_soda = f'"{field_name}"'
|
|
616
|
-
else:
|
|
617
|
-
field_name_for_soda = field_name
|
|
598
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
618
599
|
|
|
619
600
|
check_type = "field_null_values"
|
|
620
601
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -648,10 +629,7 @@ def check_property_invalid_values(
|
|
|
648
629
|
valid_values: list = None,
|
|
649
630
|
quoting_config: QuotingConfig = QuotingConfig(),
|
|
650
631
|
):
|
|
651
|
-
|
|
652
|
-
field_name_for_soda = f'"{field_name}"'
|
|
653
|
-
else:
|
|
654
|
-
field_name_for_soda = field_name
|
|
632
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
655
633
|
|
|
656
634
|
check_type = "field_invalid_values"
|
|
657
635
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -691,10 +669,7 @@ def check_property_missing_values(
|
|
|
691
669
|
missing_values: list = None,
|
|
692
670
|
quoting_config: QuotingConfig = QuotingConfig(),
|
|
693
671
|
):
|
|
694
|
-
|
|
695
|
-
field_name_for_soda = f'"{field_name}"'
|
|
696
|
-
else:
|
|
697
|
-
field_name_for_soda = field_name
|
|
672
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
698
673
|
|
|
699
674
|
check_type = "field_missing_values"
|
|
700
675
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -819,7 +794,9 @@ def check_quality_list(
|
|
|
819
794
|
)
|
|
820
795
|
)
|
|
821
796
|
else:
|
|
822
|
-
checks.append(
|
|
797
|
+
checks.append(
|
|
798
|
+
check_property_duplicate_values(schema_name, property_name, threshold, quoting_config)
|
|
799
|
+
)
|
|
823
800
|
elif quality.metric == "nullValues":
|
|
824
801
|
if property_name is not None:
|
|
825
802
|
checks.append(check_property_null_values(schema_name, property_name, threshold, quoting_config))
|
|
@@ -829,7 +806,9 @@ def check_quality_list(
|
|
|
829
806
|
if property_name is not None:
|
|
830
807
|
valid_values = quality.arguments.get("validValues") if quality.arguments else None
|
|
831
808
|
checks.append(
|
|
832
|
-
check_property_invalid_values(
|
|
809
|
+
check_property_invalid_values(
|
|
810
|
+
schema_name, property_name, threshold, valid_values, quoting_config
|
|
811
|
+
)
|
|
833
812
|
)
|
|
834
813
|
else:
|
|
835
814
|
logger.warning("Quality check invalidValues is only supported at field level")
|
|
@@ -837,7 +816,9 @@ def check_quality_list(
|
|
|
837
816
|
if property_name is not None:
|
|
838
817
|
missing_values = quality.arguments.get("missingValues") if quality.arguments else None
|
|
839
818
|
checks.append(
|
|
840
|
-
check_property_missing_values(
|
|
819
|
+
check_property_missing_values(
|
|
820
|
+
schema_name, property_name, threshold, missing_values, quoting_config
|
|
821
|
+
)
|
|
841
822
|
)
|
|
842
823
|
else:
|
|
843
824
|
logger.warning("Quality check missingValues is only supported at field level")
|
|
@@ -863,10 +844,7 @@ def prepare_query(
|
|
|
863
844
|
|
|
864
845
|
query = quality.query
|
|
865
846
|
|
|
866
|
-
|
|
867
|
-
field_name_for_soda = f'"{field_name}"'
|
|
868
|
-
else:
|
|
869
|
-
field_name_for_soda = field_name
|
|
847
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
870
848
|
|
|
871
849
|
if quoting_config.quote_model_name:
|
|
872
850
|
model_name_for_soda = f'"{model_name}"'
|
|
@@ -1050,11 +1028,12 @@ def to_servicelevel_retention_check(data_contract: OpenDataContractStandard, sla
|
|
|
1050
1028
|
logger.info(f"Model {model_name} not found in schema, skipping retention check")
|
|
1051
1029
|
return None
|
|
1052
1030
|
|
|
1053
|
-
#
|
|
1054
|
-
|
|
1055
|
-
|
|
1031
|
+
# Convert retention value to seconds
|
|
1032
|
+
# Supports both numeric value + unit (ODCS style: value=3, unit=y)
|
|
1033
|
+
# and ISO 8601 duration strings (e.g., "P1Y")
|
|
1034
|
+
seconds = _retention_value_to_seconds(sla.value, sla.unit)
|
|
1056
1035
|
if seconds is None:
|
|
1057
|
-
logger.info(f"Could not parse retention period {
|
|
1036
|
+
logger.info(f"Could not parse retention period (value={sla.value}, unit={sla.unit}), skipping retention check")
|
|
1058
1037
|
return None
|
|
1059
1038
|
|
|
1060
1039
|
check_type = "servicelevel_retention"
|
|
@@ -1083,6 +1062,43 @@ def to_servicelevel_retention_check(data_contract: OpenDataContractStandard, sla
|
|
|
1083
1062
|
)
|
|
1084
1063
|
|
|
1085
1064
|
|
|
1065
|
+
def _retention_value_to_seconds(value, unit: str | None) -> int | None:
|
|
1066
|
+
"""Convert a retention value to seconds.
|
|
1067
|
+
|
|
1068
|
+
Supports:
|
|
1069
|
+
- Numeric value with unit (ODCS style): value=3, unit="y"
|
|
1070
|
+
- ISO 8601 duration string: value="P1Y"
|
|
1071
|
+
"""
|
|
1072
|
+
if value is None:
|
|
1073
|
+
return None
|
|
1074
|
+
|
|
1075
|
+
# If value is numeric, use the unit to convert to seconds
|
|
1076
|
+
if isinstance(value, (int, float)):
|
|
1077
|
+
numeric_value = int(value)
|
|
1078
|
+
unit_lower = unit.lower() if unit else "d"
|
|
1079
|
+
if unit_lower in ("y", "yr", "year", "years"):
|
|
1080
|
+
return numeric_value * 365 * 24 * 60 * 60
|
|
1081
|
+
elif unit_lower in ("m", "mo", "month", "months"):
|
|
1082
|
+
return numeric_value * 30 * 24 * 60 * 60
|
|
1083
|
+
elif unit_lower in ("d", "day", "days"):
|
|
1084
|
+
return numeric_value * 24 * 60 * 60
|
|
1085
|
+
elif unit_lower in ("h", "hr", "hour", "hours"):
|
|
1086
|
+
return numeric_value * 60 * 60
|
|
1087
|
+
elif unit_lower in ("min", "minute", "minutes"):
|
|
1088
|
+
return numeric_value * 60
|
|
1089
|
+
elif unit_lower in ("s", "sec", "second", "seconds"):
|
|
1090
|
+
return numeric_value
|
|
1091
|
+
else:
|
|
1092
|
+
logger.info(f"Unsupported retention unit: {unit}")
|
|
1093
|
+
return None
|
|
1094
|
+
|
|
1095
|
+
# If value is a string, try ISO 8601 parsing
|
|
1096
|
+
if isinstance(value, str):
|
|
1097
|
+
return _parse_iso8601_to_seconds(value)
|
|
1098
|
+
|
|
1099
|
+
return None
|
|
1100
|
+
|
|
1101
|
+
|
|
1086
1102
|
def _parse_iso8601_to_seconds(duration: str) -> int | None:
|
|
1087
1103
|
"""Parse ISO 8601 duration to seconds."""
|
|
1088
1104
|
if not duration:
|
|
@@ -1125,4 +1141,3 @@ def _parse_iso8601_to_seconds(duration: str) -> int | None:
|
|
|
1125
1141
|
return int(match.group(1))
|
|
1126
1142
|
|
|
1127
1143
|
return None
|
|
1128
|
-
|
{datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/data_contract_test.py
RENAMED
|
@@ -36,11 +36,7 @@ def execute_data_contract_test(
|
|
|
36
36
|
reason="Schema block is missing. Skip executing tests.",
|
|
37
37
|
engine="datacontract",
|
|
38
38
|
)
|
|
39
|
-
if (
|
|
40
|
-
server_name is None
|
|
41
|
-
and data_contract.servers is not None
|
|
42
|
-
and len(data_contract.servers) > 0
|
|
43
|
-
):
|
|
39
|
+
if server_name is None and data_contract.servers is not None and len(data_contract.servers) > 0:
|
|
44
40
|
server_name = data_contract.servers[0].server
|
|
45
41
|
server = get_server(data_contract, server_name)
|
|
46
42
|
run.log_info(f"Running tests for data contract {data_contract.id} with server {server_name}")
|
{datacontract_cli-0.11.4 → datacontract_cli-0.11.6}/datacontract/engines/soda/check_soda_execute.py
RENAMED
|
@@ -96,7 +96,7 @@ def check_soda_execute(
|
|
|
96
96
|
logging.info("Use Spark to connect to data source")
|
|
97
97
|
scan.add_spark_session(spark, data_source_name="datacontract-cli")
|
|
98
98
|
scan.set_data_source_name("datacontract-cli")
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
# ------------------------------------------------------------------
|
|
101
101
|
# NEW: native Impala server type
|
|
102
102
|
# ------------------------------------------------------------------
|
|
@@ -107,7 +107,6 @@ def check_soda_execute(
|
|
|
107
107
|
# data source name must match what we configure in to_impala_soda_configuration
|
|
108
108
|
scan.set_data_source_name("impala")
|
|
109
109
|
|
|
110
|
-
|
|
111
110
|
elif server.type == "kafka":
|
|
112
111
|
if spark is None:
|
|
113
112
|
spark = create_spark_session()
|
|
@@ -231,4 +230,4 @@ def update_reason(check, c):
|
|
|
231
230
|
# print(check.reason)
|
|
232
231
|
break # Exit the loop once the desired block is found
|
|
233
232
|
if "fail" in c["diagnostics"]:
|
|
234
|
-
check.reason = f"Value: {c['diagnostics']['value']} Fail: {c['diagnostics']['fail']}"
|
|
233
|
+
check.reason = f"Value: {c['diagnostics']['value']} Fail: {c['diagnostics']['fail']}"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import yaml
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# https://docs.soda.io/soda/connect-bigquery.html#authentication-methods
|
|
7
|
+
def to_bigquery_soda_configuration(server):
|
|
8
|
+
data_source = {
|
|
9
|
+
"type": "bigquery",
|
|
10
|
+
"project_id": server.project,
|
|
11
|
+
"dataset": server.dataset,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if "DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH" in os.environ:
|
|
15
|
+
data_source["account_info_json_path"] = os.environ["DATACONTRACT_BIGQUERY_ACCOUNT_INFO_JSON_PATH"]
|
|
16
|
+
data_source["auth_scopes"] = ["https://www.googleapis.com/auth/bigquery"]
|
|
17
|
+
else:
|
|
18
|
+
data_source["use_context_auth"] = True
|
|
19
|
+
|
|
20
|
+
if "DATACONTRACT_BIGQUERY_IMPERSONATION_ACCOUNT" in os.environ:
|
|
21
|
+
data_source["impersonation_account"] = os.environ["DATACONTRACT_BIGQUERY_IMPERSONATION_ACCOUNT"]
|
|
22
|
+
|
|
23
|
+
soda_configuration_str = yaml.dump({f"data_source {server.type}": data_source})
|
|
24
|
+
return soda_configuration_str
|