datacontract-cli 0.10.24__tar.gz → 0.10.25__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.24/datacontract_cli.egg-info → datacontract_cli-0.10.25}/PKG-INFO +33 -5
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/README.md +25 -1
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/api.py +3 -3
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/cli.py +1 -1
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/great_expectations_converter.py +49 -2
- datacontract_cli-0.10.25/datacontract/export/odcs_v3_exporter.py +359 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/spark_converter.py +1 -1
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/avro_importer.py +23 -23
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/csv_importer.py +2 -2
- datacontract_cli-0.10.25/datacontract/imports/excel_importer.py +850 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/importer.py +4 -2
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/importer_factory.py +5 -0
- datacontract_cli-0.10.25/datacontract/imports/odcs_v3_importer.py +415 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/protobuf_importer.py +0 -2
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/linters/description_linter.py +1 -3
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/linters/field_reference_linter.py +1 -2
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/linters/notice_period_linter.py +2 -2
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/linters/valid_constraints_linter.py +3 -3
- datacontract_cli-0.10.25/datacontract/model/data_contract_specification/__init__.py +1 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25/datacontract_cli.egg-info}/PKG-INFO +33 -5
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract_cli.egg-info/SOURCES.txt +3 -1
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract_cli.egg-info/requires.txt +7 -2
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/pyproject.toml +14 -4
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_great_expectations.py +103 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_odcs_v3.py +11 -3
- datacontract_cli-0.10.25/tests/test_import_excel.py +40 -0
- datacontract_cli-0.10.24/datacontract/export/odcs_v3_exporter.py +0 -334
- datacontract_cli-0.10.24/datacontract/imports/odcs_v3_importer.py +0 -358
- datacontract_cli-0.10.24/datacontract/model/data_contract_specification.py +0 -327
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/LICENSE +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/MANIFEST.in +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/__init__.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/breaking/breaking.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/breaking/breaking_change.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/breaking/breaking_rules.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/catalog/catalog.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/data_contract.py +0 -0
- {datacontract_cli-0.10.24/datacontract/output → datacontract_cli-0.10.25/datacontract/engines}/__init__.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/data_contract_checks.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/data_contract_test.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-0.10.24/datacontract/lint/linters → datacontract_cli-0.10.25/datacontract/engines/soda}/__init__.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/check_soda_execute.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/bigquery.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/databricks.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/duckdb_connection.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/kafka.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/postgres.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/snowflake.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/sqlserver.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/engines/soda/connections/trino.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/avro_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/avro_idl_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/bigquery_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/custom_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/data_caterer_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/dbml_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/dbt_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/go_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/html_export.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/iceberg_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/jsonschema_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/markdown_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/protobuf_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/pydantic_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/rdf_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/sodacl_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/sql_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/sqlalchemy_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/terraform_converter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/integration/datamesh_manager.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/files.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/lint.py +0 -0
- {datacontract_cli-0.10.24/datacontract/engines/soda → datacontract_cli-0.10.25/datacontract/lint/linters}/__init__.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/linters/field_pattern_linter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/model/run.py +0 -0
- {datacontract_cli-0.10.24/datacontract/engines → datacontract_cli-0.10.25/datacontract/output}/__init__.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/output/junit_test_results.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/output/test_results_writer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/py.typed +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/index.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/model_field.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/setup.cfg +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_api.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_breaking.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_catalog.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_changelog.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_cli.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_data_contract_checks.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_description_linter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_documentation_linter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_avro.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_custom.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_go.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_html.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_spark.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_sql.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_export_terraform.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_field_constraint_linter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_field_pattern_linter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_field_reference_linter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_avro.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_csv.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_glue.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_spark.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_integration_datameshmanager.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_lint.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_notice_period_linter.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_resolve.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_spec_fields_field.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_spec_ref.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_delta.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_output_junit.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_quality.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/tests/test_test_trino.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.25
|
|
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
|
+
License-Expression: MIT
|
|
6
7
|
Project-URL: Homepage, https://cli.datacontract.com
|
|
7
8
|
Project-URL: Issues, https://github.com/datacontract/datacontract-cli/issues
|
|
8
9
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
@@ -28,17 +28,21 @@ Requires-Dist: python-dotenv<2.0.0,>=1.0.0
|
|
|
28
28
|
Requires-Dist: boto3<2.0.0,>=1.34.41
|
|
29
29
|
Requires-Dist: Jinja2<4.0.0,>=3.1.5
|
|
30
30
|
Requires-Dist: jinja_partials<1.0.0,>=0.2.1
|
|
31
|
+
Requires-Dist: datacontract-specification<2.0.0,>=1.1.1
|
|
32
|
+
Requires-Dist: open-data-contract-standard<4.0.0,>=3.0.4
|
|
31
33
|
Provides-Extra: avro
|
|
32
34
|
Requires-Dist: avro==1.12.0; extra == "avro"
|
|
33
35
|
Provides-Extra: bigquery
|
|
34
36
|
Requires-Dist: soda-core-bigquery<3.6.0,>=3.3.20; extra == "bigquery"
|
|
35
37
|
Provides-Extra: csv
|
|
36
38
|
Requires-Dist: pandas>=2.0.0; extra == "csv"
|
|
39
|
+
Provides-Extra: excel
|
|
40
|
+
Requires-Dist: openpyxl<4.0.0,>=3.1.5; extra == "excel"
|
|
37
41
|
Provides-Extra: databricks
|
|
38
42
|
Requires-Dist: soda-core-spark-df<3.6.0,>=3.3.20; extra == "databricks"
|
|
39
43
|
Requires-Dist: soda-core-spark[databricks]<3.6.0,>=3.3.20; extra == "databricks"
|
|
40
44
|
Requires-Dist: databricks-sql-connector<4.1.0,>=3.7.0; extra == "databricks"
|
|
41
|
-
Requires-Dist: databricks-sdk<0.
|
|
45
|
+
Requires-Dist: databricks-sdk<0.51.0; extra == "databricks"
|
|
42
46
|
Provides-Extra: iceberg
|
|
43
47
|
Requires-Dist: pyiceberg==0.8.1; extra == "iceberg"
|
|
44
48
|
Provides-Extra: kafka
|
|
@@ -70,7 +74,7 @@ Requires-Dist: uvicorn==0.34.0; extra == "api"
|
|
|
70
74
|
Provides-Extra: protobuf
|
|
71
75
|
Requires-Dist: grpcio-tools>=1.53; extra == "protobuf"
|
|
72
76
|
Provides-Extra: all
|
|
73
|
-
Requires-Dist: datacontract-cli[api,bigquery,csv,databricks,dbml,dbt,iceberg,kafka,parquet,postgres,protobuf,rdf,s3,snowflake,sqlserver,trino]; extra == "all"
|
|
77
|
+
Requires-Dist: datacontract-cli[api,bigquery,csv,databricks,dbml,dbt,excel,iceberg,kafka,parquet,postgres,protobuf,rdf,s3,snowflake,sqlserver,trino]; extra == "all"
|
|
74
78
|
Provides-Extra: dev
|
|
75
79
|
Requires-Dist: datacontract-cli[all]; extra == "dev"
|
|
76
80
|
Requires-Dist: httpx==0.28.1; extra == "dev"
|
|
@@ -900,6 +904,29 @@ models:
|
|
|
900
904
|
| `DATACONTRACT_TRINO_PASSWORD` | `mysecretpassword` | Password |
|
|
901
905
|
|
|
902
906
|
|
|
907
|
+
#### Local
|
|
908
|
+
|
|
909
|
+
Data Contract CLI can test local files in parquet, json, csv, or delta format.
|
|
910
|
+
|
|
911
|
+
##### Example
|
|
912
|
+
|
|
913
|
+
datacontract.yaml
|
|
914
|
+
```yaml
|
|
915
|
+
servers:
|
|
916
|
+
local:
|
|
917
|
+
type: local
|
|
918
|
+
path: ./*.parquet
|
|
919
|
+
format: parquet
|
|
920
|
+
models:
|
|
921
|
+
my_table_1: # corresponds to a table
|
|
922
|
+
type: table
|
|
923
|
+
fields:
|
|
924
|
+
my_column_1: # corresponds to a column
|
|
925
|
+
type: varchar
|
|
926
|
+
my_column_2: # corresponds to a column
|
|
927
|
+
type: string
|
|
928
|
+
```
|
|
929
|
+
|
|
903
930
|
|
|
904
931
|
### export
|
|
905
932
|
```
|
|
@@ -1994,7 +2021,8 @@ pytest
|
|
|
1994
2021
|
```bash
|
|
1995
2022
|
# make sure uv is installed
|
|
1996
2023
|
uv python pin 3.11
|
|
1997
|
-
uv
|
|
2024
|
+
uv pip install -e '.[dev]'
|
|
2025
|
+
uv run ruff check
|
|
1998
2026
|
uv run pytest
|
|
1999
2027
|
```
|
|
2000
2028
|
|
|
@@ -812,6 +812,29 @@ models:
|
|
|
812
812
|
| `DATACONTRACT_TRINO_PASSWORD` | `mysecretpassword` | Password |
|
|
813
813
|
|
|
814
814
|
|
|
815
|
+
#### Local
|
|
816
|
+
|
|
817
|
+
Data Contract CLI can test local files in parquet, json, csv, or delta format.
|
|
818
|
+
|
|
819
|
+
##### Example
|
|
820
|
+
|
|
821
|
+
datacontract.yaml
|
|
822
|
+
```yaml
|
|
823
|
+
servers:
|
|
824
|
+
local:
|
|
825
|
+
type: local
|
|
826
|
+
path: ./*.parquet
|
|
827
|
+
format: parquet
|
|
828
|
+
models:
|
|
829
|
+
my_table_1: # corresponds to a table
|
|
830
|
+
type: table
|
|
831
|
+
fields:
|
|
832
|
+
my_column_1: # corresponds to a column
|
|
833
|
+
type: varchar
|
|
834
|
+
my_column_2: # corresponds to a column
|
|
835
|
+
type: string
|
|
836
|
+
```
|
|
837
|
+
|
|
815
838
|
|
|
816
839
|
### export
|
|
817
840
|
```
|
|
@@ -1906,7 +1929,8 @@ pytest
|
|
|
1906
1929
|
```bash
|
|
1907
1930
|
# make sure uv is installed
|
|
1908
1931
|
uv python pin 3.11
|
|
1909
|
-
uv
|
|
1932
|
+
uv pip install -e '.[dev]'
|
|
1933
|
+
uv run ruff check
|
|
1910
1934
|
uv run pytest
|
|
1911
1935
|
```
|
|
1912
1936
|
|
|
@@ -162,7 +162,7 @@ async def test(
|
|
|
162
162
|
server: Annotated[
|
|
163
163
|
str | None,
|
|
164
164
|
Query(
|
|
165
|
-
|
|
165
|
+
examples=["production"],
|
|
166
166
|
description="The server name to test. Optional, if there is only one server.",
|
|
167
167
|
),
|
|
168
168
|
] = None,
|
|
@@ -191,7 +191,7 @@ async def lint(
|
|
|
191
191
|
schema: Annotated[
|
|
192
192
|
str | None,
|
|
193
193
|
Query(
|
|
194
|
-
|
|
194
|
+
examples=["https://datacontract.com/datacontract.schema.json"],
|
|
195
195
|
description="The schema to use for validation. This must be a URL.",
|
|
196
196
|
),
|
|
197
197
|
] = None,
|
|
@@ -220,7 +220,7 @@ def export(
|
|
|
220
220
|
server: Annotated[
|
|
221
221
|
str | None,
|
|
222
222
|
Query(
|
|
223
|
-
|
|
223
|
+
examples=["production"],
|
|
224
224
|
description="The server name to export. Optional, if there is only one server.",
|
|
225
225
|
),
|
|
226
226
|
] = None,
|
|
@@ -244,7 +244,7 @@ def import_(
|
|
|
244
244
|
] = None,
|
|
245
245
|
source: Annotated[
|
|
246
246
|
Optional[str],
|
|
247
|
-
typer.Option(help="The path to the file
|
|
247
|
+
typer.Option(help="The path to the file that should be imported."),
|
|
248
248
|
] = None,
|
|
249
249
|
dialect: Annotated[
|
|
250
250
|
Optional[str],
|
|
@@ -19,6 +19,7 @@ from datacontract.export.spark_converter import to_spark_data_type
|
|
|
19
19
|
from datacontract.export.sql_type_converter import convert_to_sql_type
|
|
20
20
|
from datacontract.model.data_contract_specification import (
|
|
21
21
|
DataContractSpecification,
|
|
22
|
+
DeprecatedQuality,
|
|
22
23
|
Field,
|
|
23
24
|
Quality,
|
|
24
25
|
)
|
|
@@ -91,8 +92,14 @@ def to_great_expectations(
|
|
|
91
92
|
model_key=model_key, contract_version=data_contract_spec.info.version
|
|
92
93
|
)
|
|
93
94
|
model_value = data_contract_spec.models.get(model_key)
|
|
94
|
-
|
|
95
|
+
|
|
96
|
+
# Support for Deprecated Quality
|
|
97
|
+
quality_checks = get_deprecated_quality_checks(data_contract_spec.quality)
|
|
98
|
+
|
|
99
|
+
expectations.extend(get_quality_checks(model_value.quality))
|
|
100
|
+
|
|
95
101
|
expectations.extend(model_to_expectations(model_value.fields, engine, sql_server_type))
|
|
102
|
+
|
|
96
103
|
expectations.extend(checks_to_expectations(quality_checks, model_key))
|
|
97
104
|
model_expectation_suite = to_suite(expectations, expectation_suite_name)
|
|
98
105
|
|
|
@@ -135,6 +142,7 @@ def model_to_expectations(fields: Dict[str, Field], engine: str | None, sql_serv
|
|
|
135
142
|
add_column_order_exp(fields, expectations)
|
|
136
143
|
for field_name, field in fields.items():
|
|
137
144
|
add_field_expectations(field_name, field, expectations, engine, sql_server_type)
|
|
145
|
+
expectations.extend(get_quality_checks(field.quality, field_name))
|
|
138
146
|
return expectations
|
|
139
147
|
|
|
140
148
|
|
|
@@ -173,6 +181,8 @@ def add_field_expectations(
|
|
|
173
181
|
expectations.append(to_column_length_exp(field_name, field.minLength, field.maxLength))
|
|
174
182
|
if field.minimum is not None or field.maximum is not None:
|
|
175
183
|
expectations.append(to_column_min_max_exp(field_name, field.minimum, field.maximum))
|
|
184
|
+
if field.enum is not None and len(field.enum) != 0:
|
|
185
|
+
expectations.append(to_column_enum_exp(field_name, field.enum))
|
|
176
186
|
|
|
177
187
|
return expectations
|
|
178
188
|
|
|
@@ -266,7 +276,24 @@ def to_column_min_max_exp(field_name, minimum, maximum) -> Dict[str, Any]:
|
|
|
266
276
|
}
|
|
267
277
|
|
|
268
278
|
|
|
269
|
-
def
|
|
279
|
+
def to_column_enum_exp(field_name, enum_list: List[str]) -> Dict[str, Any]:
|
|
280
|
+
"""Creates a expect_column_values_to_be_in_set expectation.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
field_name (str): The name of the field.
|
|
284
|
+
enum_list (Set[str]): enum list of value.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
Dict[str, Any]: Column value in set expectation.
|
|
288
|
+
"""
|
|
289
|
+
return {
|
|
290
|
+
"expectation_type": "expect_column_values_to_be_in_set",
|
|
291
|
+
"kwargs": {"column": field_name, "value_set": enum_list},
|
|
292
|
+
"meta": {},
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def get_deprecated_quality_checks(quality: DeprecatedQuality) -> Dict[str, Any]:
|
|
270
297
|
"""Retrieves quality checks defined in a data contract.
|
|
271
298
|
|
|
272
299
|
Args:
|
|
@@ -288,6 +315,26 @@ def get_quality_checks(quality: Quality) -> Dict[str, Any]:
|
|
|
288
315
|
return quality_specification
|
|
289
316
|
|
|
290
317
|
|
|
318
|
+
def get_quality_checks(qualities: List[Quality], field_name: str | None = None) -> List[Dict[str, Any]]:
|
|
319
|
+
"""Retrieves quality checks defined in a data contract.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
qualities (List[Quality]): List of quality object from the model specification.
|
|
323
|
+
field_name (str | None): field name if the quality list is attached to a specific field
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
Dict[str, Any]: Dictionary of quality checks.
|
|
327
|
+
"""
|
|
328
|
+
quality_specification = []
|
|
329
|
+
for quality in qualities:
|
|
330
|
+
if quality is not None and quality.engine is not None and quality.engine.lower() == "great-expectations":
|
|
331
|
+
ge_expectation = quality.implementation
|
|
332
|
+
if field_name is not None:
|
|
333
|
+
ge_expectation["column"] = field_name
|
|
334
|
+
quality_specification.append(ge_expectation)
|
|
335
|
+
return quality_specification
|
|
336
|
+
|
|
337
|
+
|
|
291
338
|
def checks_to_expectations(quality_checks: Dict[str, Any], model_key: str) -> List[Dict[str, Any]]:
|
|
292
339
|
"""Converts quality checks to a list of expectations.
|
|
293
340
|
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
from typing import Dict
|
|
2
|
+
|
|
3
|
+
from open_data_contract_standard.model import (
|
|
4
|
+
CustomProperty,
|
|
5
|
+
DataQuality,
|
|
6
|
+
Description,
|
|
7
|
+
OpenDataContractStandard,
|
|
8
|
+
Role,
|
|
9
|
+
SchemaObject,
|
|
10
|
+
SchemaProperty,
|
|
11
|
+
Server,
|
|
12
|
+
ServiceLevelAgreementProperty,
|
|
13
|
+
Support,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from datacontract.export.exporter import Exporter
|
|
17
|
+
from datacontract.model.data_contract_specification import DataContractSpecification, Field, Model
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class OdcsV3Exporter(Exporter):
|
|
21
|
+
def export(self, data_contract, model, server, sql_server_type, export_args) -> dict:
|
|
22
|
+
return to_odcs_v3_yaml(data_contract)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def to_odcs_v3_yaml(data_contract_spec: DataContractSpecification) -> str:
|
|
26
|
+
result = OpenDataContractStandard(
|
|
27
|
+
apiVersion="v3.0.1",
|
|
28
|
+
kind="DataContract",
|
|
29
|
+
id=data_contract_spec.id,
|
|
30
|
+
name=data_contract_spec.info.title,
|
|
31
|
+
version=data_contract_spec.info.version,
|
|
32
|
+
status=to_status(data_contract_spec.info.status),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if data_contract_spec.terms is not None:
|
|
36
|
+
result.description = Description(
|
|
37
|
+
purpose=data_contract_spec.terms.description.strip()
|
|
38
|
+
if data_contract_spec.terms.description is not None
|
|
39
|
+
else None,
|
|
40
|
+
usage=data_contract_spec.terms.usage.strip() if data_contract_spec.terms.usage is not None else None,
|
|
41
|
+
limitations=data_contract_spec.terms.limitations.strip()
|
|
42
|
+
if data_contract_spec.terms.limitations is not None
|
|
43
|
+
else None,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
result.schema_ = []
|
|
47
|
+
for model_key, model_value in data_contract_spec.models.items():
|
|
48
|
+
odcs_schema = to_odcs_schema(model_key, model_value)
|
|
49
|
+
result.schema_.append(odcs_schema)
|
|
50
|
+
|
|
51
|
+
if data_contract_spec.servicelevels is not None:
|
|
52
|
+
slas = []
|
|
53
|
+
if data_contract_spec.servicelevels.availability is not None:
|
|
54
|
+
slas.append(
|
|
55
|
+
ServiceLevelAgreementProperty(
|
|
56
|
+
property="generalAvailability", value=data_contract_spec.servicelevels.availability.description
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
if data_contract_spec.servicelevels.retention is not None:
|
|
60
|
+
slas.append(
|
|
61
|
+
ServiceLevelAgreementProperty(
|
|
62
|
+
property="retention", value=data_contract_spec.servicelevels.retention.period
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if len(slas) > 0:
|
|
67
|
+
result.slaProperties = slas
|
|
68
|
+
|
|
69
|
+
if data_contract_spec.info.contact is not None:
|
|
70
|
+
support = []
|
|
71
|
+
if data_contract_spec.info.contact.email is not None:
|
|
72
|
+
support.append(Support(channel="email", url="mailto:" + data_contract_spec.info.contact.email))
|
|
73
|
+
if data_contract_spec.info.contact.url is not None:
|
|
74
|
+
support.append(Support(channel="other", url=data_contract_spec.info.contact.url))
|
|
75
|
+
if len(support) > 0:
|
|
76
|
+
result.support = support
|
|
77
|
+
|
|
78
|
+
if data_contract_spec.servers is not None and len(data_contract_spec.servers) > 0:
|
|
79
|
+
servers = []
|
|
80
|
+
|
|
81
|
+
for server_key, server_value in data_contract_spec.servers.items():
|
|
82
|
+
server = Server(server=server_key, type=server_value.type or "")
|
|
83
|
+
|
|
84
|
+
# Set all the attributes that are not None
|
|
85
|
+
if server_value.environment is not None:
|
|
86
|
+
server.environment = server_value.environment
|
|
87
|
+
if server_value.account is not None:
|
|
88
|
+
server.account = server_value.account
|
|
89
|
+
if server_value.database is not None:
|
|
90
|
+
server.database = server_value.database
|
|
91
|
+
if server_value.schema_ is not None:
|
|
92
|
+
server.schema_ = server_value.schema_
|
|
93
|
+
if server_value.format is not None:
|
|
94
|
+
server.format = server_value.format
|
|
95
|
+
if server_value.project is not None:
|
|
96
|
+
server.project = server_value.project
|
|
97
|
+
if server_value.dataset is not None:
|
|
98
|
+
server.dataset = server_value.dataset
|
|
99
|
+
if server_value.path is not None:
|
|
100
|
+
server.path = server_value.path
|
|
101
|
+
if server_value.delimiter is not None:
|
|
102
|
+
server.delimiter = server_value.delimiter
|
|
103
|
+
if server_value.endpointUrl is not None:
|
|
104
|
+
server.endpointUrl = server_value.endpointUrl
|
|
105
|
+
if server_value.location is not None:
|
|
106
|
+
server.location = server_value.location
|
|
107
|
+
if server_value.host is not None:
|
|
108
|
+
server.host = server_value.host
|
|
109
|
+
if server_value.port is not None:
|
|
110
|
+
server.port = server_value.port
|
|
111
|
+
if server_value.catalog is not None:
|
|
112
|
+
server.catalog = server_value.catalog
|
|
113
|
+
if server_value.topic is not None:
|
|
114
|
+
server.topic = server_value.topic
|
|
115
|
+
if server_value.http_path is not None:
|
|
116
|
+
server.http_path = server_value.http_path
|
|
117
|
+
if server_value.token is not None:
|
|
118
|
+
server.token = server_value.token
|
|
119
|
+
if server_value.driver is not None:
|
|
120
|
+
server.driver = server_value.driver
|
|
121
|
+
|
|
122
|
+
if server_value.roles is not None:
|
|
123
|
+
server.roles = [Role(role=role.name, description=role.description) for role in server_value.roles]
|
|
124
|
+
|
|
125
|
+
servers.append(server)
|
|
126
|
+
|
|
127
|
+
if len(servers) > 0:
|
|
128
|
+
result.servers = servers
|
|
129
|
+
|
|
130
|
+
custom_properties = []
|
|
131
|
+
if data_contract_spec.info.owner is not None:
|
|
132
|
+
custom_properties.append(CustomProperty(property="owner", value=data_contract_spec.info.owner))
|
|
133
|
+
if data_contract_spec.info.model_extra is not None:
|
|
134
|
+
for key, value in data_contract_spec.info.model_extra.items():
|
|
135
|
+
custom_properties.append(CustomProperty(property=key, value=value))
|
|
136
|
+
|
|
137
|
+
if len(custom_properties) > 0:
|
|
138
|
+
result.customProperties = custom_properties
|
|
139
|
+
|
|
140
|
+
return result.to_yaml()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def to_odcs_schema(model_key, model_value: Model) -> SchemaObject:
|
|
144
|
+
schema_obj = SchemaObject(
|
|
145
|
+
name=model_key, physicalName=model_key, logicalType="object", physicalType=model_value.type
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if model_value.description is not None:
|
|
149
|
+
schema_obj.description = model_value.description
|
|
150
|
+
|
|
151
|
+
properties = to_properties(model_value.fields)
|
|
152
|
+
if properties:
|
|
153
|
+
schema_obj.properties = properties
|
|
154
|
+
|
|
155
|
+
model_quality = to_odcs_quality_list(model_value.quality)
|
|
156
|
+
if len(model_quality) > 0:
|
|
157
|
+
schema_obj.quality = model_quality
|
|
158
|
+
|
|
159
|
+
custom_properties = []
|
|
160
|
+
if model_value.model_extra is not None:
|
|
161
|
+
for key, value in model_value.model_extra.items():
|
|
162
|
+
custom_properties.append(CustomProperty(property=key, value=value))
|
|
163
|
+
|
|
164
|
+
if len(custom_properties) > 0:
|
|
165
|
+
schema_obj.customProperties = custom_properties
|
|
166
|
+
|
|
167
|
+
return schema_obj
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def to_properties(fields: Dict[str, Field]) -> list:
|
|
171
|
+
properties = []
|
|
172
|
+
for field_name, field in fields.items():
|
|
173
|
+
property = to_property(field_name, field)
|
|
174
|
+
properties.append(property)
|
|
175
|
+
return properties
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def to_logical_type(type: str) -> str | None:
|
|
179
|
+
if type is None:
|
|
180
|
+
return None
|
|
181
|
+
if type.lower() in ["string", "varchar", "text"]:
|
|
182
|
+
return "string"
|
|
183
|
+
if type.lower() in ["timestamp", "timestamp_tz"]:
|
|
184
|
+
return "date"
|
|
185
|
+
if type.lower() in ["timestamp_ntz"]:
|
|
186
|
+
return "date"
|
|
187
|
+
if type.lower() in ["date"]:
|
|
188
|
+
return "date"
|
|
189
|
+
if type.lower() in ["time"]:
|
|
190
|
+
return "string"
|
|
191
|
+
if type.lower() in ["number", "decimal", "numeric"]:
|
|
192
|
+
return "number"
|
|
193
|
+
if type.lower() in ["float", "double"]:
|
|
194
|
+
return "number"
|
|
195
|
+
if type.lower() in ["integer", "int", "long", "bigint"]:
|
|
196
|
+
return "integer"
|
|
197
|
+
if type.lower() in ["boolean"]:
|
|
198
|
+
return "boolean"
|
|
199
|
+
if type.lower() in ["object", "record", "struct"]:
|
|
200
|
+
return "object"
|
|
201
|
+
if type.lower() in ["bytes"]:
|
|
202
|
+
return "array"
|
|
203
|
+
if type.lower() in ["array"]:
|
|
204
|
+
return "array"
|
|
205
|
+
if type.lower() in ["null"]:
|
|
206
|
+
return None
|
|
207
|
+
return None
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def to_physical_type(type: str) -> str | None:
|
|
211
|
+
return type
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def to_property(field_name: str, field: Field) -> SchemaProperty:
|
|
215
|
+
property = SchemaProperty(name=field_name)
|
|
216
|
+
|
|
217
|
+
if field.fields:
|
|
218
|
+
properties = []
|
|
219
|
+
for field_name_, field_ in field.fields.items():
|
|
220
|
+
property_ = to_property(field_name_, field_)
|
|
221
|
+
properties.append(property_)
|
|
222
|
+
property.properties = properties
|
|
223
|
+
|
|
224
|
+
if field.items:
|
|
225
|
+
items = to_property(field_name, field.items)
|
|
226
|
+
items.name = None # Clear the name for items
|
|
227
|
+
property.items = items
|
|
228
|
+
|
|
229
|
+
if field.title is not None:
|
|
230
|
+
property.businessName = field.title
|
|
231
|
+
|
|
232
|
+
if field.type is not None:
|
|
233
|
+
property.logicalType = to_logical_type(field.type)
|
|
234
|
+
property.physicalType = to_physical_type(field.type)
|
|
235
|
+
|
|
236
|
+
if field.description is not None:
|
|
237
|
+
property.description = field.description
|
|
238
|
+
|
|
239
|
+
if field.required is not None:
|
|
240
|
+
property.required = field.required
|
|
241
|
+
|
|
242
|
+
if field.unique is not None:
|
|
243
|
+
property.unique = field.unique
|
|
244
|
+
|
|
245
|
+
if field.classification is not None:
|
|
246
|
+
property.classification = field.classification
|
|
247
|
+
|
|
248
|
+
if field.examples is not None:
|
|
249
|
+
property.examples = field.examples.copy()
|
|
250
|
+
|
|
251
|
+
if field.example is not None:
|
|
252
|
+
property.examples = [field.example]
|
|
253
|
+
|
|
254
|
+
if field.primaryKey is not None and field.primaryKey:
|
|
255
|
+
property.primaryKey = field.primaryKey
|
|
256
|
+
property.primaryKeyPosition = 1
|
|
257
|
+
|
|
258
|
+
if field.primary is not None and field.primary:
|
|
259
|
+
property.primaryKey = field.primary
|
|
260
|
+
property.primaryKeyPosition = 1
|
|
261
|
+
|
|
262
|
+
custom_properties = []
|
|
263
|
+
if field.model_extra is not None:
|
|
264
|
+
for key, value in field.model_extra.items():
|
|
265
|
+
custom_properties.append(CustomProperty(property=key, value=value))
|
|
266
|
+
|
|
267
|
+
if field.pii is not None:
|
|
268
|
+
custom_properties.append(CustomProperty(property="pii", value=field.pii))
|
|
269
|
+
|
|
270
|
+
if len(custom_properties) > 0:
|
|
271
|
+
property.customProperties = custom_properties
|
|
272
|
+
|
|
273
|
+
if field.tags is not None and len(field.tags) > 0:
|
|
274
|
+
property.tags = field.tags
|
|
275
|
+
|
|
276
|
+
logical_type_options = {}
|
|
277
|
+
if field.minLength is not None:
|
|
278
|
+
logical_type_options["minLength"] = field.minLength
|
|
279
|
+
if field.maxLength is not None:
|
|
280
|
+
logical_type_options["maxLength"] = field.maxLength
|
|
281
|
+
if field.pattern is not None:
|
|
282
|
+
logical_type_options["pattern"] = field.pattern
|
|
283
|
+
if field.minimum is not None:
|
|
284
|
+
logical_type_options["minimum"] = field.minimum
|
|
285
|
+
if field.maximum is not None:
|
|
286
|
+
logical_type_options["maximum"] = field.maximum
|
|
287
|
+
if field.exclusiveMinimum is not None:
|
|
288
|
+
logical_type_options["exclusiveMinimum"] = field.exclusiveMinimum
|
|
289
|
+
if field.exclusiveMaximum is not None:
|
|
290
|
+
logical_type_options["exclusiveMaximum"] = field.exclusiveMaximum
|
|
291
|
+
|
|
292
|
+
if logical_type_options:
|
|
293
|
+
property.logicalTypeOptions = logical_type_options
|
|
294
|
+
|
|
295
|
+
if field.quality is not None:
|
|
296
|
+
quality_list = field.quality
|
|
297
|
+
quality_property = to_odcs_quality_list(quality_list)
|
|
298
|
+
if len(quality_property) > 0:
|
|
299
|
+
property.quality = quality_property
|
|
300
|
+
|
|
301
|
+
return property
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def to_odcs_quality_list(quality_list):
|
|
305
|
+
quality_property = []
|
|
306
|
+
for quality in quality_list:
|
|
307
|
+
quality_property.append(to_odcs_quality(quality))
|
|
308
|
+
return quality_property
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def to_odcs_quality(quality):
|
|
312
|
+
quality_obj = DataQuality(type=quality.type)
|
|
313
|
+
|
|
314
|
+
if quality.description is not None:
|
|
315
|
+
quality_obj.description = quality.description
|
|
316
|
+
if quality.query is not None:
|
|
317
|
+
quality_obj.query = quality.query
|
|
318
|
+
# dialect is not supported in v3.0.0
|
|
319
|
+
if quality.mustBe is not None:
|
|
320
|
+
quality_obj.mustBe = quality.mustBe
|
|
321
|
+
if quality.mustNotBe is not None:
|
|
322
|
+
quality_obj.mustNotBe = quality.mustNotBe
|
|
323
|
+
if quality.mustBeGreaterThan is not None:
|
|
324
|
+
quality_obj.mustBeGreaterThan = quality.mustBeGreaterThan
|
|
325
|
+
if quality.mustBeGreaterThanOrEqualTo is not None:
|
|
326
|
+
quality_obj.mustBeGreaterOrEqualTo = quality.mustBeGreaterThanOrEqualTo
|
|
327
|
+
if quality.mustBeLessThan is not None:
|
|
328
|
+
quality_obj.mustBeLessThan = quality.mustBeLessThan
|
|
329
|
+
if quality.mustBeLessThanOrEqualTo is not None:
|
|
330
|
+
quality_obj.mustBeLessOrEqualTo = quality.mustBeLessThanOrEqualTo
|
|
331
|
+
if quality.mustBeBetween is not None:
|
|
332
|
+
quality_obj.mustBeBetween = quality.mustBeBetween
|
|
333
|
+
if quality.mustNotBeBetween is not None:
|
|
334
|
+
quality_obj.mustNotBeBetween = quality.mustNotBeBetween
|
|
335
|
+
if quality.engine is not None:
|
|
336
|
+
quality_obj.engine = quality.engine
|
|
337
|
+
if quality.implementation is not None:
|
|
338
|
+
quality_obj.implementation = quality.implementation
|
|
339
|
+
|
|
340
|
+
return quality_obj
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def to_status(status):
|
|
344
|
+
"""Convert the data contract status to ODCS v3 format."""
|
|
345
|
+
if status is None:
|
|
346
|
+
return "draft" # Default to draft if no status is provided
|
|
347
|
+
|
|
348
|
+
# Valid status values according to ODCS v3.0.1 spec
|
|
349
|
+
valid_statuses = ["proposed", "draft", "active", "deprecated", "retired"]
|
|
350
|
+
|
|
351
|
+
# Convert to lowercase for comparison
|
|
352
|
+
status_lower = status.lower()
|
|
353
|
+
|
|
354
|
+
# If status is already valid, return it as is
|
|
355
|
+
if status_lower in valid_statuses:
|
|
356
|
+
return status_lower
|
|
357
|
+
|
|
358
|
+
# Default to "draft" for any non-standard status
|
|
359
|
+
return "draft"
|
{datacontract_cli-0.10.24 → datacontract_cli-0.10.25}/datacontract/export/spark_converter.py
RENAMED
|
@@ -175,7 +175,7 @@ def print_schema(dtype: types.DataType) -> str:
|
|
|
175
175
|
Returns:
|
|
176
176
|
str: The indented text.
|
|
177
177
|
"""
|
|
178
|
-
return "\n".join([f'
|
|
178
|
+
return "\n".join([f"{' ' * level}{line}" for line in text.split("\n")])
|
|
179
179
|
|
|
180
180
|
def repr_column(column: types.StructField) -> str:
|
|
181
181
|
"""
|