datacontract-cli 1.0.12__tar.gz → 1.0.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {datacontract_cli-1.0.12/datacontract_cli.egg-info → datacontract_cli-1.0.13}/PKG-INFO +4 -4
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/check_spec.py +1 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/create_checks.py +67 -3
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/physical_type_match.py +29 -2
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/type_normalize.py +66 -21
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/ibis_check_execute.py +81 -2
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/snowflake_structured_types.py +15 -11
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13/datacontract_cli.egg-info}/PKG-INFO +4 -4
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract_cli.egg-info/SOURCES.txt +1 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract_cli.egg-info/requires.txt +3 -3
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/pyproject.toml +4 -4
- datacontract_cli-1.0.13/tests/test_create_checks_nested_type.py +438 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_physical_type_match.py +35 -2
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_snowflake_structured_types.py +15 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/LICENSE +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/MANIFEST.in +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/README.md +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/api.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/catalog/catalog.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/changelog/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/changelog/changelog.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/changelog/normalize.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/cli.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_api.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_catalog.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_changelog.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_ci.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_dbt.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_edit.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_export.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_import.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_init.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_lint.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_publish.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/command_test.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/data_contract.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/VERSION +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/abap-Bs8kvjsq.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/apex-Dspwrl5m.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/azcli-k1BiOau1.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/bat-BIP72KWc.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/bicep-VhQeYhS3.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/cameligo-DnuAXtHg.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/clojure-BAuDPsal.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/coffee-BV06qSnj.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/cpp-Cz8Jeyrf.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/csharp-F6hhlXFb.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/csp-KzlEHCyI.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/css-e4FKntZ3.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/cssMode-BNkTa2xp.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/cypher-CpvDGKRr.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/dart-DdHeFWR0.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/datacontract-editor.css +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/datacontract-editor.es.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/dockerfile-aoNXDcio.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/ecl-C4Q0DYuA.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/elixir-C9X42b0T.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/flow9-Bff42pfB.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/freemarker2-Dyfzmb5A.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/fsharp-C6vPAsHG.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/go-DEr8zx9f.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/graphql-BiNBBRFh.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/handlebars-BtDNI-uC.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/hcl-2T9lKuFg.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/html-Cn4TGw_o.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/htmlMode-Bf84vbo2.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/index.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/ini-CZGtssYM.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/java-B260NeH3.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/javascript-B86Kac07.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/jsonMode-Ckgg5lAE.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/julia-kuNLM9c5.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/kotlin-Bz6kAefA.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/less-AZUtS89I.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/lexon-BcmgnyRb.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/liquid-D0NPwuu_.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/lua-Dz1RbATg.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/m3-CIMooLFn.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/markdown-C1BsCK9P.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/mdx-QFRSBtVQ.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/mips-BovsnfLQ.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/monaco-4.7.0.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/msdax-CiRB2ZB-.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/mysql-BwdpPE19.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/objective-c-D4nfHfso.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/odcs.svg +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/pascal--j5-PYtz.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/pascaligo-C7TcJxNL.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/perl-BzEWqUb5.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/pgsql-B_KZ0mGX.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/php-A19QHzQV.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/pla-COeKY1hA.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/postiats-BfMp7zJL.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/powerquery-B0TS_5Gb.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/powershell-5jSbKdYB.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/protobuf-YgnOutn3.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/pug-DLej6kn5.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/python-C8RW9B6A.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/qsharp-AhjqtSHB.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/r-D-F4P80w.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/razor-CLZqdY_r.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/redis-hwwIlMnV.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/redshift-Bcm_kjEG.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/restructuredtext-CrdzfPP-.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/ruby-QC2UNm1s.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/rust-5aqiQ3L5.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/sb-B1g1ZfLJ.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/scala-C2U4R5Gb.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/scheme-DeFRbslr.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/scss-RSTCiCmI.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/shell-BpF-iNu8.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/solidity-C00r2mbQ.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/sophia-DVW5ZKDB.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/sparql-B0nmpxeX.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/sql-CJwKPERn.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/st-DPlKG5DT.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/swift-YZBAbVHV.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/systemverilog-CDQSaH63.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/tcl-Dlu8sp6Q.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/tsMode-yleMwhPq.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/twig-C5TO7-kw.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/typescript-CJBeebKU.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/typespec-BsmjDEu7.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/vb-ChHvIDrk.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/wgsl-XEp1ju8c.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/xml-vC-NMVX1.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/editor_assets/yaml-Dlf2VF-T.js +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/data_contract_test.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/connections/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/connections/connect.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/connections/duckdb_connection.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/connections/kafka.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/connections/redshift_patch.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/dtype_category.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/native_type.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/avro_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/avro_idl_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/bigquery_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/data_caterer_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/dbml_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/dbt_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/dqx_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/excel_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/great_expectations_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/html_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/iceberg_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/markdown_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/mermaid_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/odcs_export_helper.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/protobuf_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/pydantic_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/rdf_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/sodacl_check_builder.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/sql_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/export/sqlalchemy_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/dcs_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/excel_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/json_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/odcs_helper.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/powerbi_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/snowflake_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/integration/dbt_sync.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/integration/dbt_test_mapping.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/lint/files.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/model/changelog.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/model/run.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/model/server.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/output/__init__.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/output/ci_output.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/output/json_test_results.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/output/junit_test_results.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/output/test_results_writer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/output/text_changelog_results.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/py.typed +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/odcs-3.1.0.init.yaml +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/index.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/model_field.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/setup.cfg +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_api.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_catalog.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_changelog.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_changelog_engine.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_changelog_normalize.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_changelog_output_text.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_ci_output.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_cli.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_connect_databricks.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_connect_sqlserver.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_connect_trino.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_create_checks_physical_type.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_data_contract.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_data_contract_checks.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_dbt_sync.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_dbt_test_mapping.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_description_linter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_dtype_category.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_edit.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_avro.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_custom.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_custom_model.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_excel.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_go.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_html.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_spark.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_sql.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_sql_clickhouse.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_ibis_mssql_pattern.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_ibis_oracle_schema.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_avro.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_csv.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_excel.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_glue.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_json.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_powerbi.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_snowflake.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_spark.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_sql_oracle.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_sql_snowflake.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_lint.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_oracle_patch.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_redshift_patch.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_require_env.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_resolve.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_resolve_definitions.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_sql_type_converter_physicaltype.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_api.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_azure_blob_file.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_checks_filter.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_delta.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_diagnostics.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_failed_samples.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_mysql.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_oracle_xe.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_output_json.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_output_junit.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_quality.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_quality_local_fallback.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_quality_percent_severity.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_redshift.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_schema_evolution.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_server_not_found.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_soda_connection_error.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_test_trino.py +0 -0
- {datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/tests/test_type_normalize.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.13
|
|
4
4
|
Summary: The datacontract CLI is an open source command-line tool for working with Data Contracts. It uses data contract YAML files to lint the data contract, connect to data sources and execute schema and quality tests, detect breaking changes, and export to different formats. The tool is written in Python. It can be used as a standalone CLI tool, in a CI/CD pipeline, or directly as a Python library.
|
|
5
5
|
Author-email: Jochen Christ <jochen.christ@innoq.com>, Stefan Negele <stefan.negele@innoq.com>, Simon Harrer <simon.harrer@innoq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -15,7 +15,7 @@ Requires-Dist: typer<0.27,>=0.18.0
|
|
|
15
15
|
Requires-Dist: click<9.0.0,>=8.1.0
|
|
16
16
|
Requires-Dist: pydantic<2.14.0,>=2.8.2
|
|
17
17
|
Requires-Dist: pyyaml~=6.0.1
|
|
18
|
-
Requires-Dist: ruamel.yaml<0.
|
|
18
|
+
Requires-Dist: ruamel.yaml<0.20,>=0.17
|
|
19
19
|
Requires-Dist: requests<2.35,>=2.31
|
|
20
20
|
Requires-Dist: truststore<1.0,>=0.10
|
|
21
21
|
Requires-Dist: fastjsonschema<2.22.0,>=2.19.1
|
|
@@ -94,7 +94,7 @@ Provides-Extra: rdf
|
|
|
94
94
|
Requires-Dist: rdflib==7.6.0; extra == "rdf"
|
|
95
95
|
Provides-Extra: api
|
|
96
96
|
Requires-Dist: fastapi<0.140.0,>=0.115.0; extra == "api"
|
|
97
|
-
Requires-Dist: uvicorn<0.
|
|
97
|
+
Requires-Dist: uvicorn<0.52.0,>=0.44.0; extra == "api"
|
|
98
98
|
Provides-Extra: protobuf
|
|
99
99
|
Requires-Dist: proto-schema-parser<3.0,>=1.0; extra == "protobuf"
|
|
100
100
|
Provides-Extra: all
|
|
@@ -112,7 +112,7 @@ Requires-Dist: pytest-xdist; extra == "dev"
|
|
|
112
112
|
Requires-Dist: pymssql==2.3.13; extra == "dev"
|
|
113
113
|
Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == "dev"
|
|
114
114
|
Requires-Dist: mysql-connector-python<9.7.0,>=8.0.30; extra == "dev"
|
|
115
|
-
Requires-Dist: ruff==0.15.
|
|
115
|
+
Requires-Dist: ruff==0.15.21; extra == "dev"
|
|
116
116
|
Requires-Dist: testcontainers[kafka,minio,mssql,mysql,postgres]==4.14.2; extra == "dev"
|
|
117
117
|
Requires-Dist: trino==0.338.0; extra == "dev"
|
|
118
118
|
Dynamic: license-file
|
{datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/check_spec.py
RENAMED
|
@@ -30,6 +30,7 @@ class MetricType(str, Enum):
|
|
|
30
30
|
FIELD_PRESENT = "field_present"
|
|
31
31
|
FIELD_TYPE = "field_type"
|
|
32
32
|
FIELD_PHYSICAL_TYPE = "field_physical_type"
|
|
33
|
+
FIELD_NESTED_TYPE = "field_nested_type"
|
|
33
34
|
FRESHNESS = "freshness"
|
|
34
35
|
RETENTION = "retention"
|
|
35
36
|
CUSTOM_SQL = "custom_sql"
|
{datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/create_checks.py
RENAMED
|
@@ -22,6 +22,7 @@ from open_data_contract_standard.model import (
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
from datacontract.engines.checks.check_spec import CheckSpec, MetricType, Op, Threshold
|
|
25
|
+
from datacontract.engines.checks.type_normalize import normalize_type_name
|
|
25
26
|
from datacontract.engines.ibis.native_type import supports_native_type_introspection
|
|
26
27
|
|
|
27
28
|
logger = logging.getLogger(__name__)
|
|
@@ -54,6 +55,51 @@ def to_schema_name(schema_object: SchemaObject, server_type: Optional[str]) -> s
|
|
|
54
55
|
return schema_object.name
|
|
55
56
|
|
|
56
57
|
|
|
58
|
+
def _scalar_element_type(prop: SchemaProperty, physical: bool) -> Optional[str]:
|
|
59
|
+
"""The declared element type of an array of scalars, or None for anything else."""
|
|
60
|
+
if normalize_type_name(prop.logicalType or prop.physicalType) != "array" or prop.items is None:
|
|
61
|
+
return None
|
|
62
|
+
items = prop.items
|
|
63
|
+
if items.properties or items.items is not None:
|
|
64
|
+
return None
|
|
65
|
+
label = (items.physicalType or items.logicalType) if physical else (items.logicalType or items.physicalType)
|
|
66
|
+
if normalize_type_name(label) in ("object", "array"):
|
|
67
|
+
return None
|
|
68
|
+
return label
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _declared_type_label(prop: SchemaProperty, physical: bool) -> Optional[str]:
|
|
72
|
+
"""Render the declared type with its children, e.g. ``OBJECT(code VARCHAR(10), description VARCHAR)``."""
|
|
73
|
+
label = (prop.physicalType or prop.logicalType) if physical else (prop.logicalType or prop.physicalType)
|
|
74
|
+
base = normalize_type_name(label)
|
|
75
|
+
if base == "array" and prop.items is not None:
|
|
76
|
+
return f"{label}({_declared_type_label(prop.items, physical)})"
|
|
77
|
+
if base == "object" and prop.properties:
|
|
78
|
+
children = ", ".join(f"{child.name} {_declared_type_label(child, physical)}" for child in prop.properties)
|
|
79
|
+
return f"{label}({children})"
|
|
80
|
+
return label
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _nested_type_check(model: str, field: str, prop: SchemaProperty, physical: bool) -> CheckSpec:
|
|
84
|
+
check_type = "field_nested_physical_type" if physical else "field_nested_type"
|
|
85
|
+
element = _scalar_element_type(prop, physical)
|
|
86
|
+
if element is not None:
|
|
87
|
+
name = f"Check that items of array {field} have {'physical type' if physical else 'type'} {element}"
|
|
88
|
+
else:
|
|
89
|
+
name = f"Check that nested {'physical types' if physical else 'types'} of {field} are correct"
|
|
90
|
+
return CheckSpec(
|
|
91
|
+
key=f"{model}__{field}__{check_type}",
|
|
92
|
+
category="schema",
|
|
93
|
+
type=check_type,
|
|
94
|
+
name=name,
|
|
95
|
+
model=model,
|
|
96
|
+
field=field,
|
|
97
|
+
metric=MetricType.FIELD_NESTED_TYPE,
|
|
98
|
+
expected_type_label=_declared_type_label(prop, physical),
|
|
99
|
+
expected_schema_property=prop,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
57
103
|
_PERCENT_UNITS = {"percent", "percentage", "%"}
|
|
58
104
|
|
|
59
105
|
|
|
@@ -172,6 +218,20 @@ def _to_schema_checks(schema_object: SchemaObject, server: Optional[Server]) ->
|
|
|
172
218
|
)
|
|
173
219
|
)
|
|
174
220
|
|
|
221
|
+
# The raw view cannot provide nested type checks
|
|
222
|
+
declared_base = normalize_type_name(prop.logicalType or prop.physicalType)
|
|
223
|
+
nested_checks_possible = (
|
|
224
|
+
check_types
|
|
225
|
+
and not uses_raw_view
|
|
226
|
+
and declared_base in ("object", "array")
|
|
227
|
+
and (bool(prop.properties) or prop.items is not None)
|
|
228
|
+
)
|
|
229
|
+
base_prop = (
|
|
230
|
+
SchemaProperty(name=prop.name, logicalType=prop.logicalType, physicalType=prop.physicalType)
|
|
231
|
+
if nested_checks_possible
|
|
232
|
+
else prop
|
|
233
|
+
)
|
|
234
|
+
|
|
175
235
|
# A declared physicalType is checked against the column's real native
|
|
176
236
|
# type in the platform catalog and takes precedence over logicalType,
|
|
177
237
|
# but only on backends that expose a meaningful native type. Elsewhere
|
|
@@ -191,11 +251,13 @@ def _to_schema_checks(schema_object: SchemaObject, server: Optional[Server]) ->
|
|
|
191
251
|
expected_physical_type=prop.physicalType,
|
|
192
252
|
# Carried for the logicalType fallback when the native type
|
|
193
253
|
# cannot be read or the physicalType is cross-dialect.
|
|
194
|
-
expected_schema_property=
|
|
254
|
+
expected_schema_property=base_prop if prop.logicalType is not None else None,
|
|
195
255
|
)
|
|
196
256
|
)
|
|
257
|
+
if nested_checks_possible:
|
|
258
|
+
checks.append(_nested_type_check(model, field, prop, physical=True))
|
|
197
259
|
elif check_types and prop.logicalType is not None:
|
|
198
|
-
|
|
260
|
+
label = prop.logicalType or ""
|
|
199
261
|
checks.append(
|
|
200
262
|
CheckSpec(
|
|
201
263
|
key=f"{model}__{field}__field_type",
|
|
@@ -207,9 +269,11 @@ def _to_schema_checks(schema_object: SchemaObject, server: Optional[Server]) ->
|
|
|
207
269
|
metric=MetricType.FIELD_TYPE,
|
|
208
270
|
expected_category=label,
|
|
209
271
|
expected_type_label=label,
|
|
210
|
-
expected_schema_property=
|
|
272
|
+
expected_schema_property=base_prop,
|
|
211
273
|
)
|
|
212
274
|
)
|
|
275
|
+
if nested_checks_possible:
|
|
276
|
+
checks.append(_nested_type_check(model, field, prop, physical=False))
|
|
213
277
|
|
|
214
278
|
if prop.required:
|
|
215
279
|
checks.append(
|
|
@@ -43,6 +43,31 @@ def _timestamp_family() -> set:
|
|
|
43
43
|
|
|
44
44
|
_TIMESTAMP_FAMILY = _timestamp_family()
|
|
45
45
|
|
|
46
|
+
# Each group is a single Snowflake type under different names, which its catalog
|
|
47
|
+
# reports as the one canonical name (TEXT, NUMBER, FLOAT), so a contract declaring
|
|
48
|
+
# any of the aliases must match its own column. Dialect-specific because elsewhere
|
|
49
|
+
# (MySQL, SQL Server) TEXT and VARCHAR, or INT and DECIMAL, are distinct types.
|
|
50
|
+
_SNOWFLAKE_FAMILIES = (
|
|
51
|
+
{exp.DataType.Type.VARCHAR, exp.DataType.Type.TEXT, exp.DataType.Type.NVARCHAR},
|
|
52
|
+
# exact numerics: INT/INTEGER/BIGINT/SMALLINT/TINYINT/BYTEINT/NUMERIC are NUMBER(38,0)
|
|
53
|
+
{
|
|
54
|
+
exp.DataType.Type.DECIMAL,
|
|
55
|
+
exp.DataType.Type.INT,
|
|
56
|
+
exp.DataType.Type.BIGINT,
|
|
57
|
+
exp.DataType.Type.SMALLINT,
|
|
58
|
+
exp.DataType.Type.TINYINT,
|
|
59
|
+
},
|
|
60
|
+
# approximate numerics: FLOAT/FLOAT4/FLOAT8/DOUBLE/REAL are all 64-bit FLOAT
|
|
61
|
+
{exp.DataType.Type.DOUBLE, exp.DataType.Type.FLOAT},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _is_snowflake(dialect) -> bool:
|
|
66
|
+
if isinstance(dialect, str):
|
|
67
|
+
return dialect.lower() == "snowflake"
|
|
68
|
+
name = getattr(dialect, "__name__", None) or type(dialect).__name__
|
|
69
|
+
return name.lower() == "snowflake"
|
|
70
|
+
|
|
46
71
|
|
|
47
72
|
def _parse(type_str: str, dialect) -> Optional[exp.DataType]:
|
|
48
73
|
"""Parse a type string into an ``exp.DataType`` for ``dialect``, or ``None``."""
|
|
@@ -132,12 +157,14 @@ def physical_type_matches(
|
|
|
132
157
|
exp_dt.this == act_dt.this
|
|
133
158
|
or {exp_dt.this, act_dt.this} <= _TIMESTAMP_FAMILY
|
|
134
159
|
or (both_numeric and _base_sql(exp_dt, dialect) == _base_sql(act_dt, dialect))
|
|
160
|
+
or (_is_snowflake(dialect) and any({exp_dt.this, act_dt.this} <= family for family in _SNOWFLAKE_FAMILIES))
|
|
135
161
|
)
|
|
136
162
|
if not same_base:
|
|
137
163
|
return False, f"expected physical type '{expected}' but the column is '{actual}'"
|
|
138
164
|
|
|
139
|
-
|
|
140
|
-
|
|
165
|
+
# sqlglot fills in a dialect's default precision (a bare NUMBER parses as
|
|
166
|
+
# DECIMAL(38,0)), so what the contract declares is read off the raw string.
|
|
167
|
+
if _split_base(_normalize_raw(expected))[1] and _params(exp_dt) != _params(act_dt):
|
|
141
168
|
return False, f"expected physical type '{expected}' but the column is '{actual}'"
|
|
142
169
|
|
|
143
170
|
return True, ""
|
{datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/checks/type_normalize.py
RENAMED
|
@@ -11,9 +11,12 @@ the actual type is structurally compatible with the expected one.
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
13
|
import re
|
|
14
|
+
from typing import NamedTuple
|
|
14
15
|
|
|
15
16
|
from open_data_contract_standard.model import SchemaProperty
|
|
16
17
|
|
|
18
|
+
from datacontract.engines.checks.physical_type_match import physical_type_matches
|
|
19
|
+
|
|
17
20
|
# logicalType marker for a field whose type the backend cannot describe: a
|
|
18
21
|
# dynamically-typed column (ibis json: Snowflake VARIANT, Postgres JSONB,
|
|
19
22
|
# BigQuery JSON) or an unsupported one (binary, geography). No declared type can
|
|
@@ -176,29 +179,42 @@ def schema_property_matches(expected: SchemaProperty | None, actual: SchemaPrope
|
|
|
176
179
|
return True
|
|
177
180
|
|
|
178
181
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
actual
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
class TypeMismatch(NamedTuple):
|
|
183
|
+
message: str
|
|
184
|
+
# False when the actual structure cannot be read (json / variant / untyped
|
|
185
|
+
# object): the declared type is neither confirmed nor refuted.
|
|
186
|
+
verifiable: bool
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def format_mismatch_reason(errors: list[TypeMismatch]) -> str:
|
|
190
|
+
"""The first mismatch and a count of the other type errors, or '' if none."""
|
|
186
191
|
num_errors = len(errors)
|
|
187
192
|
|
|
188
193
|
if num_errors == 0:
|
|
189
194
|
return ""
|
|
190
195
|
elif num_errors == 1:
|
|
191
|
-
return errors[0]
|
|
196
|
+
return errors[0].message
|
|
192
197
|
else:
|
|
193
|
-
return f"{errors[0]} (and {num_errors - 1} other error{'s' if num_errors > 2 else ''})"
|
|
198
|
+
return f"{errors[0].message} (and {num_errors - 1} other error{'s' if num_errors > 2 else ''})"
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def schema_property_mismatch_reason(
|
|
202
|
+
expected: SchemaProperty | None,
|
|
203
|
+
actual: SchemaProperty | None,
|
|
204
|
+
path: str = "",
|
|
205
|
+
dialect=None,
|
|
206
|
+
) -> str:
|
|
207
|
+
"""Return a human-readable description of the first structural mismatch and a count of other type errors, or '' if none."""
|
|
208
|
+
return format_mismatch_reason(schema_property_mismatch_reasons(expected, actual, path, dialect))
|
|
194
209
|
|
|
195
210
|
|
|
196
211
|
def schema_property_mismatch_reasons(
|
|
197
212
|
expected: SchemaProperty | None,
|
|
198
213
|
actual: SchemaProperty | None,
|
|
199
214
|
path: str = "",
|
|
200
|
-
|
|
201
|
-
|
|
215
|
+
dialect=None,
|
|
216
|
+
) -> list[TypeMismatch]:
|
|
217
|
+
errors: list[TypeMismatch] = []
|
|
202
218
|
|
|
203
219
|
if expected is None:
|
|
204
220
|
return errors
|
|
@@ -206,7 +222,12 @@ def schema_property_mismatch_reasons(
|
|
|
206
222
|
field_label = f"field '{path}'" if path else "column"
|
|
207
223
|
if actual is None:
|
|
208
224
|
exp_str = expected.logicalType or expected.physicalType
|
|
209
|
-
errors.append(
|
|
225
|
+
errors.append(
|
|
226
|
+
TypeMismatch(
|
|
227
|
+
f"{field_label}: expected type '{exp_str}' but the column type could not be determined",
|
|
228
|
+
verifiable=False,
|
|
229
|
+
)
|
|
230
|
+
)
|
|
210
231
|
return errors
|
|
211
232
|
expected_base = normalize_type_name(expected.logicalType or expected.physicalType)
|
|
212
233
|
actual_base = normalize_type_name(actual.logicalType or actual.physicalType)
|
|
@@ -218,30 +239,54 @@ def schema_property_mismatch_reasons(
|
|
|
218
239
|
exp_str = expected.logicalType or expected.physicalType
|
|
219
240
|
act_str = actual.physicalType or "unknown"
|
|
220
241
|
errors.append(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
242
|
+
TypeMismatch(
|
|
243
|
+
f"{field_label}: has type '{act_str}', but the contract specifies '{exp_str}'. "
|
|
244
|
+
f"A '{act_str}' value has no verifiable logical type. "
|
|
245
|
+
f"If this is intentional, specify `physicalType: {act_str}`.",
|
|
246
|
+
verifiable=False,
|
|
247
|
+
)
|
|
224
248
|
)
|
|
225
249
|
return errors
|
|
226
250
|
|
|
251
|
+
# A leaf that declares a physicalType is compared against the column's real
|
|
252
|
+
# native type, where the backend reports one. The declared type wins over the
|
|
253
|
+
# logicalType, as it does for the column itself.
|
|
254
|
+
if expected_base not in ("object", "array") and expected.physicalType and actual.physicalType:
|
|
255
|
+
result, reason = physical_type_matches(expected.physicalType, actual.physicalType, dialect)
|
|
256
|
+
if result is True:
|
|
257
|
+
return errors
|
|
258
|
+
if result is False:
|
|
259
|
+
errors.append(TypeMismatch(f"{field_label}: {reason}", verifiable=True))
|
|
260
|
+
return errors
|
|
261
|
+
# The declared type names nothing in this dialect (a logical keyword such
|
|
262
|
+
# as `string`, or a type from another platform): fall back to the category
|
|
263
|
+
# comparison, and only give up when there is no logicalType to fall back on.
|
|
264
|
+
if expected.logicalType is None:
|
|
265
|
+
errors.append(TypeMismatch(f"{field_label}: {reason}", verifiable=False))
|
|
266
|
+
return errors
|
|
267
|
+
|
|
227
268
|
if expected_base != actual_base and not (expected_base in _NUMERIC and actual_base in _NUMERIC):
|
|
228
269
|
exp_str = expected.logicalType or expected.physicalType
|
|
229
270
|
act_str = actual.logicalType or actual.physicalType
|
|
230
|
-
errors.append(f"{field_label}: expected type '{exp_str}' but got '{act_str}'")
|
|
271
|
+
errors.append(TypeMismatch(f"{field_label}: expected type '{exp_str}' but got '{act_str}'", verifiable=True))
|
|
231
272
|
return errors
|
|
232
273
|
|
|
233
274
|
if expected_base == "array":
|
|
234
275
|
if expected.items is not None:
|
|
235
276
|
child_path = f"{path}[]" if path else "[]"
|
|
236
|
-
errors.extend(schema_property_mismatch_reasons(expected.items, actual.items, child_path))
|
|
277
|
+
errors.extend(schema_property_mismatch_reasons(expected.items, actual.items, child_path, dialect))
|
|
237
278
|
|
|
238
279
|
if expected_base == "object":
|
|
239
280
|
if not expected.properties:
|
|
240
281
|
return errors
|
|
241
282
|
if actual.properties is None:
|
|
242
283
|
errors.append(
|
|
243
|
-
|
|
244
|
-
|
|
284
|
+
TypeMismatch(
|
|
285
|
+
f"{field_label}: nested properties are declared but the column is an untyped object "
|
|
286
|
+
"whose structure can't be verified. Use a structured type for your data or specify "
|
|
287
|
+
"physicalType.",
|
|
288
|
+
verifiable=False,
|
|
289
|
+
)
|
|
245
290
|
)
|
|
246
291
|
return errors
|
|
247
292
|
|
|
@@ -254,9 +299,9 @@ def schema_property_mismatch_reasons(
|
|
|
254
299
|
act_field = actual_by_name.get(exp_field.name.lower())
|
|
255
300
|
|
|
256
301
|
if act_field is None:
|
|
257
|
-
errors.append(f"field '{child_path}' is missing")
|
|
302
|
+
errors.append(TypeMismatch(f"field '{child_path}' is missing", verifiable=True))
|
|
258
303
|
continue
|
|
259
304
|
|
|
260
|
-
errors.extend(schema_property_mismatch_reasons(exp_field, act_field, child_path))
|
|
305
|
+
errors.extend(schema_property_mismatch_reasons(exp_field, act_field, child_path, dialect))
|
|
261
306
|
|
|
262
307
|
return errors
|
{datacontract_cli-1.0.12 → datacontract_cli-1.0.13}/datacontract/engines/ibis/ibis_check_execute.py
RENAMED
|
@@ -18,7 +18,13 @@ from open_data_contract_standard.model import OpenDataContractStandard, SchemaPr
|
|
|
18
18
|
|
|
19
19
|
from datacontract.engines.checks.check_spec import CheckSpec, MetricType
|
|
20
20
|
from datacontract.engines.checks.physical_type_match import physical_type_matches
|
|
21
|
-
from datacontract.engines.checks.type_normalize import
|
|
21
|
+
from datacontract.engines.checks.type_normalize import (
|
|
22
|
+
format_mismatch_reason,
|
|
23
|
+
normalize_type_name,
|
|
24
|
+
schema_property_matches,
|
|
25
|
+
schema_property_mismatch_reason,
|
|
26
|
+
schema_property_mismatch_reasons,
|
|
27
|
+
)
|
|
22
28
|
from datacontract.engines.ibis.connections.connect import connect_ibis
|
|
23
29
|
from datacontract.engines.ibis.dtype_category import ibis_dtype_to_schema_property
|
|
24
30
|
from datacontract.engines.ibis.native_type import fetch_native_types, sqlglot_dialect
|
|
@@ -63,6 +69,8 @@ def _describe(spec: CheckSpec) -> str:
|
|
|
63
69
|
return f"type({spec.field}) == {spec.expected_type_label}"
|
|
64
70
|
if spec.metric == MetricType.FIELD_PHYSICAL_TYPE:
|
|
65
71
|
return f"physical_type({spec.field}) == {spec.expected_physical_type}"
|
|
72
|
+
if spec.metric == MetricType.FIELD_NESTED_TYPE:
|
|
73
|
+
return f"nested_types({spec.field}) match the contract"
|
|
66
74
|
if spec.metric == MetricType.FIELD_PRESENT:
|
|
67
75
|
return f"present({spec.field})"
|
|
68
76
|
if spec.threshold is not None:
|
|
@@ -201,7 +209,8 @@ def _run_model(
|
|
|
201
209
|
# the real nested types from SHOW COLUMNS so field_type checks can recurse.
|
|
202
210
|
structured_types = None
|
|
203
211
|
if get_server_type(server) == "snowflake" and any(
|
|
204
|
-
spec.metric in (MetricType.FIELD_TYPE, MetricType.FIELD_PHYSICAL_TYPE)
|
|
212
|
+
spec.metric in (MetricType.FIELD_TYPE, MetricType.FIELD_PHYSICAL_TYPE, MetricType.FIELD_NESTED_TYPE)
|
|
213
|
+
for spec in specs
|
|
205
214
|
):
|
|
206
215
|
structured_types = fetch_structured_types(con, server, t.get_name())
|
|
207
216
|
|
|
@@ -231,6 +240,8 @@ def _run_model(
|
|
|
231
240
|
_run_type(run, schema, columns, spec, structured_types)
|
|
232
241
|
elif spec.metric == MetricType.FIELD_PHYSICAL_TYPE:
|
|
233
242
|
_run_physical_type(run, con, server, schema, columns, native_types, spec, structured_types)
|
|
243
|
+
elif spec.metric == MetricType.FIELD_NESTED_TYPE:
|
|
244
|
+
_run_nested_type(run, schema, columns, spec, structured_types, sqlglot_dialect(con))
|
|
234
245
|
elif spec.metric in (MetricType.FRESHNESS, MetricType.RETENTION):
|
|
235
246
|
_run_freshness(run, t, columns, spec)
|
|
236
247
|
elif spec.metric == MetricType.CUSTOM_SQL:
|
|
@@ -746,6 +757,74 @@ def _run_physical_type(
|
|
|
746
757
|
_set_result(run, spec.key, ResultEnum.warning, f"{reason}; skipping the physical type check")
|
|
747
758
|
|
|
748
759
|
|
|
760
|
+
def _run_nested_type(
|
|
761
|
+
run: Run,
|
|
762
|
+
schema,
|
|
763
|
+
columns,
|
|
764
|
+
spec: CheckSpec,
|
|
765
|
+
structured_types: dict[str, SchemaProperty] | None = None,
|
|
766
|
+
dialect=None,
|
|
767
|
+
):
|
|
768
|
+
"""Compare the children a property declares (``properties:`` / ``items:``) against
|
|
769
|
+
the column's real nested structure. The column's own type is the base check's job.
|
|
770
|
+
"""
|
|
771
|
+
metric = spec.type
|
|
772
|
+
_set_impl(run, spec.key, f"nested types of '{spec.field}' match the contract", "introspection")
|
|
773
|
+
actual_col = columns.get(spec.field.lower())
|
|
774
|
+
if actual_col is None:
|
|
775
|
+
_set_diagnostics(run, spec.key, _diag(metric=metric, field=spec.field, expected=spec.expected_type_label))
|
|
776
|
+
_set_result(run, spec.key, ResultEnum.failed, f"Column '{spec.field}' is missing")
|
|
777
|
+
return
|
|
778
|
+
|
|
779
|
+
dtype = schema[actual_col]
|
|
780
|
+
structured_prop = structured_types.get(spec.field.lower()) if structured_types else None
|
|
781
|
+
actual_prop = structured_prop or ibis_dtype_to_schema_property(dtype)
|
|
782
|
+
actual_label = (structured_prop.physicalType if structured_prop else None) or str(dtype)
|
|
783
|
+
_set_diagnostics(
|
|
784
|
+
run,
|
|
785
|
+
spec.key,
|
|
786
|
+
_diag(metric=metric, field=spec.field, expected=spec.expected_type_label, actual=actual_label),
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
expected = spec.expected_schema_property
|
|
790
|
+
expected_base = normalize_type_name(expected.logicalType or expected.physicalType)
|
|
791
|
+
actual_base = normalize_type_name(actual_prop.logicalType or actual_prop.physicalType)
|
|
792
|
+
if actual_base is None:
|
|
793
|
+
# A dynamically-typed column (json / variant / jsonb) holds a different
|
|
794
|
+
# structure per row, so there is nothing to compare the children against.
|
|
795
|
+
_set_result(
|
|
796
|
+
run,
|
|
797
|
+
spec.key,
|
|
798
|
+
ResultEnum.warning,
|
|
799
|
+
f"The structure of the '{actual_label}' column '{spec.field}' cannot be read; "
|
|
800
|
+
f"skipping the nested type check",
|
|
801
|
+
)
|
|
802
|
+
return
|
|
803
|
+
if expected_base != actual_base:
|
|
804
|
+
# The base type check names the actual type; repeating it here would print
|
|
805
|
+
# the column's whole rendered structure.
|
|
806
|
+
_set_result(
|
|
807
|
+
run,
|
|
808
|
+
spec.key,
|
|
809
|
+
ResultEnum.failed,
|
|
810
|
+
f"Cannot verify the nested types of '{spec.field}': the column is not an {expected_base}",
|
|
811
|
+
)
|
|
812
|
+
return
|
|
813
|
+
|
|
814
|
+
errors = schema_property_mismatch_reasons(expected, actual_prop, spec.field, dialect)
|
|
815
|
+
if not errors:
|
|
816
|
+
_set_result(run, spec.key, ResultEnum.passed, None)
|
|
817
|
+
return
|
|
818
|
+
_update_diagnostics(run, spec.key, {"errors": [error.message for error in errors]})
|
|
819
|
+
verified = any(error.verifiable for error in errors)
|
|
820
|
+
_set_result(
|
|
821
|
+
run,
|
|
822
|
+
spec.key,
|
|
823
|
+
ResultEnum.failed if verified else ResultEnum.warning,
|
|
824
|
+
format_mismatch_reason(errors),
|
|
825
|
+
)
|
|
826
|
+
|
|
827
|
+
|
|
749
828
|
def _run_freshness(run: Run, t, columns, spec: CheckSpec):
|
|
750
829
|
import pandas as pd
|
|
751
830
|
|
|
@@ -26,13 +26,18 @@ _LEAF_TYPES = {
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def _to_property(node: dict) -> SchemaProperty:
|
|
29
|
-
"""Convert one ``data_type`` JSON node to a ``SchemaProperty``.
|
|
29
|
+
"""Convert one ``data_type`` JSON node to a ``SchemaProperty``.
|
|
30
|
+
|
|
31
|
+
Every node also carries its rendered native type, so a declared physicalType
|
|
32
|
+
can be checked against the column's real one down the whole tree.
|
|
33
|
+
"""
|
|
34
|
+
native = _render_native(node)
|
|
30
35
|
node_type = node.get("type")
|
|
31
36
|
if node_type == "OBJECT":
|
|
32
37
|
fields = node.get("fields")
|
|
33
38
|
if not fields:
|
|
34
39
|
# untyped OBJECT: same shape as the collapsed ibis map
|
|
35
|
-
return SchemaProperty(logicalType="object", properties=None)
|
|
40
|
+
return SchemaProperty(logicalType="object", physicalType=native, properties=None)
|
|
36
41
|
properties = []
|
|
37
42
|
for field in fields:
|
|
38
43
|
name = field.get("fieldName")
|
|
@@ -48,19 +53,21 @@ def _to_property(node: dict) -> SchemaProperty:
|
|
|
48
53
|
properties=child.properties,
|
|
49
54
|
)
|
|
50
55
|
)
|
|
51
|
-
return SchemaProperty(logicalType="object", properties=properties or None)
|
|
56
|
+
return SchemaProperty(logicalType="object", physicalType=native, properties=properties or None)
|
|
52
57
|
if node_type == "ARRAY":
|
|
53
58
|
element = node.get("elementType")
|
|
54
59
|
# untyped ARRAY: no element type to recurse into
|
|
55
|
-
return SchemaProperty(
|
|
60
|
+
return SchemaProperty(
|
|
61
|
+
logicalType="array", physicalType=native, items=_to_property(element) if element else None
|
|
62
|
+
)
|
|
56
63
|
if node_type == "MAP":
|
|
57
64
|
# dynamic keys can't be matched to named contract properties
|
|
58
|
-
return SchemaProperty(logicalType="object", properties=None)
|
|
65
|
+
return SchemaProperty(logicalType="object", physicalType=native, properties=None)
|
|
59
66
|
logical = _LEAF_TYPES.get(node_type)
|
|
60
67
|
if logical:
|
|
61
|
-
return SchemaProperty(logicalType=logical)
|
|
68
|
+
return SchemaProperty(logicalType=logical, physicalType=native)
|
|
62
69
|
# VARIANT, BINARY, GEOGRAPHY, …: keep the Snowflake token for the failure message
|
|
63
|
-
return SchemaProperty(logicalType=UNKNOWN_LOGICAL_TYPE, physicalType=
|
|
70
|
+
return SchemaProperty(logicalType=UNKNOWN_LOGICAL_TYPE, physicalType=native)
|
|
64
71
|
|
|
65
72
|
|
|
66
73
|
def has_nesting(prop: SchemaProperty) -> bool:
|
|
@@ -122,10 +129,7 @@ def fetch_structured_types(con, server: Server, table_name: str) -> dict[str, Sc
|
|
|
122
129
|
except (TypeError, ValueError):
|
|
123
130
|
continue
|
|
124
131
|
prop = _to_property(node)
|
|
125
|
-
if has_nesting(prop):
|
|
126
|
-
# the real native type, for diagnostics the collapsed ibis dtype can't give
|
|
127
|
-
prop.physicalType = _render_native(node)
|
|
128
|
-
elif prop.logicalType != UNKNOWN_LOGICAL_TYPE:
|
|
132
|
+
if not has_nesting(prop) and prop.logicalType != UNKNOWN_LOGICAL_TYPE:
|
|
129
133
|
# scalars and untyped OBJECT/ARRAY: the collapsed ibis dtype says the same
|
|
130
134
|
continue
|
|
131
135
|
# an unverifiable leaf (VARIANT, GEOGRAPHY, …) keeps its Snowflake token, which
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.13
|
|
4
4
|
Summary: The datacontract CLI is an open source command-line tool for working with Data Contracts. It uses data contract YAML files to lint the data contract, connect to data sources and execute schema and quality tests, detect breaking changes, and export to different formats. The tool is written in Python. It can be used as a standalone CLI tool, in a CI/CD pipeline, or directly as a Python library.
|
|
5
5
|
Author-email: Jochen Christ <jochen.christ@innoq.com>, Stefan Negele <stefan.negele@innoq.com>, Simon Harrer <simon.harrer@innoq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -15,7 +15,7 @@ Requires-Dist: typer<0.27,>=0.18.0
|
|
|
15
15
|
Requires-Dist: click<9.0.0,>=8.1.0
|
|
16
16
|
Requires-Dist: pydantic<2.14.0,>=2.8.2
|
|
17
17
|
Requires-Dist: pyyaml~=6.0.1
|
|
18
|
-
Requires-Dist: ruamel.yaml<0.
|
|
18
|
+
Requires-Dist: ruamel.yaml<0.20,>=0.17
|
|
19
19
|
Requires-Dist: requests<2.35,>=2.31
|
|
20
20
|
Requires-Dist: truststore<1.0,>=0.10
|
|
21
21
|
Requires-Dist: fastjsonschema<2.22.0,>=2.19.1
|
|
@@ -94,7 +94,7 @@ Provides-Extra: rdf
|
|
|
94
94
|
Requires-Dist: rdflib==7.6.0; extra == "rdf"
|
|
95
95
|
Provides-Extra: api
|
|
96
96
|
Requires-Dist: fastapi<0.140.0,>=0.115.0; extra == "api"
|
|
97
|
-
Requires-Dist: uvicorn<0.
|
|
97
|
+
Requires-Dist: uvicorn<0.52.0,>=0.44.0; extra == "api"
|
|
98
98
|
Provides-Extra: protobuf
|
|
99
99
|
Requires-Dist: proto-schema-parser<3.0,>=1.0; extra == "protobuf"
|
|
100
100
|
Provides-Extra: all
|
|
@@ -112,7 +112,7 @@ Requires-Dist: pytest-xdist; extra == "dev"
|
|
|
112
112
|
Requires-Dist: pymssql==2.3.13; extra == "dev"
|
|
113
113
|
Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == "dev"
|
|
114
114
|
Requires-Dist: mysql-connector-python<9.7.0,>=8.0.30; extra == "dev"
|
|
115
|
-
Requires-Dist: ruff==0.15.
|
|
115
|
+
Requires-Dist: ruff==0.15.21; extra == "dev"
|
|
116
116
|
Requires-Dist: testcontainers[kafka,minio,mssql,mysql,postgres]==4.14.2; extra == "dev"
|
|
117
117
|
Requires-Dist: trino==0.338.0; extra == "dev"
|
|
118
118
|
Dynamic: license-file
|
|
@@ -255,6 +255,7 @@ tests/test_cli.py
|
|
|
255
255
|
tests/test_connect_databricks.py
|
|
256
256
|
tests/test_connect_sqlserver.py
|
|
257
257
|
tests/test_connect_trino.py
|
|
258
|
+
tests/test_create_checks_nested_type.py
|
|
258
259
|
tests/test_create_checks_physical_type.py
|
|
259
260
|
tests/test_data_contract.py
|
|
260
261
|
tests/test_data_contract_checks.py
|
|
@@ -2,7 +2,7 @@ typer<0.27,>=0.18.0
|
|
|
2
2
|
click<9.0.0,>=8.1.0
|
|
3
3
|
pydantic<2.14.0,>=2.8.2
|
|
4
4
|
pyyaml~=6.0.1
|
|
5
|
-
ruamel.yaml<0.
|
|
5
|
+
ruamel.yaml<0.20,>=0.17
|
|
6
6
|
requests<2.35,>=2.31
|
|
7
7
|
truststore<1.0,>=0.10
|
|
8
8
|
fastjsonschema<2.22.0,>=2.19.1
|
|
@@ -24,7 +24,7 @@ datacontract-cli[api,athena,azure,bigquery,csv,databricks,dbml,duckdb,excel,gcs,
|
|
|
24
24
|
|
|
25
25
|
[api]
|
|
26
26
|
fastapi<0.140.0,>=0.115.0
|
|
27
|
-
uvicorn<0.
|
|
27
|
+
uvicorn<0.52.0,>=0.44.0
|
|
28
28
|
|
|
29
29
|
[athena]
|
|
30
30
|
ibis-framework[athena]<13.0.0,>=10.0.0
|
|
@@ -66,7 +66,7 @@ pytest-xdist
|
|
|
66
66
|
pymssql==2.3.13
|
|
67
67
|
psycopg2-binary<3.0,>=2.9
|
|
68
68
|
mysql-connector-python<9.7.0,>=8.0.30
|
|
69
|
-
ruff==0.15.
|
|
69
|
+
ruff==0.15.21
|
|
70
70
|
testcontainers[kafka,minio,mssql,mysql,postgres]==4.14.2
|
|
71
71
|
trino==0.338.0
|
|
72
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datacontract-cli"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.13"
|
|
4
4
|
description = "The datacontract CLI is an open source command-line tool for working with Data Contracts. It uses data contract YAML files to lint the data contract, connect to data sources and execute schema and quality tests, detect breaking changes, and export to different formats. The tool is written in Python. It can be used as a standalone CLI tool, in a CI/CD pipeline, or directly as a Python library."
|
|
5
5
|
license = "MIT"
|
|
6
6
|
readme = "README.md"
|
|
@@ -19,7 +19,7 @@ dependencies = [
|
|
|
19
19
|
"click>=8.1.0,<9.0.0",
|
|
20
20
|
"pydantic>=2.8.2,<2.14.0",
|
|
21
21
|
"pyyaml~=6.0.1",
|
|
22
|
-
"ruamel.yaml>=0.17,<0.
|
|
22
|
+
"ruamel.yaml>=0.17,<0.20",
|
|
23
23
|
"requests>=2.31,<2.35",
|
|
24
24
|
"truststore>=0.10,<1.0",
|
|
25
25
|
"fastjsonschema>=2.19.1,<2.22.0",
|
|
@@ -171,7 +171,7 @@ rdf = [
|
|
|
171
171
|
|
|
172
172
|
api = [
|
|
173
173
|
"fastapi>=0.115.0,<0.140.0",
|
|
174
|
-
"uvicorn>=0.44.0,<0.
|
|
174
|
+
"uvicorn>=0.44.0,<0.52.0",
|
|
175
175
|
]
|
|
176
176
|
|
|
177
177
|
protobuf = [
|
|
@@ -200,7 +200,7 @@ dev = [
|
|
|
200
200
|
# psycopg v3 and DuckDB's mysql extension respectively).
|
|
201
201
|
"psycopg2-binary>=2.9,<3.0",
|
|
202
202
|
"mysql-connector-python>=8.0.30,<9.7.0",
|
|
203
|
-
"ruff==0.15.
|
|
203
|
+
"ruff==0.15.21",
|
|
204
204
|
"testcontainers[minio,postgres,kafka,mssql,mysql]==4.14.2",
|
|
205
205
|
"trino==0.338.0",
|
|
206
206
|
]
|