datacontract-cli 0.11.2__tar.gz → 0.11.3__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.2/datacontract_cli.egg-info → datacontract_cli-0.11.3}/PKG-INFO +9 -10
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/README.md +1 -2
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/catalog/catalog.py +1 -1
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/cli.py +5 -5
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/data_contract_checks.py +1 -1
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/duckdb_connection.py +70 -17
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/bigquery_exporter.py +2 -2
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/pydantic_exporter.py +15 -4
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/init/init_template.py +1 -1
- datacontract_cli-0.11.3/datacontract/schemas/odcs-3.1.0.init.yaml +36 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3/datacontract_cli.egg-info}/PKG-INFO +9 -10
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract_cli.egg-info/SOURCES.txt +2 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract_cli.egg-info/requires.txt +7 -7
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/pyproject.toml +8 -8
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_download_datacontract_file.py +18 -3
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_pydantic.py +17 -1
- datacontract_cli-0.11.3/tests/test_test_schema_evolution.py +110 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/LICENSE +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/MANIFEST.in +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/__init__.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/api.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/data_contract.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/data_contract_test.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/__init__.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/check_soda_execute.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/athena.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/bigquery.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/databricks.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/impala.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/kafka.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/oracle.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/postgres.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/snowflake.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/sqlserver.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/soda/connections/trino.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/avro_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/avro_idl_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/data_caterer_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/dbml_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/dbt_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/dqx_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/excel_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/great_expectations_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/html_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/iceberg_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/markdown_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/mermaid_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/odcs_export_helper.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/protobuf_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/rdf_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/sql_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/sqlalchemy_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/dcs_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/excel_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/json_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/odcs_helper.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/lint/files.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/model/run.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/output/__init__.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/output/junit_test_results.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/output/test_results_writer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/py.typed +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/index.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/model_field.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/setup.cfg +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_api.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_catalog.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_cli.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_data_contract_checks.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_description_linter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_avro.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_custom.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_excel.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_go.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_html.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_spark.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_sql.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_avro.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_csv.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_excel.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_glue.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_json.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_spark.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_sql_oracle.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_lint.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_resolve.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_api.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_delta.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_output_junit.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_quality.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/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.3
|
|
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
|
|
@@ -16,7 +16,7 @@ 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
|
|
18
18
|
Requires-Dist: fastjsonschema<2.22.0,>=2.19.1
|
|
19
|
-
Requires-Dist: fastparquet<
|
|
19
|
+
Requires-Dist: fastparquet<2026.0.0,>=2024.5.0
|
|
20
20
|
Requires-Dist: numpy<2.0.0,>=1.26.4
|
|
21
21
|
Requires-Dist: python-multipart<1.0.0,>=0.0.20
|
|
22
22
|
Requires-Dist: rich<15.0,>=13.7
|
|
@@ -29,7 +29,7 @@ Requires-Dist: boto3<2.0.0,>=1.34.41
|
|
|
29
29
|
Requires-Dist: Jinja2<4.0.0,>=3.1.5
|
|
30
30
|
Requires-Dist: jinja_partials<1.0.0,>=0.2.1
|
|
31
31
|
Requires-Dist: datacontract-specification<2.0.0,>=1.2.3
|
|
32
|
-
Requires-Dist: open-data-contract-standard<4.0.0,>=3.1.
|
|
32
|
+
Requires-Dist: open-data-contract-standard<4.0.0,>=3.1.2
|
|
33
33
|
Provides-Extra: avro
|
|
34
34
|
Requires-Dist: avro==1.12.1; extra == "avro"
|
|
35
35
|
Provides-Extra: bigquery
|
|
@@ -43,18 +43,18 @@ Requires-Dist: soda-core-spark-df<3.6.0,>=3.3.20; extra == "databricks"
|
|
|
43
43
|
Requires-Dist: soda-core-spark[databricks]<3.6.0,>=3.3.20; extra == "databricks"
|
|
44
44
|
Requires-Dist: databricks-sql-connector<4.3.0,>=3.7.0; extra == "databricks"
|
|
45
45
|
Requires-Dist: databricks-sdk<0.74.0; extra == "databricks"
|
|
46
|
-
Requires-Dist: pyspark<
|
|
46
|
+
Requires-Dist: pyspark<5.0.0,>=3.5.5; extra == "databricks"
|
|
47
47
|
Provides-Extra: iceberg
|
|
48
48
|
Requires-Dist: pyiceberg==0.10.0; extra == "iceberg"
|
|
49
49
|
Provides-Extra: kafka
|
|
50
50
|
Requires-Dist: datacontract-cli[avro]; extra == "kafka"
|
|
51
51
|
Requires-Dist: soda-core-spark-df<3.6.0,>=3.3.20; extra == "kafka"
|
|
52
|
-
Requires-Dist: pyspark<
|
|
52
|
+
Requires-Dist: pyspark<5.0.0,>=3.5.5; extra == "kafka"
|
|
53
53
|
Provides-Extra: postgres
|
|
54
54
|
Requires-Dist: soda-core-postgres<3.6.0,>=3.3.20; extra == "postgres"
|
|
55
55
|
Provides-Extra: s3
|
|
56
56
|
Requires-Dist: s3fs<2026.0.0,>=2025.2.0; extra == "s3"
|
|
57
|
-
Requires-Dist: aiobotocore<2.
|
|
57
|
+
Requires-Dist: aiobotocore<3.2.0,>=2.17.0; extra == "s3"
|
|
58
58
|
Provides-Extra: snowflake
|
|
59
59
|
Requires-Dist: snowflake-connector-python[pandas]<4.2,>=3.6; extra == "snowflake"
|
|
60
60
|
Requires-Dist: soda-core-snowflake<3.6.0,>=3.3.20; extra == "snowflake"
|
|
@@ -73,10 +73,10 @@ Requires-Dist: pydbml>=1.1.1; extra == "dbml"
|
|
|
73
73
|
Provides-Extra: parquet
|
|
74
74
|
Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
|
|
75
75
|
Provides-Extra: rdf
|
|
76
|
-
Requires-Dist: rdflib==7.
|
|
76
|
+
Requires-Dist: rdflib==7.5.0; extra == "rdf"
|
|
77
77
|
Provides-Extra: api
|
|
78
78
|
Requires-Dist: fastapi==0.121.2; extra == "api"
|
|
79
|
-
Requires-Dist: uvicorn==0.
|
|
79
|
+
Requires-Dist: uvicorn==0.40.0; extra == "api"
|
|
80
80
|
Provides-Extra: protobuf
|
|
81
81
|
Requires-Dist: grpcio-tools>=1.53; extra == "protobuf"
|
|
82
82
|
Provides-Extra: all
|
|
@@ -657,8 +657,7 @@ datacontract.yaml
|
|
|
657
657
|
servers:
|
|
658
658
|
production:
|
|
659
659
|
type: azure
|
|
660
|
-
|
|
661
|
-
location: abfss://dataproducts/inventory_events/*.parquet
|
|
660
|
+
location: abfss://datameshdatabricksdemo.dfs.core.windows.net/inventory_events/*.parquet
|
|
662
661
|
format: parquet
|
|
663
662
|
```
|
|
664
663
|
|
|
@@ -558,8 +558,7 @@ datacontract.yaml
|
|
|
558
558
|
servers:
|
|
559
559
|
production:
|
|
560
560
|
type: azure
|
|
561
|
-
|
|
562
|
-
location: abfss://dataproducts/inventory_events/*.parquet
|
|
561
|
+
location: abfss://datameshdatabricksdemo.dfs.core.windows.net/inventory_events/*.parquet
|
|
563
562
|
format: parquet
|
|
564
563
|
```
|
|
565
564
|
|
|
@@ -14,7 +14,7 @@ from datacontract.export.html_exporter import get_version
|
|
|
14
14
|
|
|
15
15
|
def _get_owner(odcs: OpenDataContractStandard) -> Optional[str]:
|
|
16
16
|
"""Get the owner from ODCS customProperties or team."""
|
|
17
|
-
if odcs.team and odcs.team.name:
|
|
17
|
+
if odcs.team and hasattr(odcs.team, "name") and odcs.team.name:
|
|
18
18
|
return odcs.team.name
|
|
19
19
|
if odcs.customProperties:
|
|
20
20
|
for prop in odcs.customProperties:
|
|
@@ -67,7 +67,7 @@ def common(
|
|
|
67
67
|
pass
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
@app.command()
|
|
70
|
+
@app.command(name="init")
|
|
71
71
|
def init(
|
|
72
72
|
location: Annotated[
|
|
73
73
|
str, typer.Argument(help="The location of the data contract file to create.")
|
|
@@ -90,7 +90,7 @@ def init(
|
|
|
90
90
|
console.print("📄 data contract written to " + location)
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
@app.command()
|
|
93
|
+
@app.command(name="lint")
|
|
94
94
|
def lint(
|
|
95
95
|
location: Annotated[
|
|
96
96
|
str,
|
|
@@ -125,7 +125,7 @@ def enable_debug_logging(debug: bool):
|
|
|
125
125
|
)
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
@app.command()
|
|
128
|
+
@app.command(name="test")
|
|
129
129
|
def test(
|
|
130
130
|
location: Annotated[
|
|
131
131
|
str,
|
|
@@ -187,7 +187,7 @@ def test(
|
|
|
187
187
|
write_test_result(run, console, output_format, output, data_contract)
|
|
188
188
|
|
|
189
189
|
|
|
190
|
-
@app.command()
|
|
190
|
+
@app.command(name="export")
|
|
191
191
|
def export(
|
|
192
192
|
format: Annotated[ExportFormat, typer.Option(help="The export format.")],
|
|
193
193
|
output: Annotated[
|
|
@@ -467,7 +467,7 @@ def _get_uvicorn_arguments(port: int, host: str, context: typer.Context) -> dict
|
|
|
467
467
|
return default_args | dict(zip(trimmed_keys, context.args[1::2]))
|
|
468
468
|
|
|
469
469
|
|
|
470
|
-
@app.command(context_settings={"allow_extra_args": True, "ignore_unknown_options": True})
|
|
470
|
+
@app.command(name="api", context_settings={"allow_extra_args": True, "ignore_unknown_options": True})
|
|
471
471
|
def api(
|
|
472
472
|
ctx: Annotated[typer.Context, typer.Option(help="Extra arguments to pass to uvicorn.run().")],
|
|
473
473
|
port: Annotated[int, typer.Option(help="Bind socket to this port.")] = 4242,
|
{datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/engines/data_contract_checks.py
RENAMED
|
@@ -161,7 +161,7 @@ def to_schema_name(schema_object: SchemaObject, server_type: str) -> str:
|
|
|
161
161
|
# Use physicalName if set (ODCS standard way to specify actual table name)
|
|
162
162
|
if schema_object.physicalName:
|
|
163
163
|
return schema_object.physicalName
|
|
164
|
-
|
|
164
|
+
|
|
165
165
|
return schema_object.name
|
|
166
166
|
|
|
167
167
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import re
|
|
2
3
|
from typing import Any, List, Optional
|
|
3
4
|
|
|
4
5
|
import duckdb
|
|
5
6
|
from open_data_contract_standard.model import OpenDataContractStandard, SchemaObject, SchemaProperty, Server
|
|
6
7
|
|
|
7
8
|
from datacontract.export.duckdb_type_converter import convert_to_duckdb_csv_type, convert_to_duckdb_json_type
|
|
9
|
+
from datacontract.export.sql_type_converter import convert_to_duckdb
|
|
8
10
|
from datacontract.model.run import Run
|
|
9
11
|
|
|
10
12
|
|
|
@@ -57,20 +59,9 @@ def get_duckdb_connection(
|
|
|
57
59
|
)
|
|
58
60
|
add_nested_views(con, model_name, schema_obj.properties)
|
|
59
61
|
elif server.format == "parquet":
|
|
60
|
-
con
|
|
61
|
-
CREATE VIEW "{model_name}" AS SELECT * FROM read_parquet('{model_path}', hive_partitioning=1);
|
|
62
|
-
""")
|
|
62
|
+
create_view_with_schema_union(con, schema_obj, model_path, "read_parquet", to_parquet_types)
|
|
63
63
|
elif server.format == "csv":
|
|
64
|
-
|
|
65
|
-
run.log_info("Using columns: " + str(columns))
|
|
66
|
-
if columns is None:
|
|
67
|
-
con.sql(
|
|
68
|
-
f"""CREATE VIEW "{model_name}" AS SELECT * FROM read_csv('{model_path}', hive_partitioning=1);"""
|
|
69
|
-
)
|
|
70
|
-
else:
|
|
71
|
-
con.sql(
|
|
72
|
-
f"""CREATE VIEW "{model_name}" AS SELECT * FROM read_csv('{model_path}', hive_partitioning=1, columns={columns});"""
|
|
73
|
-
)
|
|
64
|
+
create_view_with_schema_union(con, schema_obj, model_path, "read_csv", to_csv_types)
|
|
74
65
|
elif server.format == "delta":
|
|
75
66
|
con.sql("update extensions;") # Make sure we have the latest delta extension
|
|
76
67
|
con.sql(f"""CREATE VIEW "{model_name}" AS SELECT * FROM delta_scan('{model_path}');""")
|
|
@@ -80,6 +71,34 @@ def get_duckdb_connection(
|
|
|
80
71
|
return con
|
|
81
72
|
|
|
82
73
|
|
|
74
|
+
def create_view_with_schema_union(con, schema_obj: SchemaObject, model_path: str, read_function: str, type_converter):
|
|
75
|
+
"""Create a view by unioning empty schema table with data files using union_by_name"""
|
|
76
|
+
converted_types = type_converter(schema_obj)
|
|
77
|
+
model_name = schema_obj.name
|
|
78
|
+
if converted_types:
|
|
79
|
+
# Create empty table with contract schema
|
|
80
|
+
columns_def = [f'"{col_name}" {col_type}' for col_name, col_type in converted_types.items()]
|
|
81
|
+
create_empty_table = f"""CREATE TABLE "{model_name}" ({', '.join(columns_def)});"""
|
|
82
|
+
con.sql(create_empty_table)
|
|
83
|
+
|
|
84
|
+
# Read columns existing in both current data contract and data
|
|
85
|
+
intersecting_columns = con.sql(f"""SELECT column_name
|
|
86
|
+
FROM (DESCRIBE SELECT * FROM {read_function}('{model_path}', union_by_name=true, hive_partitioning=1))
|
|
87
|
+
INTERSECT SELECT column_name
|
|
88
|
+
FROM information_schema.columns
|
|
89
|
+
WHERE table_name = '{model_name}'""").fetchall()
|
|
90
|
+
selected_columns = ', '.join([column[0] for column in intersecting_columns])
|
|
91
|
+
|
|
92
|
+
# Insert data into table by name, but only columns existing in contract and data
|
|
93
|
+
insert_data_sql = f"""INSERT INTO {model_name} BY NAME
|
|
94
|
+
(SELECT {selected_columns} FROM {read_function}('{model_path}', union_by_name=true, hive_partitioning=1));"""
|
|
95
|
+
con.sql(insert_data_sql)
|
|
96
|
+
else:
|
|
97
|
+
# Fallback
|
|
98
|
+
con.sql(
|
|
99
|
+
f"""CREATE VIEW "{model_name}" AS SELECT * FROM {read_function}('{model_path}', union_by_name=true, hive_partitioning=1);"""
|
|
100
|
+
)
|
|
101
|
+
|
|
83
102
|
def to_csv_types(schema_obj: SchemaObject) -> dict[Any, str | None] | None:
|
|
84
103
|
if schema_obj is None:
|
|
85
104
|
return None
|
|
@@ -89,6 +108,15 @@ def to_csv_types(schema_obj: SchemaObject) -> dict[Any, str | None] | None:
|
|
|
89
108
|
columns[prop.name] = convert_to_duckdb_csv_type(prop)
|
|
90
109
|
return columns
|
|
91
110
|
|
|
111
|
+
def to_parquet_types(schema_obj: SchemaObject) -> dict[Any, str | None] | None:
|
|
112
|
+
"""Get proper SQL types for Parquet (preserves decimals, etc.)"""
|
|
113
|
+
if schema_obj is None:
|
|
114
|
+
return None
|
|
115
|
+
columns = {}
|
|
116
|
+
if schema_obj.properties:
|
|
117
|
+
for prop in schema_obj.properties:
|
|
118
|
+
columns[prop.name] = convert_to_duckdb(prop)
|
|
119
|
+
return columns
|
|
92
120
|
|
|
93
121
|
def to_json_types(schema_obj: SchemaObject) -> dict[Any, str | None] | None:
|
|
94
122
|
if schema_obj is None:
|
|
@@ -140,7 +168,7 @@ def add_nested_views(con: duckdb.DuckDBPyConnection, model_name: str, properties
|
|
|
140
168
|
add_nested_views(con, nested_model_name, prop.properties)
|
|
141
169
|
|
|
142
170
|
|
|
143
|
-
def setup_s3_connection(con, server):
|
|
171
|
+
def setup_s3_connection(con, server: Server):
|
|
144
172
|
s3_region = os.getenv("DATACONTRACT_S3_REGION")
|
|
145
173
|
s3_access_key_id = os.getenv("DATACONTRACT_S3_ACCESS_KEY_ID")
|
|
146
174
|
s3_secret_access_key = os.getenv("DATACONTRACT_S3_SECRET_ACCESS_KEY")
|
|
@@ -184,7 +212,7 @@ def setup_s3_connection(con, server):
|
|
|
184
212
|
""")
|
|
185
213
|
|
|
186
214
|
|
|
187
|
-
def setup_gcs_connection(con, server):
|
|
215
|
+
def setup_gcs_connection(con, server: Server):
|
|
188
216
|
key_id = os.getenv("DATACONTRACT_GCS_KEY_ID")
|
|
189
217
|
secret = os.getenv("DATACONTRACT_GCS_SECRET")
|
|
190
218
|
|
|
@@ -202,11 +230,14 @@ def setup_gcs_connection(con, server):
|
|
|
202
230
|
""")
|
|
203
231
|
|
|
204
232
|
|
|
205
|
-
def setup_azure_connection(con, server):
|
|
233
|
+
def setup_azure_connection(con, server: Server):
|
|
206
234
|
tenant_id = os.getenv("DATACONTRACT_AZURE_TENANT_ID")
|
|
207
235
|
client_id = os.getenv("DATACONTRACT_AZURE_CLIENT_ID")
|
|
208
236
|
client_secret = os.getenv("DATACONTRACT_AZURE_CLIENT_SECRET")
|
|
209
|
-
storage_account =
|
|
237
|
+
storage_account = (
|
|
238
|
+
to_azure_storage_account(server.location) if server.type == "azure" and "://" in server.location
|
|
239
|
+
else None
|
|
240
|
+
)
|
|
210
241
|
|
|
211
242
|
if tenant_id is None:
|
|
212
243
|
raise ValueError("Error: Environment variable DATACONTRACT_AZURE_TENANT_ID is not set")
|
|
@@ -239,3 +270,25 @@ def setup_azure_connection(con, server):
|
|
|
239
270
|
CLIENT_SECRET '{client_secret}'
|
|
240
271
|
);
|
|
241
272
|
""")
|
|
273
|
+
|
|
274
|
+
def to_azure_storage_account(location: str) -> str | None:
|
|
275
|
+
"""
|
|
276
|
+
Converts a storage location string to extract the storage account name.
|
|
277
|
+
ODCS v3.0 has no explicit field for the storage account. It uses the location field, which is a URI.
|
|
278
|
+
This function parses a storage location string to identify and return the
|
|
279
|
+
storage account name. It handles two primary patterns:
|
|
280
|
+
1. Protocol://containerName@storageAccountName
|
|
281
|
+
2. Protocol://storageAccountName
|
|
282
|
+
:param location: The storage location string to parse, typically following
|
|
283
|
+
the format protocol://containerName@storageAccountName. or
|
|
284
|
+
protocol://storageAccountName.
|
|
285
|
+
:return: The extracted storage account name if found, otherwise None
|
|
286
|
+
"""
|
|
287
|
+
# to catch protocol://containerName@storageAccountName. pattern from location
|
|
288
|
+
match = re.search(r"(?<=@)([^.]*)", location, re.IGNORECASE)
|
|
289
|
+
if match:
|
|
290
|
+
return match.group()
|
|
291
|
+
else:
|
|
292
|
+
# to catch protocol://storageAccountName. pattern from location
|
|
293
|
+
match = re.search(r"(?<=//)(?!@)([^.]*)", location, re.IGNORECASE)
|
|
294
|
+
return match.group() if match else None
|
{datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/bigquery_exporter.py
RENAMED
|
@@ -113,8 +113,8 @@ def map_type_to_bigquery(prop: SchemaProperty) -> str:
|
|
|
113
113
|
# If physicalType is already a BigQuery type, return it directly
|
|
114
114
|
if prop.physicalType:
|
|
115
115
|
bq_types = {
|
|
116
|
-
"STRING", "BYTES", "INT64", "INTEGER", "FLOAT64", "
|
|
117
|
-
"BIGNUMERIC", "BOOL", "
|
|
116
|
+
"STRING", "BYTES", "INT64", "INTEGER", "FLOAT64", "NUMERIC",
|
|
117
|
+
"BIGNUMERIC", "BOOL", "TIMESTAMP", "DATE", "TIME", "DATETIME",
|
|
118
118
|
"GEOGRAPHY", "JSON", "RECORD", "STRUCT", "ARRAY"
|
|
119
119
|
}
|
|
120
120
|
if prop.physicalType.upper() in bq_types or prop.physicalType.upper().startswith(("STRUCT<", "ARRAY<", "RANGE<")):
|
{datacontract_cli-0.11.2 → datacontract_cli-0.11.3}/datacontract/export/pydantic_exporter.py
RENAMED
|
@@ -19,9 +19,9 @@ def _get_description_str(description) -> str | None:
|
|
|
19
19
|
if isinstance(description, str):
|
|
20
20
|
return description
|
|
21
21
|
# It's a Description object - get purpose or other meaningful field
|
|
22
|
-
if hasattr(description,
|
|
22
|
+
if hasattr(description, "purpose") and description.purpose:
|
|
23
23
|
return description.purpose
|
|
24
|
-
if hasattr(description,
|
|
24
|
+
if hasattr(description, "usage") and description.usage:
|
|
25
25
|
return description.usage
|
|
26
26
|
return None
|
|
27
27
|
|
|
@@ -41,6 +41,7 @@ def to_pydantic_model_str(contract: OpenDataContractStandard) -> str:
|
|
|
41
41
|
ast.Name("datetime", ctx=ast.Load()),
|
|
42
42
|
ast.Name("typing", ctx=ast.Load()),
|
|
43
43
|
ast.Name("pydantic", ctx=ast.Load()),
|
|
44
|
+
ast.Name("decimal", ctx=ast.Load()),
|
|
44
45
|
]
|
|
45
46
|
),
|
|
46
47
|
*documentation,
|
|
@@ -76,14 +77,23 @@ def _get_type(prop: SchemaProperty) -> Optional[str]:
|
|
|
76
77
|
return prop.logicalType
|
|
77
78
|
|
|
78
79
|
|
|
80
|
+
def _get_physical_type(prop: SchemaProperty) -> Optional[str]:
|
|
81
|
+
"""Get the physical type from a schema property."""
|
|
82
|
+
return prop.physicalType.lower() if prop.physicalType else None
|
|
83
|
+
|
|
84
|
+
|
|
79
85
|
def constant_field_annotation(
|
|
80
86
|
field_name: str, prop: SchemaProperty
|
|
81
87
|
) -> tuple[type_annotation_type, typing.Optional[ast.ClassDef]]:
|
|
82
88
|
prop_type = _get_type(prop)
|
|
89
|
+
physical_type = _get_physical_type(prop)
|
|
90
|
+
|
|
83
91
|
match prop_type:
|
|
84
92
|
case "string":
|
|
85
93
|
return (ast.Name("str", ctx=ast.Load()), None)
|
|
86
94
|
case "number":
|
|
95
|
+
if physical_type == "decimal":
|
|
96
|
+
return (ast.Attribute(value=ast.Name(id="decimal", ctx=ast.Load()), attr="Decimal"), None)
|
|
87
97
|
# Either integer or float in specification,
|
|
88
98
|
# so we use float.
|
|
89
99
|
return (ast.Name("float", ctx=ast.Load()), None)
|
|
@@ -103,7 +113,6 @@ def constant_field_annotation(
|
|
|
103
113
|
return (ast.Name(field_name.capitalize(), ctx=ast.Load()), classdef)
|
|
104
114
|
case _:
|
|
105
115
|
# Check physical type for more specific mappings
|
|
106
|
-
physical_type = prop.physicalType.lower() if prop.physicalType else None
|
|
107
116
|
if physical_type:
|
|
108
117
|
if physical_type in ["text", "varchar", "char", "nvarchar"]:
|
|
109
118
|
return (ast.Name("str", ctx=ast.Load()), None)
|
|
@@ -115,8 +124,10 @@ def constant_field_annotation(
|
|
|
115
124
|
return (ast.Name("float", ctx=ast.Load()), None)
|
|
116
125
|
elif physical_type in ["double", "float64"]:
|
|
117
126
|
return (ast.Name("float", ctx=ast.Load()), None)
|
|
118
|
-
elif physical_type in ["
|
|
127
|
+
elif physical_type in ["numeric", "number"]:
|
|
119
128
|
return (ast.Name("float", ctx=ast.Load()), None)
|
|
129
|
+
elif physical_type == "decimal":
|
|
130
|
+
return (ast.Attribute(value=ast.Name(id="decimal", ctx=ast.Load()), attr="Decimal"), None)
|
|
120
131
|
elif physical_type in ["timestamp", "datetime", "timestamp_tz", "timestamp_ntz"]:
|
|
121
132
|
return (ast.Attribute(value=ast.Name(id="datetime", ctx=ast.Load()), attr="datetime"), None)
|
|
122
133
|
elif physical_type == "date":
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: v3.1.0
|
|
2
|
+
kind: DataContract
|
|
3
|
+
id: my-data-contract-id
|
|
4
|
+
name: My Data Contract
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
status: draft
|
|
7
|
+
|
|
8
|
+
#team:
|
|
9
|
+
# name: Owner
|
|
10
|
+
#
|
|
11
|
+
#description:
|
|
12
|
+
# purpose: Purpose of the dataset.
|
|
13
|
+
# usage: Intended usage of the dataset.
|
|
14
|
+
# limitations: Limitations of the dataset.
|
|
15
|
+
#
|
|
16
|
+
#schema:
|
|
17
|
+
# - name: my_table
|
|
18
|
+
# description: Description of the table
|
|
19
|
+
# properties:
|
|
20
|
+
# - name: my_field
|
|
21
|
+
# logicalType: string
|
|
22
|
+
# description: Description of the field
|
|
23
|
+
#
|
|
24
|
+
#servers:
|
|
25
|
+
# - server: production
|
|
26
|
+
# type: postgres
|
|
27
|
+
# host: localhost
|
|
28
|
+
# port: 5432
|
|
29
|
+
# database: my_database
|
|
30
|
+
# schema: public
|
|
31
|
+
#
|
|
32
|
+
#slaProperties:
|
|
33
|
+
# - property: latency
|
|
34
|
+
# value: 1h
|
|
35
|
+
# - property: availability
|
|
36
|
+
# value: 99.9%
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.3
|
|
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
|
|
@@ -16,7 +16,7 @@ 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
|
|
18
18
|
Requires-Dist: fastjsonschema<2.22.0,>=2.19.1
|
|
19
|
-
Requires-Dist: fastparquet<
|
|
19
|
+
Requires-Dist: fastparquet<2026.0.0,>=2024.5.0
|
|
20
20
|
Requires-Dist: numpy<2.0.0,>=1.26.4
|
|
21
21
|
Requires-Dist: python-multipart<1.0.0,>=0.0.20
|
|
22
22
|
Requires-Dist: rich<15.0,>=13.7
|
|
@@ -29,7 +29,7 @@ Requires-Dist: boto3<2.0.0,>=1.34.41
|
|
|
29
29
|
Requires-Dist: Jinja2<4.0.0,>=3.1.5
|
|
30
30
|
Requires-Dist: jinja_partials<1.0.0,>=0.2.1
|
|
31
31
|
Requires-Dist: datacontract-specification<2.0.0,>=1.2.3
|
|
32
|
-
Requires-Dist: open-data-contract-standard<4.0.0,>=3.1.
|
|
32
|
+
Requires-Dist: open-data-contract-standard<4.0.0,>=3.1.2
|
|
33
33
|
Provides-Extra: avro
|
|
34
34
|
Requires-Dist: avro==1.12.1; extra == "avro"
|
|
35
35
|
Provides-Extra: bigquery
|
|
@@ -43,18 +43,18 @@ Requires-Dist: soda-core-spark-df<3.6.0,>=3.3.20; extra == "databricks"
|
|
|
43
43
|
Requires-Dist: soda-core-spark[databricks]<3.6.0,>=3.3.20; extra == "databricks"
|
|
44
44
|
Requires-Dist: databricks-sql-connector<4.3.0,>=3.7.0; extra == "databricks"
|
|
45
45
|
Requires-Dist: databricks-sdk<0.74.0; extra == "databricks"
|
|
46
|
-
Requires-Dist: pyspark<
|
|
46
|
+
Requires-Dist: pyspark<5.0.0,>=3.5.5; extra == "databricks"
|
|
47
47
|
Provides-Extra: iceberg
|
|
48
48
|
Requires-Dist: pyiceberg==0.10.0; extra == "iceberg"
|
|
49
49
|
Provides-Extra: kafka
|
|
50
50
|
Requires-Dist: datacontract-cli[avro]; extra == "kafka"
|
|
51
51
|
Requires-Dist: soda-core-spark-df<3.6.0,>=3.3.20; extra == "kafka"
|
|
52
|
-
Requires-Dist: pyspark<
|
|
52
|
+
Requires-Dist: pyspark<5.0.0,>=3.5.5; extra == "kafka"
|
|
53
53
|
Provides-Extra: postgres
|
|
54
54
|
Requires-Dist: soda-core-postgres<3.6.0,>=3.3.20; extra == "postgres"
|
|
55
55
|
Provides-Extra: s3
|
|
56
56
|
Requires-Dist: s3fs<2026.0.0,>=2025.2.0; extra == "s3"
|
|
57
|
-
Requires-Dist: aiobotocore<2.
|
|
57
|
+
Requires-Dist: aiobotocore<3.2.0,>=2.17.0; extra == "s3"
|
|
58
58
|
Provides-Extra: snowflake
|
|
59
59
|
Requires-Dist: snowflake-connector-python[pandas]<4.2,>=3.6; extra == "snowflake"
|
|
60
60
|
Requires-Dist: soda-core-snowflake<3.6.0,>=3.3.20; extra == "snowflake"
|
|
@@ -73,10 +73,10 @@ Requires-Dist: pydbml>=1.1.1; extra == "dbml"
|
|
|
73
73
|
Provides-Extra: parquet
|
|
74
74
|
Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
|
|
75
75
|
Provides-Extra: rdf
|
|
76
|
-
Requires-Dist: rdflib==7.
|
|
76
|
+
Requires-Dist: rdflib==7.5.0; extra == "rdf"
|
|
77
77
|
Provides-Extra: api
|
|
78
78
|
Requires-Dist: fastapi==0.121.2; extra == "api"
|
|
79
|
-
Requires-Dist: uvicorn==0.
|
|
79
|
+
Requires-Dist: uvicorn==0.40.0; extra == "api"
|
|
80
80
|
Provides-Extra: protobuf
|
|
81
81
|
Requires-Dist: grpcio-tools>=1.53; extra == "protobuf"
|
|
82
82
|
Provides-Extra: all
|
|
@@ -657,8 +657,7 @@ datacontract.yaml
|
|
|
657
657
|
servers:
|
|
658
658
|
production:
|
|
659
659
|
type: azure
|
|
660
|
-
|
|
661
|
-
location: abfss://dataproducts/inventory_events/*.parquet
|
|
660
|
+
location: abfss://datameshdatabricksdemo.dfs.core.windows.net/inventory_events/*.parquet
|
|
662
661
|
format: parquet
|
|
663
662
|
```
|
|
664
663
|
|
|
@@ -102,6 +102,7 @@ datacontract/schemas/datacontract-1.2.1.init.yaml
|
|
|
102
102
|
datacontract/schemas/datacontract-1.2.1.schema.json
|
|
103
103
|
datacontract/schemas/odcs-3.0.1.schema.json
|
|
104
104
|
datacontract/schemas/odcs-3.0.2.schema.json
|
|
105
|
+
datacontract/schemas/odcs-3.1.0.init.yaml
|
|
105
106
|
datacontract/schemas/odcs-3.1.0.schema.json
|
|
106
107
|
datacontract/templates/datacontract.html
|
|
107
108
|
datacontract/templates/datacontract_odcs.html
|
|
@@ -204,6 +205,7 @@ tests/test_test_s3_json.py
|
|
|
204
205
|
tests/test_test_s3_json_complex.py
|
|
205
206
|
tests/test_test_s3_json_multiple_models.py
|
|
206
207
|
tests/test_test_s3_json_remote.py
|
|
208
|
+
tests/test_test_schema_evolution.py
|
|
207
209
|
tests/test_test_snowflake.py
|
|
208
210
|
tests/test_test_sqlserver.py
|
|
209
211
|
tests/test_test_trino.py
|
|
@@ -3,7 +3,7 @@ pydantic<2.13.0,>=2.8.2
|
|
|
3
3
|
pyyaml~=6.0.1
|
|
4
4
|
requests<2.33,>=2.31
|
|
5
5
|
fastjsonschema<2.22.0,>=2.19.1
|
|
6
|
-
fastparquet<
|
|
6
|
+
fastparquet<2026.0.0,>=2024.5.0
|
|
7
7
|
numpy<2.0.0,>=1.26.4
|
|
8
8
|
python-multipart<1.0.0,>=0.0.20
|
|
9
9
|
rich<15.0,>=13.7
|
|
@@ -16,14 +16,14 @@ boto3<2.0.0,>=1.34.41
|
|
|
16
16
|
Jinja2<4.0.0,>=3.1.5
|
|
17
17
|
jinja_partials<1.0.0,>=0.2.1
|
|
18
18
|
datacontract-specification<2.0.0,>=1.2.3
|
|
19
|
-
open-data-contract-standard<4.0.0,>=3.1.
|
|
19
|
+
open-data-contract-standard<4.0.0,>=3.1.2
|
|
20
20
|
|
|
21
21
|
[all]
|
|
22
22
|
datacontract-cli[api,athena,bigquery,csv,databricks,dbml,dbt,excel,iceberg,kafka,oracle,parquet,postgres,protobuf,rdf,s3,snowflake,sqlserver,trino]
|
|
23
23
|
|
|
24
24
|
[api]
|
|
25
25
|
fastapi==0.121.2
|
|
26
|
-
uvicorn==0.
|
|
26
|
+
uvicorn==0.40.0
|
|
27
27
|
|
|
28
28
|
[athena]
|
|
29
29
|
soda-core-athena<3.6.0,>=3.3.20
|
|
@@ -42,7 +42,7 @@ soda-core-spark-df<3.6.0,>=3.3.20
|
|
|
42
42
|
soda-core-spark[databricks]<3.6.0,>=3.3.20
|
|
43
43
|
databricks-sql-connector<4.3.0,>=3.7.0
|
|
44
44
|
databricks-sdk<0.74.0
|
|
45
|
-
pyspark<
|
|
45
|
+
pyspark<5.0.0,>=3.5.5
|
|
46
46
|
|
|
47
47
|
[dbml]
|
|
48
48
|
pydbml>=1.1.1
|
|
@@ -74,7 +74,7 @@ pyiceberg==0.10.0
|
|
|
74
74
|
[kafka]
|
|
75
75
|
datacontract-cli[avro]
|
|
76
76
|
soda-core-spark-df<3.6.0,>=3.3.20
|
|
77
|
-
pyspark<
|
|
77
|
+
pyspark<5.0.0,>=3.5.5
|
|
78
78
|
|
|
79
79
|
[oracle]
|
|
80
80
|
soda-core-oracle<3.6.0,>=3.3.20
|
|
@@ -89,11 +89,11 @@ soda-core-postgres<3.6.0,>=3.3.20
|
|
|
89
89
|
grpcio-tools>=1.53
|
|
90
90
|
|
|
91
91
|
[rdf]
|
|
92
|
-
rdflib==7.
|
|
92
|
+
rdflib==7.5.0
|
|
93
93
|
|
|
94
94
|
[s3]
|
|
95
95
|
s3fs<2026.0.0,>=2025.2.0
|
|
96
|
-
aiobotocore<2.
|
|
96
|
+
aiobotocore<3.2.0,>=2.17.0
|
|
97
97
|
|
|
98
98
|
[snowflake]
|
|
99
99
|
snowflake-connector-python[pandas]<4.2,>=3.6
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datacontract-cli"
|
|
3
|
-
version = "0.11.
|
|
3
|
+
version = "0.11.3"
|
|
4
4
|
description = "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
|
license = "MIT"
|
|
6
6
|
readme = "README.md"
|
|
@@ -20,7 +20,7 @@ dependencies = [
|
|
|
20
20
|
"pyyaml~=6.0.1",
|
|
21
21
|
"requests>=2.31,<2.33",
|
|
22
22
|
"fastjsonschema>=2.19.1,<2.22.0",
|
|
23
|
-
"fastparquet>=2024.5.0,<
|
|
23
|
+
"fastparquet>=2024.5.0,<2026.0.0",
|
|
24
24
|
"numpy>=1.26.4,<2.0.0", # transitive dependency, needs to be <2.0.0 https://github.com/datacontract/datacontract-cli/issues/575
|
|
25
25
|
"python-multipart>=0.0.20,<1.0.0",
|
|
26
26
|
"rich>=13.7,<15.0",
|
|
@@ -34,7 +34,7 @@ dependencies = [
|
|
|
34
34
|
"Jinja2>=3.1.5,<4.0.0",
|
|
35
35
|
"jinja_partials>=0.2.1,<1.0.0",
|
|
36
36
|
"datacontract-specification>=1.2.3,<2.0.0",
|
|
37
|
-
"open-data-contract-standard>=3.1.
|
|
37
|
+
"open-data-contract-standard>=3.1.2,<4.0.0",
|
|
38
38
|
]
|
|
39
39
|
|
|
40
40
|
[project.optional-dependencies]
|
|
@@ -61,7 +61,7 @@ databricks = [
|
|
|
61
61
|
"soda-core-spark[databricks]>=3.3.20,<3.6.0",
|
|
62
62
|
"databricks-sql-connector>=3.7.0,<4.3.0",
|
|
63
63
|
"databricks-sdk<0.74.0",
|
|
64
|
-
"pyspark>=3.5.5,<
|
|
64
|
+
"pyspark>=3.5.5,<5.0.0",
|
|
65
65
|
]
|
|
66
66
|
|
|
67
67
|
iceberg = [
|
|
@@ -71,7 +71,7 @@ iceberg = [
|
|
|
71
71
|
kafka = [
|
|
72
72
|
"datacontract-cli[avro]",
|
|
73
73
|
"soda-core-spark-df>=3.3.20,<3.6.0",
|
|
74
|
-
"pyspark>=3.5.5,<
|
|
74
|
+
"pyspark>=3.5.5,<5.0.0",
|
|
75
75
|
]
|
|
76
76
|
|
|
77
77
|
postgres = [
|
|
@@ -80,7 +80,7 @@ postgres = [
|
|
|
80
80
|
|
|
81
81
|
s3 = [
|
|
82
82
|
"s3fs>=2025.2.0,<2026.0.0",
|
|
83
|
-
"aiobotocore>=2.17.0,<2.
|
|
83
|
+
"aiobotocore>=2.17.0,<3.2.0",
|
|
84
84
|
]
|
|
85
85
|
|
|
86
86
|
snowflake = [
|
|
@@ -117,12 +117,12 @@ parquet = [
|
|
|
117
117
|
]
|
|
118
118
|
|
|
119
119
|
rdf = [
|
|
120
|
-
"rdflib==7.
|
|
120
|
+
"rdflib==7.5.0",
|
|
121
121
|
]
|
|
122
122
|
|
|
123
123
|
api = [
|
|
124
124
|
"fastapi==0.121.2",
|
|
125
|
-
"uvicorn==0.
|
|
125
|
+
"uvicorn==0.40.0",
|
|
126
126
|
]
|
|
127
127
|
|
|
128
128
|
protobuf = [
|