datacontract-cli 0.10.19__tar.gz → 0.10.21__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.
Potentially problematic release.
This version of datacontract-cli might be problematic. Click here for more details.
- {datacontract_cli-0.10.19/datacontract_cli.egg-info → datacontract_cli-0.10.21}/PKG-INFO +103 -21
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/README.md +94 -15
- datacontract_cli-0.10.21/datacontract/api.py +253 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/cli.py +28 -7
- datacontract_cli-0.10.21/datacontract/export/custom_converter.py +40 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/exporter.py +1 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/exporter_factory.py +4 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/urls.py +13 -9
- datacontract_cli-0.10.21/datacontract/model/data_contract_specification.py +327 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/model/run.py +18 -18
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/datacontract.html +16 -2
- datacontract_cli-0.10.21/datacontract/templates/partials/definition.html +25 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/partials/model_field.html +13 -0
- datacontract_cli-0.10.21/datacontract/templates/partials/quality.html +49 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/style/output.css +151 -152
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21/datacontract_cli.egg-info}/PKG-INFO +103 -21
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/SOURCES.txt +6 -3
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/requires.txt +10 -5
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/pyproject.toml +13 -6
- datacontract_cli-0.10.19/tests/test_web.py → datacontract_cli-0.10.21/tests/test_api.py +6 -8
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_catalog.py +1 -0
- datacontract_cli-0.10.21/tests/test_export_custom.py +34 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_custom_exporter.py +2 -2
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_html.py +0 -11
- datacontract_cli-0.10.19/datacontract/model/data_contract_specification.py +0 -326
- datacontract_cli-0.10.19/datacontract/templates/partials/definition.html +0 -117
- datacontract_cli-0.10.19/datacontract/web.py +0 -67
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/LICENSE +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/MANIFEST.in +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/__init__.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/breaking/breaking.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/breaking/breaking_rules.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/catalog/catalog.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/data_contract.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/__init__.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/check_soda_execute.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/bigquery.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/dask.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/databricks.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/duckdb.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/kafka.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/postgres.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/snowflake.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/sqlserver.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/trino.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/avro_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/avro_idl_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/bigquery_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/csv_type_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/data_caterer_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/dbml_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/dbt_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/go_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/great_expectations_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/html_export.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/iceberg_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/jsonschema_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/markdown_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/odcs_v2_exporter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/protobuf_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/pydantic_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/rdf_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/sodacl_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/spark_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/sql_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/sqlalchemy_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/export/terraform_converter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/odcs_v2_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/odcs_v3_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/integration/datamesh_manager.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/files.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/lint.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/__init__.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/description_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/example_model_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/field_pattern_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/field_reference_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/notice_period_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/quality_schema_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/linters/valid_constraints_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/model/breaking_change.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/py.typed +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/index.html +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/setup.cfg +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_breaking.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_changelog.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_cli.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_description_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_documentation_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_example_model_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_avro.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_go.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_odcs_v2.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_spark.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_sql.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_export_terraform.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_field_constraint_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_field_pattern_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_field_reference_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_avro.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_csv.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_glue.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_odcs_v2.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_spark.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_sql.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_integration_datameshmanager.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_lint.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_notice_period_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_quality_schema_linter.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_resolve.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_spec_fields_field.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_spec_ref.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_delta.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_examples_csv.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_examples_formats_valid.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_examples_inline.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_examples_json.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_examples_missing.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_quality.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-0.10.19 → datacontract_cli-0.10.21}/tests/test_test_trino.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.21
|
|
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
|
Project-URL: Homepage, https://cli.datacontract.com
|
|
@@ -15,8 +15,6 @@ Requires-Dist: typer<0.16,>=0.15.1
|
|
|
15
15
|
Requires-Dist: pydantic<2.11.0,>=2.8.2
|
|
16
16
|
Requires-Dist: pyyaml~=6.0.1
|
|
17
17
|
Requires-Dist: requests<2.33,>=2.31
|
|
18
|
-
Requires-Dist: fastapi==0.115.6
|
|
19
|
-
Requires-Dist: uvicorn==0.34.0
|
|
20
18
|
Requires-Dist: fastjsonschema<2.22.0,>=2.19.1
|
|
21
19
|
Requires-Dist: fastparquet==2024.11.0
|
|
22
20
|
Requires-Dist: numpy<2.0.0,>=1.26.4
|
|
@@ -51,7 +49,7 @@ Provides-Extra: postgres
|
|
|
51
49
|
Requires-Dist: soda-core-postgres<3.4.0,>=3.3.20; extra == "postgres"
|
|
52
50
|
Provides-Extra: s3
|
|
53
51
|
Requires-Dist: s3fs==2024.12.0; extra == "s3"
|
|
54
|
-
Requires-Dist: aiobotocore<2.
|
|
52
|
+
Requires-Dist: aiobotocore<2.20.0,>=2.17.0; extra == "s3"
|
|
55
53
|
Provides-Extra: snowflake
|
|
56
54
|
Requires-Dist: snowflake-connector-python[pandas]<3.13,>=3.6; extra == "snowflake"
|
|
57
55
|
Requires-Dist: soda-core-snowflake<3.4.0,>=3.3.20; extra == "snowflake"
|
|
@@ -65,13 +63,18 @@ Provides-Extra: dbml
|
|
|
65
63
|
Requires-Dist: pydbml>=1.1.1; extra == "dbml"
|
|
66
64
|
Provides-Extra: parquet
|
|
67
65
|
Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
|
|
66
|
+
Provides-Extra: api
|
|
67
|
+
Requires-Dist: fastapi==0.115.6; extra == "api"
|
|
68
|
+
Requires-Dist: uvicorn==0.34.0; extra == "api"
|
|
69
|
+
Provides-Extra: custom
|
|
70
|
+
Requires-Dist: Jinja2>=3.1.5; extra == "custom"
|
|
68
71
|
Provides-Extra: all
|
|
69
|
-
Requires-Dist: datacontract-cli[bigquery,csv,databricks,dbml,dbt,iceberg,kafka,parquet,postgres,s3,snowflake,sqlserver,trino]; extra == "all"
|
|
72
|
+
Requires-Dist: datacontract-cli[api,bigquery,csv,custom,databricks,dbml,dbt,iceberg,kafka,parquet,postgres,s3,snowflake,sqlserver,trino]; extra == "all"
|
|
70
73
|
Provides-Extra: dev
|
|
71
74
|
Requires-Dist: datacontract-cli[all]; extra == "dev"
|
|
72
75
|
Requires-Dist: httpx==0.28.1; extra == "dev"
|
|
73
76
|
Requires-Dist: kafka-python; extra == "dev"
|
|
74
|
-
Requires-Dist: moto==5.0.
|
|
77
|
+
Requires-Dist: moto==5.0.27; extra == "dev"
|
|
75
78
|
Requires-Dist: pandas>=2.1.0; extra == "dev"
|
|
76
79
|
Requires-Dist: pre-commit<4.1.0,>=3.7.1; extra == "dev"
|
|
77
80
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -304,7 +307,7 @@ Commands
|
|
|
304
307
|
- [diff](#diff)
|
|
305
308
|
- [catalog](#catalog)
|
|
306
309
|
- [publish](#publish)
|
|
307
|
-
- [
|
|
310
|
+
- [api](#api)
|
|
308
311
|
|
|
309
312
|
### init
|
|
310
313
|
```
|
|
@@ -880,7 +883,7 @@ models:
|
|
|
880
883
|
│ vro-idl|sql|sql-query|html| │
|
|
881
884
|
│ go|bigquery|dbml|spark|sqla │
|
|
882
885
|
│ lchemy|data-caterer|dcs|mar │
|
|
883
|
-
│ kdown|iceberg]
|
|
886
|
+
│ kdown|iceberg|custom] │
|
|
884
887
|
│ --output PATH Specify the file path where │
|
|
885
888
|
│ the exported data will be │
|
|
886
889
|
│ saved. If no path is │
|
|
@@ -903,6 +906,9 @@ models:
|
|
|
903
906
|
│ --engine TEXT [engine] The engine used for │
|
|
904
907
|
│ great expection run. │
|
|
905
908
|
│ [default: None] │
|
|
909
|
+
│ --template PATH [custom] The file path of │
|
|
910
|
+
│ Jinja template. │
|
|
911
|
+
│ [default: None] │
|
|
906
912
|
│ --help Show this message and exit. │
|
|
907
913
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
908
914
|
╭─ RDF Options ────────────────────────────────────────────────────────────────╮
|
|
@@ -954,6 +960,7 @@ Available export options:
|
|
|
954
960
|
| `dcs` | Export to Data Contract Specification in YAML format | ✅ |
|
|
955
961
|
| `markdown` | Export to Markdown | ✅ |
|
|
956
962
|
| `iceberg` | Export to an Iceberg JSON Schema Definition | partial |
|
|
963
|
+
| `custom` | Export to Custom format with Jinja | ✅ |
|
|
957
964
|
| Missing something? | Please create an issue on GitHub | TBD |
|
|
958
965
|
|
|
959
966
|
|
|
@@ -1135,6 +1142,76 @@ to limit your contract export to a single model.
|
|
|
1135
1142
|
}
|
|
1136
1143
|
```
|
|
1137
1144
|
|
|
1145
|
+
#### Custom
|
|
1146
|
+
|
|
1147
|
+
The export function converts the data contract specification into the custom format with Jinja. You can specify the path to a Jinja template with the `--template` argument, allowing you to output files in any format.
|
|
1148
|
+
|
|
1149
|
+
```shell
|
|
1150
|
+
datacontract export --format custom --template template.txt datacontract.yaml
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
##### Jinja variables
|
|
1154
|
+
|
|
1155
|
+
You can directly use the Data Contract Specification as template variables.
|
|
1156
|
+
|
|
1157
|
+
```shell
|
|
1158
|
+
$ cat template.txt
|
|
1159
|
+
title: {{ data_contract.info.title }}
|
|
1160
|
+
|
|
1161
|
+
$ datacontract export --format custom --template template.txt datacontract.yaml
|
|
1162
|
+
title: Orders Latest
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
##### Example Jinja Templates
|
|
1166
|
+
|
|
1167
|
+
###### Customized dbt model
|
|
1168
|
+
|
|
1169
|
+
You can export the dbt models containing any logic.
|
|
1170
|
+
|
|
1171
|
+
Below is an example of a dbt staging layer that converts a field of `type: timestamp` to a `DATETIME` type with time zone conversion.
|
|
1172
|
+
|
|
1173
|
+
template.sql
|
|
1174
|
+
|
|
1175
|
+
{% raw %}
|
|
1176
|
+
```sql
|
|
1177
|
+
{%- for model_name, model in data_contract.models.items() %}
|
|
1178
|
+
{#- Export only the first model #}
|
|
1179
|
+
{%- if loop.first -%}
|
|
1180
|
+
SELECT
|
|
1181
|
+
{%- for field_name, field in model.fields.items() %}
|
|
1182
|
+
{%- if field.type == "timestamp" %}
|
|
1183
|
+
DATETIME({{ field_name }}, "Asia/Tokyo") AS {{ field_name }},
|
|
1184
|
+
{%- else %}
|
|
1185
|
+
{{ field_name }} AS {{ field_name }},
|
|
1186
|
+
{%- endif %}
|
|
1187
|
+
{%- endfor %}
|
|
1188
|
+
FROM
|
|
1189
|
+
{{ "{{" }} ref('{{ model_name }}') {{ "}}" }}
|
|
1190
|
+
{%- endif %}
|
|
1191
|
+
{%- endfor %}
|
|
1192
|
+
```
|
|
1193
|
+
{% endraw %}
|
|
1194
|
+
|
|
1195
|
+
command
|
|
1196
|
+
|
|
1197
|
+
```shell
|
|
1198
|
+
datacontract export --format custom --template template.sql --output output.sql datacontract.yaml
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
output.sql
|
|
1202
|
+
|
|
1203
|
+
```sql
|
|
1204
|
+
SELECT
|
|
1205
|
+
order_id AS order_id,
|
|
1206
|
+
DATETIME(order_timestamp, "Asia/Tokyo") AS order_timestamp,
|
|
1207
|
+
order_total AS order_total,
|
|
1208
|
+
customer_id AS customer_id,
|
|
1209
|
+
customer_email_address AS customer_email_address,
|
|
1210
|
+
DATETIME(processed_timestamp, "Asia/Tokyo") AS processed_timestamp,
|
|
1211
|
+
FROM
|
|
1212
|
+
{{ ref('orders') }}
|
|
1213
|
+
```
|
|
1214
|
+
|
|
1138
1215
|
### import
|
|
1139
1216
|
```
|
|
1140
1217
|
|
|
@@ -1539,18 +1616,23 @@ datacontract catalog --files "*.odcs.yaml"
|
|
|
1539
1616
|
|
|
1540
1617
|
```
|
|
1541
1618
|
|
|
1542
|
-
###
|
|
1619
|
+
### api
|
|
1543
1620
|
```
|
|
1544
|
-
|
|
1545
|
-
Usage: datacontract
|
|
1546
|
-
|
|
1547
|
-
Start the datacontract
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1621
|
+
|
|
1622
|
+
Usage: datacontract api [OPTIONS]
|
|
1623
|
+
|
|
1624
|
+
Start the datacontract CLI as server application with REST API.
|
|
1625
|
+
The OpenAPI documentation as Swagger UI is available on http://localhost:4242. You can execute the commands directly from the Swagger UI.
|
|
1626
|
+
To protect the API, you can set the environment variable DATACONTRACT_CLI_API_KEY to a secret API key. To authenticate, requests must include the header 'x-api-key' with the
|
|
1627
|
+
correct API key. This is highly recommended, as data contract tests may be subject to SQL injections or leak sensitive information.
|
|
1628
|
+
To connect to servers (such as a Snowflake data source), set the credentials as environment variables as documented in https://cli.datacontract.com/#test
|
|
1629
|
+
|
|
1630
|
+
╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
1631
|
+
│ --port INTEGER Bind socket to this port. [default: 4242] │
|
|
1632
|
+
│ --host TEXT Bind socket to this host. Hint: For running in docker, set it to 0.0.0.0 [default: 127.0.0.1] │
|
|
1633
|
+
│ --help Show this message and exit. │
|
|
1634
|
+
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
1635
|
+
|
|
1554
1636
|
|
|
1555
1637
|
```
|
|
1556
1638
|
|
|
@@ -1708,7 +1790,7 @@ class CustomExporter(Exporter):
|
|
|
1708
1790
|
|
|
1709
1791
|
|
|
1710
1792
|
# Register the new custom class into factory
|
|
1711
|
-
exporter_factory.register_exporter("
|
|
1793
|
+
exporter_factory.register_exporter("custom_exporter", CustomExporter)
|
|
1712
1794
|
|
|
1713
1795
|
|
|
1714
1796
|
if __name__ == "__main__":
|
|
@@ -1718,7 +1800,7 @@ if __name__ == "__main__":
|
|
|
1718
1800
|
)
|
|
1719
1801
|
# Call export
|
|
1720
1802
|
result = data_contract.export(
|
|
1721
|
-
export_format="
|
|
1803
|
+
export_format="custom_exporter", model="orders", server="production", custom_arg="my_custom_arg"
|
|
1722
1804
|
)
|
|
1723
1805
|
print(result)
|
|
1724
1806
|
|
|
@@ -221,7 +221,7 @@ Commands
|
|
|
221
221
|
- [diff](#diff)
|
|
222
222
|
- [catalog](#catalog)
|
|
223
223
|
- [publish](#publish)
|
|
224
|
-
- [
|
|
224
|
+
- [api](#api)
|
|
225
225
|
|
|
226
226
|
### init
|
|
227
227
|
```
|
|
@@ -797,7 +797,7 @@ models:
|
|
|
797
797
|
│ vro-idl|sql|sql-query|html| │
|
|
798
798
|
│ go|bigquery|dbml|spark|sqla │
|
|
799
799
|
│ lchemy|data-caterer|dcs|mar │
|
|
800
|
-
│ kdown|iceberg]
|
|
800
|
+
│ kdown|iceberg|custom] │
|
|
801
801
|
│ --output PATH Specify the file path where │
|
|
802
802
|
│ the exported data will be │
|
|
803
803
|
│ saved. If no path is │
|
|
@@ -820,6 +820,9 @@ models:
|
|
|
820
820
|
│ --engine TEXT [engine] The engine used for │
|
|
821
821
|
│ great expection run. │
|
|
822
822
|
│ [default: None] │
|
|
823
|
+
│ --template PATH [custom] The file path of │
|
|
824
|
+
│ Jinja template. │
|
|
825
|
+
│ [default: None] │
|
|
823
826
|
│ --help Show this message and exit. │
|
|
824
827
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
825
828
|
╭─ RDF Options ────────────────────────────────────────────────────────────────╮
|
|
@@ -871,6 +874,7 @@ Available export options:
|
|
|
871
874
|
| `dcs` | Export to Data Contract Specification in YAML format | ✅ |
|
|
872
875
|
| `markdown` | Export to Markdown | ✅ |
|
|
873
876
|
| `iceberg` | Export to an Iceberg JSON Schema Definition | partial |
|
|
877
|
+
| `custom` | Export to Custom format with Jinja | ✅ |
|
|
874
878
|
| Missing something? | Please create an issue on GitHub | TBD |
|
|
875
879
|
|
|
876
880
|
|
|
@@ -1052,6 +1056,76 @@ to limit your contract export to a single model.
|
|
|
1052
1056
|
}
|
|
1053
1057
|
```
|
|
1054
1058
|
|
|
1059
|
+
#### Custom
|
|
1060
|
+
|
|
1061
|
+
The export function converts the data contract specification into the custom format with Jinja. You can specify the path to a Jinja template with the `--template` argument, allowing you to output files in any format.
|
|
1062
|
+
|
|
1063
|
+
```shell
|
|
1064
|
+
datacontract export --format custom --template template.txt datacontract.yaml
|
|
1065
|
+
```
|
|
1066
|
+
|
|
1067
|
+
##### Jinja variables
|
|
1068
|
+
|
|
1069
|
+
You can directly use the Data Contract Specification as template variables.
|
|
1070
|
+
|
|
1071
|
+
```shell
|
|
1072
|
+
$ cat template.txt
|
|
1073
|
+
title: {{ data_contract.info.title }}
|
|
1074
|
+
|
|
1075
|
+
$ datacontract export --format custom --template template.txt datacontract.yaml
|
|
1076
|
+
title: Orders Latest
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
##### Example Jinja Templates
|
|
1080
|
+
|
|
1081
|
+
###### Customized dbt model
|
|
1082
|
+
|
|
1083
|
+
You can export the dbt models containing any logic.
|
|
1084
|
+
|
|
1085
|
+
Below is an example of a dbt staging layer that converts a field of `type: timestamp` to a `DATETIME` type with time zone conversion.
|
|
1086
|
+
|
|
1087
|
+
template.sql
|
|
1088
|
+
|
|
1089
|
+
{% raw %}
|
|
1090
|
+
```sql
|
|
1091
|
+
{%- for model_name, model in data_contract.models.items() %}
|
|
1092
|
+
{#- Export only the first model #}
|
|
1093
|
+
{%- if loop.first -%}
|
|
1094
|
+
SELECT
|
|
1095
|
+
{%- for field_name, field in model.fields.items() %}
|
|
1096
|
+
{%- if field.type == "timestamp" %}
|
|
1097
|
+
DATETIME({{ field_name }}, "Asia/Tokyo") AS {{ field_name }},
|
|
1098
|
+
{%- else %}
|
|
1099
|
+
{{ field_name }} AS {{ field_name }},
|
|
1100
|
+
{%- endif %}
|
|
1101
|
+
{%- endfor %}
|
|
1102
|
+
FROM
|
|
1103
|
+
{{ "{{" }} ref('{{ model_name }}') {{ "}}" }}
|
|
1104
|
+
{%- endif %}
|
|
1105
|
+
{%- endfor %}
|
|
1106
|
+
```
|
|
1107
|
+
{% endraw %}
|
|
1108
|
+
|
|
1109
|
+
command
|
|
1110
|
+
|
|
1111
|
+
```shell
|
|
1112
|
+
datacontract export --format custom --template template.sql --output output.sql datacontract.yaml
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
output.sql
|
|
1116
|
+
|
|
1117
|
+
```sql
|
|
1118
|
+
SELECT
|
|
1119
|
+
order_id AS order_id,
|
|
1120
|
+
DATETIME(order_timestamp, "Asia/Tokyo") AS order_timestamp,
|
|
1121
|
+
order_total AS order_total,
|
|
1122
|
+
customer_id AS customer_id,
|
|
1123
|
+
customer_email_address AS customer_email_address,
|
|
1124
|
+
DATETIME(processed_timestamp, "Asia/Tokyo") AS processed_timestamp,
|
|
1125
|
+
FROM
|
|
1126
|
+
{{ ref('orders') }}
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1055
1129
|
### import
|
|
1056
1130
|
```
|
|
1057
1131
|
|
|
@@ -1456,18 +1530,23 @@ datacontract catalog --files "*.odcs.yaml"
|
|
|
1456
1530
|
|
|
1457
1531
|
```
|
|
1458
1532
|
|
|
1459
|
-
###
|
|
1533
|
+
### api
|
|
1460
1534
|
```
|
|
1461
|
-
|
|
1462
|
-
Usage: datacontract
|
|
1463
|
-
|
|
1464
|
-
Start the datacontract
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1535
|
+
|
|
1536
|
+
Usage: datacontract api [OPTIONS]
|
|
1537
|
+
|
|
1538
|
+
Start the datacontract CLI as server application with REST API.
|
|
1539
|
+
The OpenAPI documentation as Swagger UI is available on http://localhost:4242. You can execute the commands directly from the Swagger UI.
|
|
1540
|
+
To protect the API, you can set the environment variable DATACONTRACT_CLI_API_KEY to a secret API key. To authenticate, requests must include the header 'x-api-key' with the
|
|
1541
|
+
correct API key. This is highly recommended, as data contract tests may be subject to SQL injections or leak sensitive information.
|
|
1542
|
+
To connect to servers (such as a Snowflake data source), set the credentials as environment variables as documented in https://cli.datacontract.com/#test
|
|
1543
|
+
|
|
1544
|
+
╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
1545
|
+
│ --port INTEGER Bind socket to this port. [default: 4242] │
|
|
1546
|
+
│ --host TEXT Bind socket to this host. Hint: For running in docker, set it to 0.0.0.0 [default: 127.0.0.1] │
|
|
1547
|
+
│ --help Show this message and exit. │
|
|
1548
|
+
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
1549
|
+
|
|
1471
1550
|
|
|
1472
1551
|
```
|
|
1473
1552
|
|
|
@@ -1625,7 +1704,7 @@ class CustomExporter(Exporter):
|
|
|
1625
1704
|
|
|
1626
1705
|
|
|
1627
1706
|
# Register the new custom class into factory
|
|
1628
|
-
exporter_factory.register_exporter("
|
|
1707
|
+
exporter_factory.register_exporter("custom_exporter", CustomExporter)
|
|
1629
1708
|
|
|
1630
1709
|
|
|
1631
1710
|
if __name__ == "__main__":
|
|
@@ -1635,7 +1714,7 @@ if __name__ == "__main__":
|
|
|
1635
1714
|
)
|
|
1636
1715
|
# Call export
|
|
1637
1716
|
result = data_contract.export(
|
|
1638
|
-
export_format="
|
|
1717
|
+
export_format="custom_exporter", model="orders", server="production", custom_arg="my_custom_arg"
|
|
1639
1718
|
)
|
|
1640
1719
|
print(result)
|
|
1641
1720
|
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import Annotated, Optional
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from fastapi import Body, Depends, FastAPI, HTTPException, Query, status
|
|
7
|
+
from fastapi.responses import PlainTextResponse
|
|
8
|
+
from fastapi.security.api_key import APIKeyHeader
|
|
9
|
+
|
|
10
|
+
from datacontract.data_contract import DataContract, ExportFormat
|
|
11
|
+
from datacontract.model.run import Run
|
|
12
|
+
|
|
13
|
+
DATA_CONTRACT_EXAMPLE_PAYLOAD = """dataContractSpecification: 1.1.0
|
|
14
|
+
id: urn:datacontract:checkout:orders-latest
|
|
15
|
+
info:
|
|
16
|
+
title: Orders Latest
|
|
17
|
+
version: 2.0.0
|
|
18
|
+
owner: Sales Team
|
|
19
|
+
servers:
|
|
20
|
+
production:
|
|
21
|
+
type: s3
|
|
22
|
+
location: s3://datacontract-example-orders-latest/v2/{model}/*.json
|
|
23
|
+
format: json
|
|
24
|
+
delimiter: new_line
|
|
25
|
+
models:
|
|
26
|
+
orders:
|
|
27
|
+
description: One record per order. Includes cancelled and deleted orders.
|
|
28
|
+
type: table
|
|
29
|
+
fields:
|
|
30
|
+
order_id:
|
|
31
|
+
type: string
|
|
32
|
+
primaryKey: true
|
|
33
|
+
order_timestamp:
|
|
34
|
+
description: The business timestamp in UTC when the order was successfully registered in the source system and the payment was successful.
|
|
35
|
+
type: timestamp
|
|
36
|
+
required: true
|
|
37
|
+
examples:
|
|
38
|
+
- "2024-09-09T08:30:00Z"
|
|
39
|
+
order_total:
|
|
40
|
+
description: Total amount the smallest monetary unit (e.g., cents).
|
|
41
|
+
type: long
|
|
42
|
+
required: true
|
|
43
|
+
examples:
|
|
44
|
+
- 9999
|
|
45
|
+
quality:
|
|
46
|
+
- type: sql
|
|
47
|
+
description: 95% of all order total values are expected to be between 10 and 499 EUR.
|
|
48
|
+
query: |
|
|
49
|
+
SELECT quantile_cont(order_total, 0.95) AS percentile_95
|
|
50
|
+
FROM orders
|
|
51
|
+
mustBeBetween: [1000, 99900]
|
|
52
|
+
customer_id:
|
|
53
|
+
description: Unique identifier for the customer.
|
|
54
|
+
type: text
|
|
55
|
+
minLength: 10
|
|
56
|
+
maxLength: 20
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
app = FastAPI(
|
|
60
|
+
docs_url="/",
|
|
61
|
+
title="Data Contract CLI API",
|
|
62
|
+
summary="You can use the API to test, export, and lint your data contracts.",
|
|
63
|
+
license_info={
|
|
64
|
+
"name": "MIT License",
|
|
65
|
+
"identifier": "MIT",
|
|
66
|
+
},
|
|
67
|
+
contact={"name": "Data Contract CLI", "url": "https://cli.datacontract.com/"},
|
|
68
|
+
openapi_tags=[
|
|
69
|
+
{
|
|
70
|
+
"name": "test",
|
|
71
|
+
"externalDocs": {
|
|
72
|
+
"description": "Documentation",
|
|
73
|
+
"url": "https://cli.datacontract.com/#test",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "lint",
|
|
78
|
+
"externalDocs": {
|
|
79
|
+
"description": "Documentation",
|
|
80
|
+
"url": "https://cli.datacontract.com/#lint",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "export",
|
|
85
|
+
"externalDocs": {
|
|
86
|
+
"description": "Documentation",
|
|
87
|
+
"url": "https://cli.datacontract.com/#export",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
api_key_header = APIKeyHeader(
|
|
94
|
+
name="x-api-key",
|
|
95
|
+
auto_error=False, # this makes authentication optional
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def check_api_key(api_key_header: str | None):
|
|
100
|
+
correct_api_key = os.getenv("DATACONTRACT_CLI_API_KEY")
|
|
101
|
+
if correct_api_key is None or correct_api_key == "":
|
|
102
|
+
logging.info("Environment variable DATACONTRACT_CLI_API_KEY is not set. Skip API key check.")
|
|
103
|
+
return
|
|
104
|
+
if api_key_header is None or api_key_header == "":
|
|
105
|
+
logging.info("The API key is missing.")
|
|
106
|
+
raise HTTPException(
|
|
107
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
108
|
+
detail="Missing API key. Use Header 'x-api-key' to provide the API key.",
|
|
109
|
+
)
|
|
110
|
+
if api_key_header != correct_api_key:
|
|
111
|
+
logging.info("The provided API key is not correct.")
|
|
112
|
+
raise HTTPException(
|
|
113
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
114
|
+
detail="The provided API key is not correct.",
|
|
115
|
+
)
|
|
116
|
+
logging.info("Request authenticated with API key.")
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@app.post(
|
|
121
|
+
"/test",
|
|
122
|
+
tags=["test"],
|
|
123
|
+
summary="Run data contract tests",
|
|
124
|
+
description="""
|
|
125
|
+
Run schema and quality tests. Data Contract CLI connects to the data sources configured in the server section.
|
|
126
|
+
This usually requires credentials to access the data sources.
|
|
127
|
+
Credentials must be provided via environment variables when running the web server.
|
|
128
|
+
POST the data contract YAML as payload.
|
|
129
|
+
""",
|
|
130
|
+
responses={
|
|
131
|
+
401: {
|
|
132
|
+
"description": "Unauthorized (when an environment variable DATACONTRACT_CLI_API_KEY is configured).",
|
|
133
|
+
"content": {
|
|
134
|
+
"application/json": {
|
|
135
|
+
"examples": {
|
|
136
|
+
"api_key_missing": {
|
|
137
|
+
"summary": "API key Missing",
|
|
138
|
+
"value": {"detail": "Missing API key. Use Header 'x-api-key' to provide the API key."},
|
|
139
|
+
},
|
|
140
|
+
"api_key_wrong": {
|
|
141
|
+
"summary": "API key Wrong",
|
|
142
|
+
"value": {"detail": "The provided API key is not correct."},
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
response_model_exclude_none=True,
|
|
150
|
+
response_model_exclude_unset=True,
|
|
151
|
+
)
|
|
152
|
+
async def test(
|
|
153
|
+
body: Annotated[
|
|
154
|
+
str,
|
|
155
|
+
Body(
|
|
156
|
+
title="Data Contract YAML",
|
|
157
|
+
media_type="application/yaml",
|
|
158
|
+
examples=[DATA_CONTRACT_EXAMPLE_PAYLOAD],
|
|
159
|
+
),
|
|
160
|
+
],
|
|
161
|
+
api_key: Annotated[str | None, Depends(api_key_header)] = None,
|
|
162
|
+
server: Annotated[
|
|
163
|
+
str | None,
|
|
164
|
+
Query(
|
|
165
|
+
example="production",
|
|
166
|
+
description="The server name to test. Optional, if there is only one server.",
|
|
167
|
+
),
|
|
168
|
+
] = None,
|
|
169
|
+
) -> Run:
|
|
170
|
+
check_api_key(api_key)
|
|
171
|
+
logging.info("Testing data contract...")
|
|
172
|
+
logging.info(body)
|
|
173
|
+
return DataContract(data_contract_str=body, server=server).test()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@app.post(
|
|
177
|
+
"/lint",
|
|
178
|
+
tags=["lint"],
|
|
179
|
+
summary="Validate that the datacontract.yaml is correctly formatted.",
|
|
180
|
+
description="""Validate that the datacontract.yaml is correctly formatted.""",
|
|
181
|
+
)
|
|
182
|
+
async def lint(
|
|
183
|
+
body: Annotated[
|
|
184
|
+
str,
|
|
185
|
+
Body(
|
|
186
|
+
title="Data Contract YAML",
|
|
187
|
+
media_type="application/yaml",
|
|
188
|
+
examples=[DATA_CONTRACT_EXAMPLE_PAYLOAD],
|
|
189
|
+
),
|
|
190
|
+
],
|
|
191
|
+
schema: Annotated[
|
|
192
|
+
str | None,
|
|
193
|
+
Query(
|
|
194
|
+
example="https://datacontract.com/datacontract.schema.json",
|
|
195
|
+
description="The schema to use for validation. This must be a URL.",
|
|
196
|
+
),
|
|
197
|
+
] = None,
|
|
198
|
+
):
|
|
199
|
+
data_contract = DataContract(data_contract_str=body, schema_location=schema)
|
|
200
|
+
lint_result = data_contract.lint()
|
|
201
|
+
return {"result": lint_result.result, "checks": lint_result.checks}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@app.post(
|
|
205
|
+
"/export",
|
|
206
|
+
tags=["export"],
|
|
207
|
+
summary="Convert data contract to a specific format.",
|
|
208
|
+
response_class=PlainTextResponse,
|
|
209
|
+
)
|
|
210
|
+
def export(
|
|
211
|
+
body: Annotated[
|
|
212
|
+
str,
|
|
213
|
+
Body(
|
|
214
|
+
title="Data Contract YAML",
|
|
215
|
+
media_type="application/yaml",
|
|
216
|
+
examples=[DATA_CONTRACT_EXAMPLE_PAYLOAD],
|
|
217
|
+
),
|
|
218
|
+
],
|
|
219
|
+
format: Annotated[ExportFormat, typer.Option(help="The export format.")],
|
|
220
|
+
server: Annotated[
|
|
221
|
+
str | None,
|
|
222
|
+
Query(
|
|
223
|
+
example="production",
|
|
224
|
+
description="The server name to export. Optional, if there is only one server.",
|
|
225
|
+
),
|
|
226
|
+
] = None,
|
|
227
|
+
model: Annotated[
|
|
228
|
+
str | None,
|
|
229
|
+
Query(
|
|
230
|
+
description="Use the key of the model in the data contract yaml file "
|
|
231
|
+
"to refer to a model, e.g., `orders`, or `all` for all "
|
|
232
|
+
"models (default).",
|
|
233
|
+
),
|
|
234
|
+
] = "all",
|
|
235
|
+
rdf_base: Annotated[
|
|
236
|
+
Optional[str],
|
|
237
|
+
typer.Option(help="[rdf] The base URI used to generate the RDF graph.", rich_help_panel="RDF Options"),
|
|
238
|
+
] = None,
|
|
239
|
+
sql_server_type: Annotated[
|
|
240
|
+
Optional[str],
|
|
241
|
+
Query(
|
|
242
|
+
description="[sql] The server type to determine the sql dialect. By default, it uses 'auto' to automatically detect the sql dialect via the specified servers in the data contract.",
|
|
243
|
+
),
|
|
244
|
+
] = None,
|
|
245
|
+
):
|
|
246
|
+
result = DataContract(data_contract_str=body, server=server).export(
|
|
247
|
+
export_format=format,
|
|
248
|
+
model=model,
|
|
249
|
+
rdf_base=rdf_base,
|
|
250
|
+
sql_server_type=sql_server_type,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return result
|