datacontract-cli 0.10.20__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.20/datacontract_cli.egg-info → datacontract_cli-0.10.21}/PKG-INFO +103 -22
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/README.md +94 -15
- datacontract_cli-0.10.20/datacontract/web.py → datacontract_cli-0.10.21/datacontract/api.py +55 -3
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/cli.py +27 -5
- datacontract_cli-0.10.21/datacontract/export/custom_converter.py +40 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/exporter.py +1 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/exporter_factory.py +4 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/urls.py +4 -4
- datacontract_cli-0.10.21/datacontract/model/data_contract_specification.py +327 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/run.py +18 -18
- {datacontract_cli-0.10.20 → 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.20 → 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.20 → datacontract_cli-0.10.21}/datacontract/templates/style/output.css +151 -152
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21/datacontract_cli.egg-info}/PKG-INFO +103 -22
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/SOURCES.txt +6 -3
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/requires.txt +10 -7
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/pyproject.toml +9 -5
- datacontract_cli-0.10.20/tests/test_web.py → datacontract_cli-0.10.21/tests/test_api.py +1 -1
- {datacontract_cli-0.10.20 → 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.20 → datacontract_cli-0.10.21}/tests/test_export_custom_exporter.py +2 -2
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_html.py +0 -11
- datacontract_cli-0.10.20/datacontract/model/data_contract_specification.py +0 -326
- datacontract_cli-0.10.20/datacontract/templates/partials/definition.html +0 -117
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/LICENSE +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/MANIFEST.in +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/__init__.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/breaking/breaking.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/breaking/breaking_rules.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/catalog/catalog.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/data_contract.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/__init__.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/check_soda_execute.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/bigquery.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/dask.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/databricks.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/duckdb.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/kafka.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/postgres.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/snowflake.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/sqlserver.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/trino.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/avro_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/avro_idl_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/bigquery_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/csv_type_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/data_caterer_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/dbml_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/dbt_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/go_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/great_expectations_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/html_export.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/iceberg_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/jsonschema_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/markdown_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/odcs_v2_exporter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/protobuf_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/pydantic_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/rdf_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sodacl_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/spark_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sql_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sqlalchemy_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/terraform_converter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/odcs_v2_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/odcs_v3_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/integration/datamesh_manager.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/files.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/lint.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/__init__.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/description_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/example_model_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/field_pattern_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/field_reference_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/notice_period_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/quality_schema_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/valid_constraints_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/breaking_change.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/py.typed +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/index.html +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/setup.cfg +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_breaking.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_changelog.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_cli.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_description_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_documentation_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_example_model_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_avro.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_go.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_odcs_v2.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_spark.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sql.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_terraform.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_field_constraint_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_field_pattern_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_field_reference_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_avro.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_csv.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_glue.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_odcs_v2.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_spark.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_sql.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_integration_datameshmanager.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_lint.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_notice_period_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_quality_schema_linter.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_resolve.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_spec_fields_field.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_spec_ref.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_delta.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_csv.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_formats_valid.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_inline.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_json.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_missing.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_quality.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-0.10.20 → 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
|
|
@@ -49,7 +49,7 @@ Provides-Extra: postgres
|
|
|
49
49
|
Requires-Dist: soda-core-postgres<3.4.0,>=3.3.20; extra == "postgres"
|
|
50
50
|
Provides-Extra: s3
|
|
51
51
|
Requires-Dist: s3fs==2024.12.0; extra == "s3"
|
|
52
|
-
Requires-Dist: aiobotocore<2.
|
|
52
|
+
Requires-Dist: aiobotocore<2.20.0,>=2.17.0; extra == "s3"
|
|
53
53
|
Provides-Extra: snowflake
|
|
54
54
|
Requires-Dist: snowflake-connector-python[pandas]<3.13,>=3.6; extra == "snowflake"
|
|
55
55
|
Requires-Dist: soda-core-snowflake<3.4.0,>=3.3.20; extra == "snowflake"
|
|
@@ -63,16 +63,18 @@ Provides-Extra: dbml
|
|
|
63
63
|
Requires-Dist: pydbml>=1.1.1; extra == "dbml"
|
|
64
64
|
Provides-Extra: parquet
|
|
65
65
|
Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
|
|
66
|
-
Provides-Extra:
|
|
67
|
-
Requires-Dist: fastapi==0.115.6; extra == "
|
|
68
|
-
Requires-Dist: uvicorn==0.34.0; extra == "
|
|
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"
|
|
69
71
|
Provides-Extra: all
|
|
70
|
-
Requires-Dist: datacontract-cli[bigquery,csv,databricks,dbml,dbt,iceberg,kafka,parquet,postgres,s3,snowflake,sqlserver,trino
|
|
72
|
+
Requires-Dist: datacontract-cli[api,bigquery,csv,custom,databricks,dbml,dbt,iceberg,kafka,parquet,postgres,s3,snowflake,sqlserver,trino]; extra == "all"
|
|
71
73
|
Provides-Extra: dev
|
|
72
74
|
Requires-Dist: datacontract-cli[all]; extra == "dev"
|
|
73
75
|
Requires-Dist: httpx==0.28.1; extra == "dev"
|
|
74
76
|
Requires-Dist: kafka-python; extra == "dev"
|
|
75
|
-
Requires-Dist: moto==5.0.
|
|
77
|
+
Requires-Dist: moto==5.0.27; extra == "dev"
|
|
76
78
|
Requires-Dist: pandas>=2.1.0; extra == "dev"
|
|
77
79
|
Requires-Dist: pre-commit<4.1.0,>=3.7.1; extra == "dev"
|
|
78
80
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -305,7 +307,7 @@ Commands
|
|
|
305
307
|
- [diff](#diff)
|
|
306
308
|
- [catalog](#catalog)
|
|
307
309
|
- [publish](#publish)
|
|
308
|
-
- [
|
|
310
|
+
- [api](#api)
|
|
309
311
|
|
|
310
312
|
### init
|
|
311
313
|
```
|
|
@@ -881,7 +883,7 @@ models:
|
|
|
881
883
|
│ vro-idl|sql|sql-query|html| │
|
|
882
884
|
│ go|bigquery|dbml|spark|sqla │
|
|
883
885
|
│ lchemy|data-caterer|dcs|mar │
|
|
884
|
-
│ kdown|iceberg]
|
|
886
|
+
│ kdown|iceberg|custom] │
|
|
885
887
|
│ --output PATH Specify the file path where │
|
|
886
888
|
│ the exported data will be │
|
|
887
889
|
│ saved. If no path is │
|
|
@@ -904,6 +906,9 @@ models:
|
|
|
904
906
|
│ --engine TEXT [engine] The engine used for │
|
|
905
907
|
│ great expection run. │
|
|
906
908
|
│ [default: None] │
|
|
909
|
+
│ --template PATH [custom] The file path of │
|
|
910
|
+
│ Jinja template. │
|
|
911
|
+
│ [default: None] │
|
|
907
912
|
│ --help Show this message and exit. │
|
|
908
913
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
909
914
|
╭─ RDF Options ────────────────────────────────────────────────────────────────╮
|
|
@@ -955,6 +960,7 @@ Available export options:
|
|
|
955
960
|
| `dcs` | Export to Data Contract Specification in YAML format | ✅ |
|
|
956
961
|
| `markdown` | Export to Markdown | ✅ |
|
|
957
962
|
| `iceberg` | Export to an Iceberg JSON Schema Definition | partial |
|
|
963
|
+
| `custom` | Export to Custom format with Jinja | ✅ |
|
|
958
964
|
| Missing something? | Please create an issue on GitHub | TBD |
|
|
959
965
|
|
|
960
966
|
|
|
@@ -1136,6 +1142,76 @@ to limit your contract export to a single model.
|
|
|
1136
1142
|
}
|
|
1137
1143
|
```
|
|
1138
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
|
+
|
|
1139
1215
|
### import
|
|
1140
1216
|
```
|
|
1141
1217
|
|
|
@@ -1540,18 +1616,23 @@ datacontract catalog --files "*.odcs.yaml"
|
|
|
1540
1616
|
|
|
1541
1617
|
```
|
|
1542
1618
|
|
|
1543
|
-
###
|
|
1619
|
+
### api
|
|
1544
1620
|
```
|
|
1545
|
-
|
|
1546
|
-
Usage: datacontract
|
|
1547
|
-
|
|
1548
|
-
Start the datacontract
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
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
|
+
|
|
1555
1636
|
|
|
1556
1637
|
```
|
|
1557
1638
|
|
|
@@ -1709,7 +1790,7 @@ class CustomExporter(Exporter):
|
|
|
1709
1790
|
|
|
1710
1791
|
|
|
1711
1792
|
# Register the new custom class into factory
|
|
1712
|
-
exporter_factory.register_exporter("
|
|
1793
|
+
exporter_factory.register_exporter("custom_exporter", CustomExporter)
|
|
1713
1794
|
|
|
1714
1795
|
|
|
1715
1796
|
if __name__ == "__main__":
|
|
@@ -1719,7 +1800,7 @@ if __name__ == "__main__":
|
|
|
1719
1800
|
)
|
|
1720
1801
|
# Call export
|
|
1721
1802
|
result = data_contract.export(
|
|
1722
|
-
export_format="
|
|
1803
|
+
export_format="custom_exporter", model="orders", server="production", custom_arg="my_custom_arg"
|
|
1723
1804
|
)
|
|
1724
1805
|
print(result)
|
|
1725
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
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
1
3
|
from typing import Annotated, Optional
|
|
2
4
|
|
|
3
5
|
import typer
|
|
4
|
-
from fastapi import Body, FastAPI, Query
|
|
6
|
+
from fastapi import Body, Depends, FastAPI, HTTPException, Query, status
|
|
5
7
|
from fastapi.responses import PlainTextResponse
|
|
8
|
+
from fastapi.security.api_key import APIKeyHeader
|
|
6
9
|
|
|
7
10
|
from datacontract.data_contract import DataContract, ExportFormat
|
|
8
11
|
from datacontract.model.run import Run
|
|
@@ -55,8 +58,8 @@ models:
|
|
|
55
58
|
|
|
56
59
|
app = FastAPI(
|
|
57
60
|
docs_url="/",
|
|
58
|
-
title="Data Contract API",
|
|
59
|
-
summary="API to
|
|
61
|
+
title="Data Contract CLI API",
|
|
62
|
+
summary="You can use the API to test, export, and lint your data contracts.",
|
|
60
63
|
license_info={
|
|
61
64
|
"name": "MIT License",
|
|
62
65
|
"identifier": "MIT",
|
|
@@ -87,6 +90,32 @@ app = FastAPI(
|
|
|
87
90
|
],
|
|
88
91
|
)
|
|
89
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
|
+
|
|
90
119
|
|
|
91
120
|
@app.post(
|
|
92
121
|
"/test",
|
|
@@ -98,6 +127,25 @@ app = FastAPI(
|
|
|
98
127
|
Credentials must be provided via environment variables when running the web server.
|
|
99
128
|
POST the data contract YAML as payload.
|
|
100
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
|
+
},
|
|
101
149
|
response_model_exclude_none=True,
|
|
102
150
|
response_model_exclude_unset=True,
|
|
103
151
|
)
|
|
@@ -110,6 +158,7 @@ async def test(
|
|
|
110
158
|
examples=[DATA_CONTRACT_EXAMPLE_PAYLOAD],
|
|
111
159
|
),
|
|
112
160
|
],
|
|
161
|
+
api_key: Annotated[str | None, Depends(api_key_header)] = None,
|
|
113
162
|
server: Annotated[
|
|
114
163
|
str | None,
|
|
115
164
|
Query(
|
|
@@ -118,6 +167,9 @@ async def test(
|
|
|
118
167
|
),
|
|
119
168
|
] = None,
|
|
120
169
|
) -> Run:
|
|
170
|
+
check_api_key(api_key)
|
|
171
|
+
logging.info("Testing data contract...")
|
|
172
|
+
logging.info(body)
|
|
121
173
|
return DataContract(data_contract_str=body, server=server).test()
|
|
122
174
|
|
|
123
175
|
|
|
@@ -196,6 +196,11 @@ def export(
|
|
|
196
196
|
Optional[str],
|
|
197
197
|
typer.Option(help="[engine] The engine used for great expection run."),
|
|
198
198
|
] = None,
|
|
199
|
+
# TODO: this should be a subcommand
|
|
200
|
+
template: Annotated[
|
|
201
|
+
Optional[Path],
|
|
202
|
+
typer.Option(help="[custom] The file path of Jinja template."),
|
|
203
|
+
] = None,
|
|
199
204
|
):
|
|
200
205
|
"""
|
|
201
206
|
Convert data contract to a specific format. Saves to file specified by `output` option if present, otherwise prints to stdout.
|
|
@@ -208,6 +213,7 @@ def export(
|
|
|
208
213
|
rdf_base=rdf_base,
|
|
209
214
|
sql_server_type=sql_server_type,
|
|
210
215
|
engine=engine,
|
|
216
|
+
template=template,
|
|
211
217
|
)
|
|
212
218
|
# Don't interpret console markup in output.
|
|
213
219
|
if output is None:
|
|
@@ -344,7 +350,7 @@ def catalog(
|
|
|
344
350
|
] = None,
|
|
345
351
|
):
|
|
346
352
|
"""
|
|
347
|
-
Create
|
|
353
|
+
Create a html catalog of data contracts.
|
|
348
354
|
"""
|
|
349
355
|
path = Path(output)
|
|
350
356
|
path.mkdir(parents=True, exist_ok=True)
|
|
@@ -433,16 +439,32 @@ def diff(
|
|
|
433
439
|
|
|
434
440
|
|
|
435
441
|
@app.command()
|
|
436
|
-
def
|
|
442
|
+
def api(
|
|
437
443
|
port: Annotated[int, typer.Option(help="Bind socket to this port.")] = 4242,
|
|
438
|
-
host: Annotated[
|
|
444
|
+
host: Annotated[
|
|
445
|
+
str, typer.Option(help="Bind socket to this host. Hint: For running in docker, set it to 0.0.0.0")
|
|
446
|
+
] = "127.0.0.1",
|
|
439
447
|
):
|
|
440
448
|
"""
|
|
441
|
-
Start the datacontract
|
|
449
|
+
Start the datacontract CLI as server application with REST API.
|
|
450
|
+
|
|
451
|
+
The OpenAPI documentation as Swagger UI is available on http://localhost:4242.
|
|
452
|
+
You can execute the commands directly from the Swagger UI.
|
|
453
|
+
|
|
454
|
+
To protect the API, you can set the environment variable DATACONTRACT_CLI_API_KEY to a secret API key.
|
|
455
|
+
To authenticate, requests must include the header 'x-api-key' with the correct API key.
|
|
456
|
+
This is highly recommended, as data contract tests may be subject to SQL injections or leak sensitive information.
|
|
457
|
+
|
|
458
|
+
To connect to servers (such as a Snowflake data source), set the credentials as environment variables as documented in
|
|
459
|
+
https://cli.datacontract.com/#test
|
|
442
460
|
"""
|
|
443
461
|
import uvicorn
|
|
462
|
+
from uvicorn.config import LOGGING_CONFIG
|
|
463
|
+
|
|
464
|
+
log_config = LOGGING_CONFIG
|
|
465
|
+
log_config["root"] = {"level": "INFO"}
|
|
444
466
|
|
|
445
|
-
uvicorn.run("datacontract.
|
|
467
|
+
uvicorn.run(app="datacontract.api:app", port=port, host=host, reload=True, log_config=LOGGING_CONFIG)
|
|
446
468
|
|
|
447
469
|
|
|
448
470
|
def _handle_result(run):
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from jinja2 import Environment, FileSystemLoader
|
|
4
|
+
|
|
5
|
+
from datacontract.export.exporter import Exporter
|
|
6
|
+
from datacontract.model.data_contract_specification import (
|
|
7
|
+
DataContractSpecification,
|
|
8
|
+
Model,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CustomExporter(Exporter):
|
|
13
|
+
"""Exporter implementation for converting data contracts to Markdown."""
|
|
14
|
+
|
|
15
|
+
def export(
|
|
16
|
+
self,
|
|
17
|
+
data_contract: DataContractSpecification,
|
|
18
|
+
model: Model,
|
|
19
|
+
server: str,
|
|
20
|
+
sql_server_type: str,
|
|
21
|
+
export_args: dict,
|
|
22
|
+
) -> str:
|
|
23
|
+
"""Exports a data contract to custom format with Jinja."""
|
|
24
|
+
template = export_args.get("template")
|
|
25
|
+
if template is None:
|
|
26
|
+
raise RuntimeError("Export to custom requires template argument.")
|
|
27
|
+
|
|
28
|
+
return to_custom(data_contract, template)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def to_custom(data_contract: DataContractSpecification, template_path: Path) -> str:
|
|
32
|
+
template = get_template(template_path)
|
|
33
|
+
rendered_sql = template.render(data_contract=data_contract)
|
|
34
|
+
return rendered_sql
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_template(path: Path):
|
|
38
|
+
abosolute_path = Path(path).resolve()
|
|
39
|
+
env = Environment(loader=FileSystemLoader(str(abosolute_path.parent)))
|
|
40
|
+
return env.get_template(path.name)
|
{datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/exporter_factory.py
RENAMED
|
@@ -206,3 +206,7 @@ exporter_factory.register_lazy_exporter(
|
|
|
206
206
|
exporter_factory.register_lazy_exporter(
|
|
207
207
|
name=ExportFormat.iceberg, module_path="datacontract.export.iceberg_converter", class_name="IcebergExporter"
|
|
208
208
|
)
|
|
209
|
+
|
|
210
|
+
exporter_factory.register_lazy_exporter(
|
|
211
|
+
name=ExportFormat.custom, module_path="datacontract.export.custom_converter", class_name="CustomExporter"
|
|
212
|
+
)
|
|
@@ -33,22 +33,22 @@ def _set_api_key(headers, url):
|
|
|
33
33
|
|
|
34
34
|
if hostname == "datamesh-manager.com" or hostname.endswith(".datamesh-manager.com"):
|
|
35
35
|
if datamesh_manager_api_key is None or datamesh_manager_api_key == "":
|
|
36
|
-
print("Error: Data Mesh Manager API
|
|
36
|
+
print("Error: Data Mesh Manager API key is not set. Set env variable DATAMESH_MANAGER_API_KEY.")
|
|
37
37
|
raise DataContractException(
|
|
38
38
|
type="lint",
|
|
39
39
|
name=f"Reading data contract from {url}",
|
|
40
|
-
reason="Error: Data Mesh Manager API
|
|
40
|
+
reason="Error: Data Mesh Manager API key is not set. Set env variable DATAMESH_MANAGER_API_KEY.",
|
|
41
41
|
engine="datacontract",
|
|
42
42
|
result="error",
|
|
43
43
|
)
|
|
44
44
|
headers["x-api-key"] = datamesh_manager_api_key
|
|
45
45
|
elif hostname == "datacontract-manager.com" or hostname.endswith(".datacontract-manager.com"):
|
|
46
46
|
if datacontract_manager_api_key is None or datacontract_manager_api_key == "":
|
|
47
|
-
print("Error: Data Contract Manager API
|
|
47
|
+
print("Error: Data Contract Manager API key is not set. Set env variable DATACONTRACT_MANAGER_API_KEY.")
|
|
48
48
|
raise DataContractException(
|
|
49
49
|
type="lint",
|
|
50
50
|
name=f"Reading data contract from {url}",
|
|
51
|
-
reason="Error: Data Contract Manager API
|
|
51
|
+
reason="Error: Data Contract Manager API key is not set. Set env variable DATACONTRACT_MANAGER_API_KEY.",
|
|
52
52
|
engine="datacontract",
|
|
53
53
|
result="error",
|
|
54
54
|
)
|