datacontract-cli 0.11.4__tar.gz → 0.11.5__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.5}/PKG-INFO +13 -11
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/README.md +4 -2
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/catalog/catalog.py +5 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/cli.py +5 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/data_contract_checks.py +72 -63
- datacontract_cli-0.11.5/datacontract/engines/soda/connections/bigquery.py +24 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/markdown_exporter.py +6 -6
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/sql_type_converter.py +12 -8
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/bigquery_importer.py +74 -27
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/output/junit_test_results.py +9 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/model_field.html +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5/datacontract_cli.egg-info}/PKG-INFO +13 -11
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract_cli.egg-info/SOURCES.txt +1 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract_cli.egg-info/requires.txt +8 -8
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/pyproject.toml +9 -9
- datacontract_cli-0.11.5/tests/test_bigquery_soda_connection.py +61 -0
- datacontract_cli-0.11.5/tests/test_data_contract_checks.py +203 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_dbml.py +1 -1
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_sodacl.py +52 -0
- datacontract_cli-0.11.5/tests/test_test_output_junit.py +59 -0
- 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.5}/LICENSE +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/MANIFEST.in +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/api.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/data_contract.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/data_contract_test.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/check_soda_execute.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/athena.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/databricks.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/duckdb_connection.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/impala.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/kafka.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/oracle.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/postgres.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/snowflake.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/sqlserver.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/engines/soda/connections/trino.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/avro_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/avro_idl_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/bigquery_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/data_caterer_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/dbml_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/dbt_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/dqx_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/excel_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/great_expectations_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/html_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/iceberg_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/mermaid_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/odcs_export_helper.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/protobuf_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/pydantic_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/rdf_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/sql_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/sqlalchemy_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/dcs_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/excel_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/json_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/odcs_helper.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/lint/files.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/model/run.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/output/__init__.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/output/test_results_writer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/py.typed +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/odcs-3.1.0.init.yaml +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/index.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/setup.cfg +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_api.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_catalog.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_cli.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_description_linter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_avro.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_custom.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_excel.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_go.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_html.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_spark.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_sql.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_avro.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_csv.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_excel.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_glue.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_spark.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_sql_oracle.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_lint.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_resolve.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_api.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_delta.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_quality.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_schema_evolution.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/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.5
|
|
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
|
|
@@ -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"
|
|
@@ -77,7 +77,7 @@ Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
|
|
|
77
77
|
Provides-Extra: rdf
|
|
78
78
|
Requires-Dist: rdflib==7.5.0; extra == "rdf"
|
|
79
79
|
Provides-Extra: api
|
|
80
|
-
Requires-Dist: fastapi==0.
|
|
80
|
+
Requires-Dist: fastapi==0.128.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.
|
|
96
|
+
Requires-Dist: pymssql==2.3.13; extra == "dev"
|
|
97
97
|
Requires-Dist: ruff; extra == "dev"
|
|
98
|
-
Requires-Dist: testcontainers[kafka,minio,mssql,postgres]==4.
|
|
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
|
|
@@ -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
|
|
@@ -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(
|
|
@@ -431,7 +431,11 @@ def catalog(
|
|
|
431
431
|
enable_debug_logging(debug)
|
|
432
432
|
|
|
433
433
|
path = Path(output)
|
|
434
|
-
|
|
434
|
+
try:
|
|
435
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
436
|
+
except FileExistsError:
|
|
437
|
+
if not path.is_dir():
|
|
438
|
+
raise
|
|
435
439
|
console.print(f"Created {output}")
|
|
436
440
|
|
|
437
441
|
contracts = []
|
{datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/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", "azure", "snowflake"],
|
|
88
|
+
quote_field_name_with_backticks=type1 in ["databricks"],
|
|
89
|
+
quote_model_name=type1 in ["postgres", "sqlserver", "snowflake"],
|
|
77
90
|
quote_model_name_with_backticks=type1 == "bigquery",
|
|
78
91
|
)
|
|
79
92
|
quoting_config = config
|
|
@@ -229,10 +242,7 @@ def check_property_type(
|
|
|
229
242
|
|
|
230
243
|
|
|
231
244
|
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
|
|
245
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
236
246
|
|
|
237
247
|
check_type = "field_required"
|
|
238
248
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -260,10 +270,7 @@ def check_property_required(model_name: str, field_name: str, quoting_config: Qu
|
|
|
260
270
|
|
|
261
271
|
|
|
262
272
|
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
|
|
273
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
267
274
|
|
|
268
275
|
check_type = "field_unique"
|
|
269
276
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -293,10 +300,7 @@ def check_property_unique(model_name: str, field_name: str, quoting_config: Quot
|
|
|
293
300
|
def check_property_min_length(
|
|
294
301
|
model_name: str, field_name: str, min_length: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
295
302
|
):
|
|
296
|
-
|
|
297
|
-
field_name_for_soda = f'"{field_name}"'
|
|
298
|
-
else:
|
|
299
|
-
field_name_for_soda = field_name
|
|
303
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
300
304
|
|
|
301
305
|
check_type = "field_min_length"
|
|
302
306
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -327,10 +331,7 @@ def check_property_min_length(
|
|
|
327
331
|
def check_property_max_length(
|
|
328
332
|
model_name: str, field_name: str, max_length: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
329
333
|
):
|
|
330
|
-
|
|
331
|
-
field_name_for_soda = f'"{field_name}"'
|
|
332
|
-
else:
|
|
333
|
-
field_name_for_soda = field_name
|
|
334
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
334
335
|
|
|
335
336
|
check_type = "field_max_length"
|
|
336
337
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -361,10 +362,7 @@ def check_property_max_length(
|
|
|
361
362
|
def check_property_minimum(
|
|
362
363
|
model_name: str, field_name: str, minimum: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
363
364
|
):
|
|
364
|
-
|
|
365
|
-
field_name_for_soda = f'"{field_name}"'
|
|
366
|
-
else:
|
|
367
|
-
field_name_for_soda = field_name
|
|
365
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
368
366
|
|
|
369
367
|
check_type = "field_minimum"
|
|
370
368
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -395,10 +393,7 @@ def check_property_minimum(
|
|
|
395
393
|
def check_property_maximum(
|
|
396
394
|
model_name: str, field_name: str, maximum: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
397
395
|
):
|
|
398
|
-
|
|
399
|
-
field_name_for_soda = f'"{field_name}"'
|
|
400
|
-
else:
|
|
401
|
-
field_name_for_soda = field_name
|
|
396
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
402
397
|
|
|
403
398
|
check_type = "field_maximum"
|
|
404
399
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -429,10 +424,7 @@ def check_property_maximum(
|
|
|
429
424
|
def check_property_not_equal(
|
|
430
425
|
model_name: str, field_name: str, value: int, quoting_config: QuotingConfig = QuotingConfig()
|
|
431
426
|
):
|
|
432
|
-
|
|
433
|
-
field_name_for_soda = f'"{field_name}"'
|
|
434
|
-
else:
|
|
435
|
-
field_name_for_soda = field_name
|
|
427
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
436
428
|
|
|
437
429
|
check_type = "field_not_equal"
|
|
438
430
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -461,10 +453,7 @@ def check_property_not_equal(
|
|
|
461
453
|
|
|
462
454
|
|
|
463
455
|
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
|
|
456
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
468
457
|
|
|
469
458
|
check_type = "field_enum"
|
|
470
459
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -493,10 +482,7 @@ def check_property_enum(model_name: str, field_name: str, enum: list, quoting_co
|
|
|
493
482
|
|
|
494
483
|
|
|
495
484
|
def check_property_regex(model_name: str, field_name: str, pattern: str, quoting_config: QuotingConfig = QuotingConfig()):
|
|
496
|
-
|
|
497
|
-
field_name_for_soda = f'"{field_name}"'
|
|
498
|
-
else:
|
|
499
|
-
field_name_for_soda = field_name
|
|
485
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
500
486
|
|
|
501
487
|
check_type = "field_regex"
|
|
502
488
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -553,7 +539,7 @@ def check_model_duplicate_values(
|
|
|
553
539
|
):
|
|
554
540
|
check_type = "model_duplicate_values"
|
|
555
541
|
check_key = f"{model_name}__{check_type}"
|
|
556
|
-
col_joined = ", ".join(cols)
|
|
542
|
+
col_joined = ", ".join(_quote_field_name(col, quoting_config) for col in cols)
|
|
557
543
|
sodacl_check_dict = {
|
|
558
544
|
checks_for(model_name, quoting_config, check_type): [
|
|
559
545
|
{
|
|
@@ -578,10 +564,7 @@ def check_model_duplicate_values(
|
|
|
578
564
|
def check_property_duplicate_values(
|
|
579
565
|
model_name: str, field_name: str, threshold: str, quoting_config: QuotingConfig = QuotingConfig()
|
|
580
566
|
):
|
|
581
|
-
|
|
582
|
-
field_name_for_soda = f'"{field_name}"'
|
|
583
|
-
else:
|
|
584
|
-
field_name_for_soda = field_name
|
|
567
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
585
568
|
|
|
586
569
|
check_type = "field_duplicate_values"
|
|
587
570
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -611,10 +594,7 @@ def check_property_duplicate_values(
|
|
|
611
594
|
def check_property_null_values(
|
|
612
595
|
model_name: str, field_name: str, threshold: str, quoting_config: QuotingConfig = QuotingConfig()
|
|
613
596
|
):
|
|
614
|
-
|
|
615
|
-
field_name_for_soda = f'"{field_name}"'
|
|
616
|
-
else:
|
|
617
|
-
field_name_for_soda = field_name
|
|
597
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
618
598
|
|
|
619
599
|
check_type = "field_null_values"
|
|
620
600
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -648,10 +628,7 @@ def check_property_invalid_values(
|
|
|
648
628
|
valid_values: list = None,
|
|
649
629
|
quoting_config: QuotingConfig = QuotingConfig(),
|
|
650
630
|
):
|
|
651
|
-
|
|
652
|
-
field_name_for_soda = f'"{field_name}"'
|
|
653
|
-
else:
|
|
654
|
-
field_name_for_soda = field_name
|
|
631
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
655
632
|
|
|
656
633
|
check_type = "field_invalid_values"
|
|
657
634
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -691,10 +668,7 @@ def check_property_missing_values(
|
|
|
691
668
|
missing_values: list = None,
|
|
692
669
|
quoting_config: QuotingConfig = QuotingConfig(),
|
|
693
670
|
):
|
|
694
|
-
|
|
695
|
-
field_name_for_soda = f'"{field_name}"'
|
|
696
|
-
else:
|
|
697
|
-
field_name_for_soda = field_name
|
|
671
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
698
672
|
|
|
699
673
|
check_type = "field_missing_values"
|
|
700
674
|
check_key = f"{model_name}__{field_name}__{check_type}"
|
|
@@ -863,10 +837,7 @@ def prepare_query(
|
|
|
863
837
|
|
|
864
838
|
query = quality.query
|
|
865
839
|
|
|
866
|
-
|
|
867
|
-
field_name_for_soda = f'"{field_name}"'
|
|
868
|
-
else:
|
|
869
|
-
field_name_for_soda = field_name
|
|
840
|
+
field_name_for_soda = _quote_field_name(field_name, quoting_config)
|
|
870
841
|
|
|
871
842
|
if quoting_config.quote_model_name:
|
|
872
843
|
model_name_for_soda = f'"{model_name}"'
|
|
@@ -1050,11 +1021,12 @@ def to_servicelevel_retention_check(data_contract: OpenDataContractStandard, sla
|
|
|
1050
1021
|
logger.info(f"Model {model_name} not found in schema, skipping retention check")
|
|
1051
1022
|
return None
|
|
1052
1023
|
|
|
1053
|
-
#
|
|
1054
|
-
|
|
1055
|
-
|
|
1024
|
+
# Convert retention value to seconds
|
|
1025
|
+
# Supports both numeric value + unit (ODCS style: value=3, unit=y)
|
|
1026
|
+
# and ISO 8601 duration strings (e.g., "P1Y")
|
|
1027
|
+
seconds = _retention_value_to_seconds(sla.value, sla.unit)
|
|
1056
1028
|
if seconds is None:
|
|
1057
|
-
logger.info(f"Could not parse retention period {
|
|
1029
|
+
logger.info(f"Could not parse retention period (value={sla.value}, unit={sla.unit}), skipping retention check")
|
|
1058
1030
|
return None
|
|
1059
1031
|
|
|
1060
1032
|
check_type = "servicelevel_retention"
|
|
@@ -1083,6 +1055,43 @@ def to_servicelevel_retention_check(data_contract: OpenDataContractStandard, sla
|
|
|
1083
1055
|
)
|
|
1084
1056
|
|
|
1085
1057
|
|
|
1058
|
+
def _retention_value_to_seconds(value, unit: str | None) -> int | None:
|
|
1059
|
+
"""Convert a retention value to seconds.
|
|
1060
|
+
|
|
1061
|
+
Supports:
|
|
1062
|
+
- Numeric value with unit (ODCS style): value=3, unit="y"
|
|
1063
|
+
- ISO 8601 duration string: value="P1Y"
|
|
1064
|
+
"""
|
|
1065
|
+
if value is None:
|
|
1066
|
+
return None
|
|
1067
|
+
|
|
1068
|
+
# If value is numeric, use the unit to convert to seconds
|
|
1069
|
+
if isinstance(value, (int, float)):
|
|
1070
|
+
numeric_value = int(value)
|
|
1071
|
+
unit_lower = unit.lower() if unit else "d"
|
|
1072
|
+
if unit_lower in ("y", "yr", "year", "years"):
|
|
1073
|
+
return numeric_value * 365 * 24 * 60 * 60
|
|
1074
|
+
elif unit_lower in ("m", "mo", "month", "months"):
|
|
1075
|
+
return numeric_value * 30 * 24 * 60 * 60
|
|
1076
|
+
elif unit_lower in ("d", "day", "days"):
|
|
1077
|
+
return numeric_value * 24 * 60 * 60
|
|
1078
|
+
elif unit_lower in ("h", "hr", "hour", "hours"):
|
|
1079
|
+
return numeric_value * 60 * 60
|
|
1080
|
+
elif unit_lower in ("min", "minute", "minutes"):
|
|
1081
|
+
return numeric_value * 60
|
|
1082
|
+
elif unit_lower in ("s", "sec", "second", "seconds"):
|
|
1083
|
+
return numeric_value
|
|
1084
|
+
else:
|
|
1085
|
+
logger.info(f"Unsupported retention unit: {unit}")
|
|
1086
|
+
return None
|
|
1087
|
+
|
|
1088
|
+
# If value is a string, try ISO 8601 parsing
|
|
1089
|
+
if isinstance(value, str):
|
|
1090
|
+
return _parse_iso8601_to_seconds(value)
|
|
1091
|
+
|
|
1092
|
+
return None
|
|
1093
|
+
|
|
1094
|
+
|
|
1086
1095
|
def _parse_iso8601_to_seconds(duration: str) -> int | None:
|
|
1087
1096
|
"""Parse ISO 8601 duration to seconds."""
|
|
1088
1097
|
if not duration:
|
|
@@ -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
|
{datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/markdown_exporter.py
RENAMED
|
@@ -105,7 +105,7 @@ def obj_attributes_to_markdown(obj: BaseModel, excluded_fields: set = set(), is_
|
|
|
105
105
|
return ""
|
|
106
106
|
if is_in_table_cell:
|
|
107
107
|
bullet_char = "•"
|
|
108
|
-
newline_char = "<br
|
|
108
|
+
newline_char = "<br />"
|
|
109
109
|
else:
|
|
110
110
|
bullet_char = "-"
|
|
111
111
|
newline_char = "\n"
|
|
@@ -247,12 +247,12 @@ def description_to_markdown(description) -> str:
|
|
|
247
247
|
if description is None:
|
|
248
248
|
return "No description."
|
|
249
249
|
if isinstance(description, str):
|
|
250
|
-
return description.replace("\n", "<br
|
|
250
|
+
return description.replace("\n", "<br />")
|
|
251
251
|
# Handle Description object - use purpose as the primary description
|
|
252
252
|
if hasattr(description, "purpose") and description.purpose:
|
|
253
|
-
return description.purpose.replace("\n", "<br
|
|
253
|
+
return description.purpose.replace("\n", "<br />")
|
|
254
254
|
if hasattr(description, "usage") and description.usage:
|
|
255
|
-
return description.usage.replace("\n", "<br
|
|
255
|
+
return description.usage.replace("\n", "<br />")
|
|
256
256
|
return "No description."
|
|
257
257
|
|
|
258
258
|
|
|
@@ -285,7 +285,7 @@ def array_of_dict_to_markdown(array: List[Dict[str, str]]) -> str:
|
|
|
285
285
|
markdown_parts.append(
|
|
286
286
|
"| "
|
|
287
287
|
+ " | ".join(
|
|
288
|
-
f"{str(element.get(header, ''))}".replace("\n", "<br
|
|
288
|
+
f"{str(element.get(header, ''))}".replace("\n", "<br />").replace("\t", TAB) for header in headers
|
|
289
289
|
)
|
|
290
290
|
+ " |"
|
|
291
291
|
)
|
|
@@ -352,7 +352,7 @@ def extra_to_markdown(obj: BaseModel, is_in_table_cell: bool = False) -> str:
|
|
|
352
352
|
|
|
353
353
|
bullet_char = "•"
|
|
354
354
|
value_line_ending = "" if is_in_table_cell else "\n"
|
|
355
|
-
row_suffix = "<br
|
|
355
|
+
row_suffix = "<br />" if is_in_table_cell else ""
|
|
356
356
|
|
|
357
357
|
def render_header(key: str) -> str:
|
|
358
358
|
return f"{bullet_char} **{key}:** " if is_in_table_cell else f"\n### {key.capitalize()}\n"
|
{datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/export/sql_type_converter.py
RENAMED
|
@@ -5,6 +5,7 @@ from open_data_contract_standard.model import SchemaProperty
|
|
|
5
5
|
|
|
6
6
|
class FieldLike(Protocol):
|
|
7
7
|
"""Protocol for field-like objects (DCS Field or PropertyAdapter)."""
|
|
8
|
+
|
|
8
9
|
type: Optional[str]
|
|
9
10
|
config: Optional[Dict[str, Any]]
|
|
10
11
|
precision: Optional[int]
|
|
@@ -270,11 +271,7 @@ def convert_to_dataframe(field: Union[SchemaProperty, FieldLike]) -> None | str:
|
|
|
270
271
|
def convert_to_databricks(field: Union[SchemaProperty, FieldLike]) -> None | str:
|
|
271
272
|
type = _get_type(field)
|
|
272
273
|
databricks_type = _get_config_value(field, "databricksType")
|
|
273
|
-
if (
|
|
274
|
-
databricks_type
|
|
275
|
-
and type
|
|
276
|
-
and type.lower() not in ["array", "object", "record", "struct"]
|
|
277
|
-
):
|
|
274
|
+
if databricks_type and type and type.lower() not in ["array", "object", "record", "struct"]:
|
|
278
275
|
return databricks_type
|
|
279
276
|
if type is None:
|
|
280
277
|
return None
|
|
@@ -343,6 +340,7 @@ def convert_to_duckdb(field: Union[SchemaProperty, FieldLike]) -> None | str:
|
|
|
343
340
|
|
|
344
341
|
# Prepare
|
|
345
342
|
type_mapping = {
|
|
343
|
+
"nvarchar": "VARCHAR",
|
|
346
344
|
"varchar": "VARCHAR",
|
|
347
345
|
"string": "VARCHAR",
|
|
348
346
|
"text": "VARCHAR",
|
|
@@ -370,10 +368,15 @@ def convert_to_duckdb(field: Union[SchemaProperty, FieldLike]) -> None | str:
|
|
|
370
368
|
return type_mapping[type_lower]
|
|
371
369
|
|
|
372
370
|
# convert decimal numbers with precision and scale
|
|
373
|
-
if
|
|
371
|
+
if "decimal" in type_lower or "number" in type_lower or "numeric" in type_lower:
|
|
372
|
+
# try CustomProperties
|
|
374
373
|
precision = _get_precision(field)
|
|
375
374
|
scale = _get_scale(field)
|
|
376
|
-
|
|
375
|
+
if precision and scale:
|
|
376
|
+
return f"DECIMAL({precision},{scale})"
|
|
377
|
+
else:
|
|
378
|
+
# force physicalType as is
|
|
379
|
+
return type
|
|
377
380
|
|
|
378
381
|
# Check list and map
|
|
379
382
|
if type_lower == "list" or type_lower == "array":
|
|
@@ -576,6 +579,7 @@ def convert_type_to_impala(field: Union[SchemaProperty, FieldLike]) -> None | st
|
|
|
576
579
|
# (returning None means no "has type" check is generated)
|
|
577
580
|
return None
|
|
578
581
|
|
|
582
|
+
|
|
579
583
|
def convert_type_to_oracle(schema_property: SchemaProperty) -> None | str:
|
|
580
584
|
"""Convert ODCS logical types to Oracle types.
|
|
581
585
|
|
|
@@ -605,4 +609,4 @@ def convert_type_to_oracle(schema_property: SchemaProperty) -> None | str:
|
|
|
605
609
|
"array": "CLOB",
|
|
606
610
|
}
|
|
607
611
|
|
|
608
|
-
return mapping.get(logical_type)
|
|
612
|
+
return mapping.get(logical_type)
|
{datacontract_cli-0.11.4 → datacontract_cli-0.11.5}/datacontract/imports/bigquery_importer.py
RENAMED
|
@@ -143,27 +143,58 @@ def import_table_fields(table_fields) -> List[SchemaProperty]:
|
|
|
143
143
|
required = field.get("mode") == "REQUIRED"
|
|
144
144
|
description = field.get("description")
|
|
145
145
|
field_type = field.get("type")
|
|
146
|
+
repeated = field.get("mode") == "REPEATED"
|
|
146
147
|
|
|
147
148
|
if field_type == "RECORD":
|
|
148
149
|
nested_properties = import_table_fields(field.get("fields", []))
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
150
|
+
if repeated:
|
|
151
|
+
items_prop = create_property(
|
|
152
|
+
name="items",
|
|
153
|
+
logical_type="object",
|
|
154
|
+
physical_type="RECORD",
|
|
155
|
+
properties=nested_properties,
|
|
156
|
+
)
|
|
157
|
+
prop = create_property(
|
|
158
|
+
name=field_name,
|
|
159
|
+
logical_type="array",
|
|
160
|
+
description=description,
|
|
161
|
+
required=None,
|
|
162
|
+
items=items_prop,
|
|
163
|
+
)
|
|
164
|
+
else:
|
|
165
|
+
prop = create_property(
|
|
166
|
+
name=field_name,
|
|
167
|
+
logical_type="object",
|
|
168
|
+
physical_type="RECORD",
|
|
169
|
+
description=description,
|
|
170
|
+
required=required if required else None,
|
|
171
|
+
properties=nested_properties,
|
|
172
|
+
)
|
|
157
173
|
elif field_type == "STRUCT":
|
|
158
174
|
nested_properties = import_table_fields(field.get("fields", []))
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
175
|
+
if repeated:
|
|
176
|
+
items_prop = create_property(
|
|
177
|
+
name="items",
|
|
178
|
+
logical_type="object",
|
|
179
|
+
physical_type="STRUCT",
|
|
180
|
+
properties=nested_properties,
|
|
181
|
+
)
|
|
182
|
+
prop = create_property(
|
|
183
|
+
name=field_name,
|
|
184
|
+
logical_type="array",
|
|
185
|
+
description=description,
|
|
186
|
+
required=None,
|
|
187
|
+
items=items_prop,
|
|
188
|
+
)
|
|
189
|
+
else:
|
|
190
|
+
prop = create_property(
|
|
191
|
+
name=field_name,
|
|
192
|
+
logical_type="object",
|
|
193
|
+
physical_type="STRUCT",
|
|
194
|
+
description=description,
|
|
195
|
+
required=required if required else None,
|
|
196
|
+
properties=nested_properties,
|
|
197
|
+
)
|
|
167
198
|
elif field_type == "RANGE":
|
|
168
199
|
# Range of date/datetime/timestamp - multiple values, map to array
|
|
169
200
|
items_prop = create_property(
|
|
@@ -194,17 +225,33 @@ def import_table_fields(table_fields) -> List[SchemaProperty]:
|
|
|
194
225
|
if field.get("scale") is not None:
|
|
195
226
|
scale = int(field.get("scale"))
|
|
196
227
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
228
|
+
if repeated:
|
|
229
|
+
items_prop = create_property(
|
|
230
|
+
name="items",
|
|
231
|
+
logical_type=logical_type,
|
|
232
|
+
physical_type=field_type,
|
|
233
|
+
max_length=max_length,
|
|
234
|
+
precision=precision,
|
|
235
|
+
scale=scale,
|
|
236
|
+
)
|
|
237
|
+
prop = create_property(
|
|
238
|
+
name=field_name,
|
|
239
|
+
logical_type="array",
|
|
240
|
+
description=description,
|
|
241
|
+
required=None,
|
|
242
|
+
items=items_prop,
|
|
243
|
+
)
|
|
244
|
+
else:
|
|
245
|
+
prop = create_property(
|
|
246
|
+
name=field_name,
|
|
247
|
+
logical_type=logical_type,
|
|
248
|
+
physical_type=field_type,
|
|
249
|
+
description=description,
|
|
250
|
+
required=required if required else None,
|
|
251
|
+
max_length=max_length,
|
|
252
|
+
precision=precision,
|
|
253
|
+
scale=scale,
|
|
254
|
+
)
|
|
208
255
|
properties.append(prop)
|
|
209
256
|
|
|
210
257
|
return properties
|