datacontract-cli 1.0.10__tar.gz → 1.0.12__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.10/datacontract_cli.egg-info → datacontract_cli-1.0.12}/PKG-INFO +1 -1
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/checks/physical_type_match.py +11 -1
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/checks/type_normalize.py +27 -1
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/dtype_category.py +22 -14
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/ibis_check_execute.py +43 -10
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/native_type.py +4 -0
- datacontract_cli-1.0.12/datacontract/engines/ibis/snowflake_structured_types.py +134 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/bigquery_importer.py +3 -2
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/lint/resolve.py +40 -12
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12/datacontract_cli.egg-info}/PKG-INFO +1 -1
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract_cli.egg-info/SOURCES.txt +2 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/pyproject.toml +1 -1
- datacontract_cli-1.0.12/tests/test_dtype_category.py +84 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_physical_type_match.py +51 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_resolve_definitions.py +20 -1
- datacontract_cli-1.0.12/tests/test_snowflake_structured_types.py +236 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_dataframe.py +2 -2
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_s3_json_remote.py +3 -0
- datacontract_cli-1.0.12/tests/test_type_normalize.py +92 -0
- datacontract_cli-1.0.10/tests/test_dtype_category.py +0 -28
- datacontract_cli-1.0.10/tests/test_type_normalize.py +0 -15
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/LICENSE +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/MANIFEST.in +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/README.md +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/api.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/catalog/catalog.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/changelog/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/changelog/changelog.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/changelog/normalize.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/cli.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_api.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_catalog.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_changelog.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_ci.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_dbt.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_edit.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_export.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_import.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_init.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_lint.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_publish.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/command_test.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/data_contract.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/VERSION +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/abap-Bs8kvjsq.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/apex-Dspwrl5m.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/azcli-k1BiOau1.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/bat-BIP72KWc.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/bicep-VhQeYhS3.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/cameligo-DnuAXtHg.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/clojure-BAuDPsal.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/coffee-BV06qSnj.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/cpp-Cz8Jeyrf.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/csharp-F6hhlXFb.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/csp-KzlEHCyI.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/css-e4FKntZ3.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/cssMode-BNkTa2xp.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/cypher-CpvDGKRr.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/dart-DdHeFWR0.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/datacontract-editor.css +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/datacontract-editor.es.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/dockerfile-aoNXDcio.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/ecl-C4Q0DYuA.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/elixir-C9X42b0T.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/flow9-Bff42pfB.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/freemarker2-Dyfzmb5A.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/fsharp-C6vPAsHG.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/go-DEr8zx9f.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/graphql-BiNBBRFh.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/handlebars-BtDNI-uC.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/hcl-2T9lKuFg.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/html-Cn4TGw_o.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/htmlMode-Bf84vbo2.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/index.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/ini-CZGtssYM.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/java-B260NeH3.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/javascript-B86Kac07.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/jsonMode-Ckgg5lAE.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/julia-kuNLM9c5.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/kotlin-Bz6kAefA.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/less-AZUtS89I.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/lexon-BcmgnyRb.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/liquid-D0NPwuu_.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/lua-Dz1RbATg.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/m3-CIMooLFn.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/markdown-C1BsCK9P.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/mdx-QFRSBtVQ.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/mips-BovsnfLQ.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/monaco-4.7.0.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/msdax-CiRB2ZB-.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/mysql-BwdpPE19.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/objective-c-D4nfHfso.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/odcs.svg +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/pascal--j5-PYtz.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/pascaligo-C7TcJxNL.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/perl-BzEWqUb5.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/pgsql-B_KZ0mGX.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/php-A19QHzQV.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/pla-COeKY1hA.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/postiats-BfMp7zJL.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/powerquery-B0TS_5Gb.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/powershell-5jSbKdYB.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/protobuf-YgnOutn3.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/pug-DLej6kn5.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/python-C8RW9B6A.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/qsharp-AhjqtSHB.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/r-D-F4P80w.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/razor-CLZqdY_r.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/redis-hwwIlMnV.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/redshift-Bcm_kjEG.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/restructuredtext-CrdzfPP-.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/ruby-QC2UNm1s.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/rust-5aqiQ3L5.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/sb-B1g1ZfLJ.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/scala-C2U4R5Gb.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/scheme-DeFRbslr.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/scss-RSTCiCmI.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/shell-BpF-iNu8.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/solidity-C00r2mbQ.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/sophia-DVW5ZKDB.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/sparql-B0nmpxeX.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/sql-CJwKPERn.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/st-DPlKG5DT.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/swift-YZBAbVHV.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/systemverilog-CDQSaH63.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/tcl-Dlu8sp6Q.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/tsMode-yleMwhPq.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/twig-C5TO7-kw.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/typescript-CJBeebKU.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/typespec-BsmjDEu7.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/vb-ChHvIDrk.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/wgsl-XEp1ju8c.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/xml-vC-NMVX1.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/editor_assets/yaml-Dlf2VF-T.js +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/checks/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/checks/check_spec.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/checks/create_checks.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/data_contract_test.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/connections/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/connections/connect.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/connections/duckdb_connection.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/connections/kafka.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/connections/redshift_patch.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/avro_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/avro_idl_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/bigquery_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/data_caterer_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/dbml_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/dbt_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/dqx_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/excel_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/great_expectations_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/html_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/iceberg_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/markdown_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/mermaid_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/odcs_export_helper.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/protobuf_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/pydantic_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/rdf_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/sodacl_check_builder.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/sql_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/export/sqlalchemy_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/dcs_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/excel_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/json_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/odcs_helper.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/powerbi_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/snowflake_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/integration/dbt_sync.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/integration/dbt_test_mapping.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/lint/files.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/model/changelog.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/model/run.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/model/server.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/output/__init__.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/output/ci_output.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/output/json_test_results.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/output/junit_test_results.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/output/test_results_writer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/output/text_changelog_results.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/py.typed +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/odcs-3.1.0.init.yaml +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/index.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/model_field.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract_cli.egg-info/requires.txt +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/setup.cfg +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_api.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_catalog.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_changelog.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_changelog_engine.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_changelog_normalize.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_changelog_output_text.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_ci_output.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_cli.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_connect_databricks.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_connect_sqlserver.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_connect_trino.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_create_checks_physical_type.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_data_contract.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_data_contract_checks.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_dbt_sync.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_dbt_test_mapping.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_description_linter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_edit.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_avro.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_custom.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_custom_model.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_excel.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_go.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_html.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_spark.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_sql.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_sql_clickhouse.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_ibis_mssql_pattern.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_ibis_oracle_schema.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_avro.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_csv.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_excel.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_glue.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_json.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_powerbi.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_snowflake.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_spark.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_sql_oracle.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_sql_snowflake.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_lint.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_oracle_patch.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_redshift_patch.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_require_env.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_resolve.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_sql_type_converter_physicaltype.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_api.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_azure_blob_file.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_checks_filter.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_delta.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_diagnostics.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_failed_samples.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_mysql.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_oracle_xe.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_output_json.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_output_junit.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_parquet.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_quality.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_quality_local_fallback.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_quality_percent_severity.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_redshift.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_schema_evolution.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_server_not_found.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_soda_connection_error.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/tests/test_test_trino.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.12
|
|
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
|
|
@@ -90,6 +90,11 @@ def _raw_match(expected: str, actual: str) -> Optional[bool]:
|
|
|
90
90
|
return True if not e_params else e == a
|
|
91
91
|
|
|
92
92
|
|
|
93
|
+
def _base_sql(dtype: exp.DataType, dialect) -> str:
|
|
94
|
+
"""Render the bare base type in ``dialect``, collapsing that dialect's aliases."""
|
|
95
|
+
return exp.DataType(this=dtype.this).sql(dialect=dialect).lower()
|
|
96
|
+
|
|
97
|
+
|
|
93
98
|
def physical_type_matches(
|
|
94
99
|
expected: Optional[str],
|
|
95
100
|
actual: Optional[str],
|
|
@@ -122,7 +127,12 @@ def physical_type_matches(
|
|
|
122
127
|
f"server under test; skipping the physical type check"
|
|
123
128
|
)
|
|
124
129
|
|
|
125
|
-
|
|
130
|
+
both_numeric = {exp_dt.this, act_dt.this} <= exp.DataType.NUMERIC_TYPES
|
|
131
|
+
same_base = (
|
|
132
|
+
exp_dt.this == act_dt.this
|
|
133
|
+
or {exp_dt.this, act_dt.this} <= _TIMESTAMP_FAMILY
|
|
134
|
+
or (both_numeric and _base_sql(exp_dt, dialect) == _base_sql(act_dt, dialect))
|
|
135
|
+
)
|
|
126
136
|
if not same_base:
|
|
127
137
|
return False, f"expected physical type '{expected}' but the column is '{actual}'"
|
|
128
138
|
|
{datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/checks/type_normalize.py
RENAMED
|
@@ -14,6 +14,13 @@ import re
|
|
|
14
14
|
|
|
15
15
|
from open_data_contract_standard.model import SchemaProperty
|
|
16
16
|
|
|
17
|
+
# logicalType marker for a field whose type the backend cannot describe: a
|
|
18
|
+
# dynamically-typed column (ibis json: Snowflake VARIANT, Postgres JSONB,
|
|
19
|
+
# BigQuery JSON) or an unsupported one (binary, geography). No declared type can
|
|
20
|
+
# be confirmed against it, so any expected type fails rather than silently passing.
|
|
21
|
+
# Distinct from a missing field, which is what dropping it would look like.
|
|
22
|
+
UNKNOWN_LOGICAL_TYPE = "__unknown__"
|
|
23
|
+
|
|
17
24
|
|
|
18
25
|
def normalize_type_name(type_name: str | None) -> str | None:
|
|
19
26
|
"""Map a contract type name (logical or physical) to one of the 9 ODCS categories.
|
|
@@ -139,6 +146,8 @@ def schema_property_matches(expected: SchemaProperty | None, actual: SchemaPrope
|
|
|
139
146
|
if expected_base is None:
|
|
140
147
|
return True
|
|
141
148
|
if actual_base is None:
|
|
149
|
+
# actual is unsupported or dynamically typed (json element/variant): a
|
|
150
|
+
# declared concrete type can't be confirmed against it, so it fails.
|
|
142
151
|
return False
|
|
143
152
|
if expected_base != actual_base and not (expected_base in _NUMERIC and actual_base in _NUMERIC):
|
|
144
153
|
return False
|
|
@@ -151,6 +160,8 @@ def schema_property_matches(expected: SchemaProperty | None, actual: SchemaPrope
|
|
|
151
160
|
if expected_base == "object":
|
|
152
161
|
if not expected.properties:
|
|
153
162
|
return True
|
|
163
|
+
# actual.properties is None for an untyped object (ibis map/variant): the
|
|
164
|
+
# empty lookup below fails every declared field, which is what we want.
|
|
154
165
|
actual_by_name = {p.name.lower(): p for p in (actual.properties or []) if p.name}
|
|
155
166
|
for exp_field in expected.properties:
|
|
156
167
|
if not exp_field.name:
|
|
@@ -197,13 +208,22 @@ def schema_property_mismatch_reasons(
|
|
|
197
208
|
exp_str = expected.logicalType or expected.physicalType
|
|
198
209
|
errors.append(f"{field_label}: expected type '{exp_str}' but the column type could not be determined")
|
|
199
210
|
return errors
|
|
200
|
-
|
|
201
211
|
expected_base = normalize_type_name(expected.logicalType or expected.physicalType)
|
|
202
212
|
actual_base = normalize_type_name(actual.logicalType or actual.physicalType)
|
|
203
213
|
|
|
204
214
|
if expected_base is None:
|
|
205
215
|
return errors
|
|
206
216
|
|
|
217
|
+
if actual_base is None:
|
|
218
|
+
exp_str = expected.logicalType or expected.physicalType
|
|
219
|
+
act_str = actual.physicalType or "unknown"
|
|
220
|
+
errors.append(
|
|
221
|
+
f"{field_label}: has type '{act_str}', but the contract specifies '{exp_str}'. "
|
|
222
|
+
f"A '{act_str}' value has no verifiable logical type. "
|
|
223
|
+
f"If this is intentional, specify `physicalType: {act_str}`."
|
|
224
|
+
)
|
|
225
|
+
return errors
|
|
226
|
+
|
|
207
227
|
if expected_base != actual_base and not (expected_base in _NUMERIC and actual_base in _NUMERIC):
|
|
208
228
|
exp_str = expected.logicalType or expected.physicalType
|
|
209
229
|
act_str = actual.logicalType or actual.physicalType
|
|
@@ -218,6 +238,12 @@ def schema_property_mismatch_reasons(
|
|
|
218
238
|
if expected_base == "object":
|
|
219
239
|
if not expected.properties:
|
|
220
240
|
return errors
|
|
241
|
+
if actual.properties is None:
|
|
242
|
+
errors.append(
|
|
243
|
+
f"{field_label}: declared with nested fields but the column is an untyped object "
|
|
244
|
+
"(map/variant) whose structure can't be verified; use a structured type or specify physicalType"
|
|
245
|
+
)
|
|
246
|
+
return errors
|
|
221
247
|
|
|
222
248
|
actual_by_name = {p.name.lower(): p for p in (actual.properties or []) if p.name}
|
|
223
249
|
for exp_field in expected.properties:
|
{datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/dtype_category.py
RENAMED
|
@@ -6,6 +6,8 @@ from typing import TYPE_CHECKING
|
|
|
6
6
|
|
|
7
7
|
from open_data_contract_standard.model import SchemaProperty
|
|
8
8
|
|
|
9
|
+
from datacontract.engines.checks.type_normalize import UNKNOWN_LOGICAL_TYPE
|
|
10
|
+
|
|
9
11
|
if TYPE_CHECKING:
|
|
10
12
|
from ibis.expr.datatypes import DataType
|
|
11
13
|
|
|
@@ -48,13 +50,14 @@ def ibis_dtype_category(dtype) -> str:
|
|
|
48
50
|
return "other"
|
|
49
51
|
|
|
50
52
|
|
|
51
|
-
def ibis_dtype_to_schema_property(dtype: DataType) -> SchemaProperty
|
|
53
|
+
def ibis_dtype_to_schema_property(dtype: DataType) -> SchemaProperty:
|
|
52
54
|
"""Map an ibis DataType to a SchemaProperty for structural type comparison.
|
|
53
55
|
|
|
54
56
|
Returns a ``SchemaProperty`` with ``logicalType`` set to one of the 9 ODCS
|
|
55
57
|
categories, recursively populating ``properties`` for structs and ``items``
|
|
56
|
-
for arrays.
|
|
57
|
-
|
|
58
|
+
for arrays. A type that carries no verifiable logical type (json, binary,
|
|
59
|
+
null, …) becomes ``UNKNOWN_LOGICAL_TYPE`` with the actual type kept in
|
|
60
|
+
``physicalType``, so the failure message can name it.
|
|
58
61
|
"""
|
|
59
62
|
try:
|
|
60
63
|
if dtype.is_boolean():
|
|
@@ -74,20 +77,25 @@ def ibis_dtype_to_schema_property(dtype: DataType) -> SchemaProperty | None:
|
|
|
74
77
|
if dtype.is_struct():
|
|
75
78
|
properties = []
|
|
76
79
|
for field_name, ftype in dtype.fields.items():
|
|
80
|
+
# an unverifiable field type is still a field: keep it, so it is not reported missing
|
|
77
81
|
child = ibis_dtype_to_schema_property(ftype)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
82
|
+
properties.append(
|
|
83
|
+
SchemaProperty(
|
|
84
|
+
name=field_name,
|
|
85
|
+
logicalType=child.logicalType,
|
|
86
|
+
physicalType=child.physicalType,
|
|
87
|
+
items=child.items,
|
|
88
|
+
properties=child.properties,
|
|
86
89
|
)
|
|
87
|
-
|
|
90
|
+
)
|
|
91
|
+
return SchemaProperty(logicalType="object", properties=properties)
|
|
88
92
|
if dtype.is_array():
|
|
89
93
|
element = ibis_dtype_to_schema_property(dtype.value_type)
|
|
90
94
|
return SchemaProperty(logicalType="array", items=element)
|
|
95
|
+
if dtype.is_map():
|
|
96
|
+
# base is confirmable, inner values are not (yet)
|
|
97
|
+
return SchemaProperty(logicalType="object", properties=None)
|
|
91
98
|
except AttributeError:
|
|
92
|
-
return
|
|
93
|
-
|
|
99
|
+
return SchemaProperty(logicalType=UNKNOWN_LOGICAL_TYPE)
|
|
100
|
+
# json holds a different type per row; binary and null have no ODCS category
|
|
101
|
+
return SchemaProperty(logicalType=UNKNOWN_LOGICAL_TYPE, physicalType=str(dtype))
|
{datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/ibis_check_execute.py
RENAMED
|
@@ -14,7 +14,7 @@ import uuid
|
|
|
14
14
|
from collections import defaultdict
|
|
15
15
|
from typing import List, Optional
|
|
16
16
|
|
|
17
|
-
from open_data_contract_standard.model import OpenDataContractStandard, Server
|
|
17
|
+
from open_data_contract_standard.model import OpenDataContractStandard, SchemaProperty, Server
|
|
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
|
|
@@ -22,6 +22,7 @@ from datacontract.engines.checks.type_normalize import schema_property_matches,
|
|
|
22
22
|
from datacontract.engines.ibis.connections.connect import connect_ibis
|
|
23
23
|
from datacontract.engines.ibis.dtype_category import ibis_dtype_to_schema_property
|
|
24
24
|
from datacontract.engines.ibis.native_type import fetch_native_types, sqlglot_dialect
|
|
25
|
+
from datacontract.engines.ibis.snowflake_structured_types import fetch_structured_types, has_nesting
|
|
25
26
|
from datacontract.model.exceptions import DataContractException
|
|
26
27
|
from datacontract.model.run import Check, ResultEnum, Run
|
|
27
28
|
from datacontract.model.server import get_server_type
|
|
@@ -196,6 +197,14 @@ def _run_model(
|
|
|
196
197
|
if any(spec.metric == MetricType.FIELD_PHYSICAL_TYPE for spec in specs):
|
|
197
198
|
native_types = fetch_native_types(con, server, model)
|
|
198
199
|
|
|
200
|
+
# Snowflake collapses structured OBJECT/ARRAY nesting in the ibis dtype; read
|
|
201
|
+
# the real nested types from SHOW COLUMNS so field_type checks can recurse.
|
|
202
|
+
structured_types = None
|
|
203
|
+
if get_server_type(server) == "snowflake" and any(
|
|
204
|
+
spec.metric in (MetricType.FIELD_TYPE, MetricType.FIELD_PHYSICAL_TYPE) for spec in specs
|
|
205
|
+
):
|
|
206
|
+
structured_types = fetch_structured_types(con, server, t.get_name())
|
|
207
|
+
|
|
199
208
|
agg_exprs = [] # list[(spec, named_expr)]
|
|
200
209
|
for spec in specs:
|
|
201
210
|
try:
|
|
@@ -219,9 +228,9 @@ def _run_model(
|
|
|
219
228
|
elif spec.metric == MetricType.FIELD_PRESENT:
|
|
220
229
|
_run_present(run, con, model, columns, spec)
|
|
221
230
|
elif spec.metric == MetricType.FIELD_TYPE:
|
|
222
|
-
_run_type(run, schema, columns, spec)
|
|
231
|
+
_run_type(run, schema, columns, spec, structured_types)
|
|
223
232
|
elif spec.metric == MetricType.FIELD_PHYSICAL_TYPE:
|
|
224
|
-
_run_physical_type(run, con, server, schema, columns, native_types, spec)
|
|
233
|
+
_run_physical_type(run, con, server, schema, columns, native_types, spec, structured_types)
|
|
225
234
|
elif spec.metric in (MetricType.FRESHNESS, MetricType.RETENTION):
|
|
226
235
|
_run_freshness(run, t, columns, spec)
|
|
227
236
|
elif spec.metric == MetricType.CUSTOM_SQL:
|
|
@@ -615,7 +624,7 @@ def _run_present(run: Run, con, model: str, columns, spec: CheckSpec):
|
|
|
615
624
|
)
|
|
616
625
|
|
|
617
626
|
|
|
618
|
-
def _run_type(run: Run, schema, columns, spec: CheckSpec):
|
|
627
|
+
def _run_type(run: Run, schema, columns, spec: CheckSpec, structured_types: dict[str, SchemaProperty] | None = None):
|
|
619
628
|
_set_impl(
|
|
620
629
|
run,
|
|
621
630
|
spec.key,
|
|
@@ -628,11 +637,19 @@ def _run_type(run: Run, schema, columns, spec: CheckSpec):
|
|
|
628
637
|
_set_result(run, spec.key, ResultEnum.failed, f"Column '{spec.field}' is missing")
|
|
629
638
|
return
|
|
630
639
|
dtype = schema[actual_col]
|
|
631
|
-
|
|
640
|
+
# Snowflake structured types come back collapsed from ibis; prefer the nested
|
|
641
|
+
# tree recovered from SHOW COLUMNS when available.
|
|
642
|
+
structured_prop = structured_types.get(spec.field.lower()) if structured_types else None
|
|
643
|
+
actual_prop = structured_prop or ibis_dtype_to_schema_property(dtype)
|
|
632
644
|
_set_diagnostics(
|
|
633
645
|
run,
|
|
634
646
|
spec.key,
|
|
635
|
-
_diag(
|
|
647
|
+
_diag(
|
|
648
|
+
metric="field_type",
|
|
649
|
+
field=spec.field,
|
|
650
|
+
expected=spec.expected_type_label,
|
|
651
|
+
actual=structured_prop.physicalType if structured_prop else str(dtype),
|
|
652
|
+
),
|
|
636
653
|
)
|
|
637
654
|
if schema_property_matches(spec.expected_schema_property, actual_prop):
|
|
638
655
|
_set_result(run, spec.key, ResultEnum.passed, None)
|
|
@@ -646,7 +663,16 @@ def _run_type(run: Run, schema, columns, spec: CheckSpec):
|
|
|
646
663
|
)
|
|
647
664
|
|
|
648
665
|
|
|
649
|
-
def _run_physical_type(
|
|
666
|
+
def _run_physical_type(
|
|
667
|
+
run: Run,
|
|
668
|
+
con,
|
|
669
|
+
server,
|
|
670
|
+
schema,
|
|
671
|
+
columns,
|
|
672
|
+
native_types,
|
|
673
|
+
spec: CheckSpec,
|
|
674
|
+
structured_types: dict[str, SchemaProperty] | None = None,
|
|
675
|
+
):
|
|
650
676
|
"""Compare a column's real native type against the contract's physicalType.
|
|
651
677
|
|
|
652
678
|
When the native type cannot be read for this backend, or the declared
|
|
@@ -668,7 +694,13 @@ def _run_physical_type(run: Run, con, server, schema, columns, native_types, spe
|
|
|
668
694
|
_set_result(run, spec.key, ResultEnum.failed, f"Column '{spec.field}' is missing")
|
|
669
695
|
return
|
|
670
696
|
|
|
671
|
-
|
|
697
|
+
# The catalog reports a structured OBJECT/ARRAY as its bare token, dropping the
|
|
698
|
+
# nested types; the tree recovered from SHOW COLUMNS renders the real native type.
|
|
699
|
+
structured_prop = structured_types.get(spec.field.lower()) if structured_types else None
|
|
700
|
+
if structured_prop is not None and has_nesting(structured_prop):
|
|
701
|
+
actual_native = structured_prop.physicalType
|
|
702
|
+
else:
|
|
703
|
+
actual_native = native_types.get(spec.field.lower()) if native_types else None
|
|
672
704
|
_set_diagnostics(
|
|
673
705
|
run,
|
|
674
706
|
spec.key,
|
|
@@ -697,16 +729,17 @@ def _run_physical_type(run: Run, con, server, schema, columns, native_types, spe
|
|
|
697
729
|
# logicalType category check when the property declares one.
|
|
698
730
|
fallback = spec.expected_schema_property
|
|
699
731
|
if fallback is not None and fallback.logicalType is not None:
|
|
700
|
-
actual_prop = ibis_dtype_to_schema_property(schema[actual_col])
|
|
732
|
+
actual_prop = structured_prop or ibis_dtype_to_schema_property(schema[actual_col])
|
|
701
733
|
if schema_property_matches(fallback, actual_prop):
|
|
702
734
|
_set_result(run, spec.key, ResultEnum.passed, None)
|
|
703
735
|
else:
|
|
704
736
|
mismatch = schema_property_mismatch_reason(fallback, actual_prop)
|
|
737
|
+
actual_label = actual_native or schema[actual_col]
|
|
705
738
|
_set_result(
|
|
706
739
|
run,
|
|
707
740
|
spec.key,
|
|
708
741
|
ResultEnum.failed,
|
|
709
|
-
mismatch or f"Expected type '{fallback.logicalType}' but column is '{
|
|
742
|
+
mismatch or f"Expected type '{fallback.logicalType}' but column is '{actual_label}'",
|
|
710
743
|
)
|
|
711
744
|
return
|
|
712
745
|
|
{datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/engines/ibis/native_type.py
RENAMED
|
@@ -124,6 +124,10 @@ def _rows(con, query: str):
|
|
|
124
124
|
try:
|
|
125
125
|
if hasattr(cursor, "fetchall"):
|
|
126
126
|
return list(cursor.fetchall())
|
|
127
|
+
# The pyspark backend (also used for databricks with a Spark session)
|
|
128
|
+
# returns a DataFrame; iterating it would yield Column objects.
|
|
129
|
+
if hasattr(cursor, "collect"):
|
|
130
|
+
return list(cursor.collect())
|
|
127
131
|
# Some backends (e.g. BigQuery) return an iterable result set
|
|
128
132
|
# (RowIterator) instead of a DBAPI cursor.
|
|
129
133
|
return list(cursor)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Rebuild Snowflake structured OBJECT/ARRAY nesting, which ibis collapses, from SHOW COLUMNS."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from open_data_contract_standard.model import SchemaProperty, Server
|
|
8
|
+
|
|
9
|
+
from datacontract.engines.checks.type_normalize import UNKNOWN_LOGICAL_TYPE
|
|
10
|
+
from datacontract.engines.ibis.native_type import _quote, _rows
|
|
11
|
+
|
|
12
|
+
# SHOW COLUMNS leaf ``type`` tokens -> ODCS logical type. FIXED and REAL both map
|
|
13
|
+
# to "number" (the comparator treats integer/number as compatible). Tokens not
|
|
14
|
+
# listed (BINARY, GEOGRAPHY, VARIANT, …) carry no verifiable logical type.
|
|
15
|
+
_LEAF_TYPES = {
|
|
16
|
+
"FIXED": "number",
|
|
17
|
+
"REAL": "number",
|
|
18
|
+
"TEXT": "string",
|
|
19
|
+
"BOOLEAN": "boolean",
|
|
20
|
+
"DATE": "date",
|
|
21
|
+
"TIME": "time",
|
|
22
|
+
"TIMESTAMP_NTZ": "timestamp",
|
|
23
|
+
"TIMESTAMP_LTZ": "timestamp",
|
|
24
|
+
"TIMESTAMP_TZ": "timestamp",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _to_property(node: dict) -> SchemaProperty:
|
|
29
|
+
"""Convert one ``data_type`` JSON node to a ``SchemaProperty``."""
|
|
30
|
+
node_type = node.get("type")
|
|
31
|
+
if node_type == "OBJECT":
|
|
32
|
+
fields = node.get("fields")
|
|
33
|
+
if not fields:
|
|
34
|
+
# untyped OBJECT: same shape as the collapsed ibis map
|
|
35
|
+
return SchemaProperty(logicalType="object", properties=None)
|
|
36
|
+
properties = []
|
|
37
|
+
for field in fields:
|
|
38
|
+
name = field.get("fieldName")
|
|
39
|
+
if not name:
|
|
40
|
+
continue
|
|
41
|
+
child = _to_property(field.get("fieldType") or {})
|
|
42
|
+
properties.append(
|
|
43
|
+
SchemaProperty(
|
|
44
|
+
name=name,
|
|
45
|
+
logicalType=child.logicalType,
|
|
46
|
+
physicalType=child.physicalType,
|
|
47
|
+
items=child.items,
|
|
48
|
+
properties=child.properties,
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
return SchemaProperty(logicalType="object", properties=properties or None)
|
|
52
|
+
if node_type == "ARRAY":
|
|
53
|
+
element = node.get("elementType")
|
|
54
|
+
# untyped ARRAY: no element type to recurse into
|
|
55
|
+
return SchemaProperty(logicalType="array", items=_to_property(element) if element else None)
|
|
56
|
+
if node_type == "MAP":
|
|
57
|
+
# dynamic keys can't be matched to named contract properties
|
|
58
|
+
return SchemaProperty(logicalType="object", properties=None)
|
|
59
|
+
logical = _LEAF_TYPES.get(node_type)
|
|
60
|
+
if logical:
|
|
61
|
+
return SchemaProperty(logicalType=logical)
|
|
62
|
+
# VARIANT, BINARY, GEOGRAPHY, …: keep the Snowflake token for the failure message
|
|
63
|
+
return SchemaProperty(logicalType=UNKNOWN_LOGICAL_TYPE, physicalType=node_type)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def has_nesting(prop: SchemaProperty) -> bool:
|
|
67
|
+
"""True only when the property is a structured OBJECT/ARRAY worth substituting."""
|
|
68
|
+
return bool(prop.properties) or prop.items is not None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _render_native(node: dict) -> str:
|
|
72
|
+
"""Render one ``data_type`` JSON node back to its Snowflake type string."""
|
|
73
|
+
node_type = node.get("type")
|
|
74
|
+
if node_type == "OBJECT":
|
|
75
|
+
fields = node.get("fields")
|
|
76
|
+
if not fields:
|
|
77
|
+
return "OBJECT"
|
|
78
|
+
rendered = [
|
|
79
|
+
f"{field['fieldName']} {_render_native(field.get('fieldType') or {})}"
|
|
80
|
+
for field in fields
|
|
81
|
+
if field.get("fieldName")
|
|
82
|
+
]
|
|
83
|
+
return "OBJECT({})".format(", ".join(rendered)) if rendered else "OBJECT"
|
|
84
|
+
if node_type == "ARRAY":
|
|
85
|
+
element = node.get("elementType")
|
|
86
|
+
return "ARRAY({})".format(_render_native(element)) if element else "ARRAY"
|
|
87
|
+
if node_type == "MAP":
|
|
88
|
+
key, value = node.get("keyType"), node.get("valueType")
|
|
89
|
+
if key and value:
|
|
90
|
+
return "MAP({}, {})".format(_render_native(key), _render_native(value))
|
|
91
|
+
return "MAP"
|
|
92
|
+
if node_type == "FIXED":
|
|
93
|
+
return "NUMBER({},{})".format(node.get("precision", 38), node.get("scale", 0))
|
|
94
|
+
if node_type == "REAL":
|
|
95
|
+
return "FLOAT"
|
|
96
|
+
if node_type == "TEXT":
|
|
97
|
+
length = node.get("length")
|
|
98
|
+
return f"VARCHAR({length})" if length is not None else "VARCHAR"
|
|
99
|
+
return str(node_type)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def fetch_structured_types(con, server: Server, table_name: str) -> dict[str, SchemaProperty] | None:
|
|
103
|
+
"""Return ``{column_name_lower: SchemaProperty}`` for the columns whose real type
|
|
104
|
+
the collapsed ibis dtype does not convey: structured OBJECT/ARRAY, and leaves with
|
|
105
|
+
no verifiable logical type. Other columns are omitted. Any failure returns ``None``.
|
|
106
|
+
"""
|
|
107
|
+
quoted_table = '"{}"'.format(table_name.replace('"', '""'))
|
|
108
|
+
path = ".".join(part for part in (server.database, server.schema_, quoted_table) if part)
|
|
109
|
+
identifier = "IDENTIFIER('{}')".format(_quote(path))
|
|
110
|
+
rows = _rows(con, f"SHOW COLUMNS IN TABLE {identifier}")
|
|
111
|
+
if not rows:
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
# SHOW COLUMNS columns: table_name, schema_name, column_name, data_type, ...
|
|
115
|
+
result: dict[str, SchemaProperty] = {}
|
|
116
|
+
for row in rows:
|
|
117
|
+
column_name, data_type = row[2], row[3]
|
|
118
|
+
if not column_name or not data_type:
|
|
119
|
+
continue
|
|
120
|
+
try:
|
|
121
|
+
node = json.loads(data_type)
|
|
122
|
+
except (TypeError, ValueError):
|
|
123
|
+
continue
|
|
124
|
+
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:
|
|
129
|
+
# scalars and untyped OBJECT/ARRAY: the collapsed ibis dtype says the same
|
|
130
|
+
continue
|
|
131
|
+
# an unverifiable leaf (VARIANT, GEOGRAPHY, …) keeps its Snowflake token, which
|
|
132
|
+
# the ibis dtype renders as the useless 'json'
|
|
133
|
+
result[str(column_name).lower()] = prop
|
|
134
|
+
return result or None
|
{datacontract_cli-1.0.10 → datacontract_cli-1.0.12}/datacontract/imports/bigquery_importer.py
RENAMED
|
@@ -261,9 +261,9 @@ def map_type_from_bigquery(bigquery_type_str: str) -> str:
|
|
|
261
261
|
"STRING": "string",
|
|
262
262
|
"BYTES": "array",
|
|
263
263
|
"INTEGER": "integer",
|
|
264
|
-
"INT64": "integer",
|
|
264
|
+
"INT64": "integer", # for dbt-bigquery
|
|
265
265
|
"FLOAT": "number",
|
|
266
|
-
"FLOAT64": "number",
|
|
266
|
+
"FLOAT64": "number", # for dbt-bigquery
|
|
267
267
|
"BOOLEAN": "boolean",
|
|
268
268
|
"BOOL": "boolean",
|
|
269
269
|
"TIMESTAMP": "timestamp",
|
|
@@ -274,6 +274,7 @@ def map_type_from_bigquery(bigquery_type_str: str) -> str:
|
|
|
274
274
|
"BIGNUMERIC": "number",
|
|
275
275
|
"GEOGRAPHY": "object",
|
|
276
276
|
"JSON": "object",
|
|
277
|
+
"INTERVAL": "string",
|
|
277
278
|
}
|
|
278
279
|
|
|
279
280
|
if bigquery_type_str in type_mapping:
|
|
@@ -206,15 +206,18 @@ def _resolve_definition(url: str, type_: str) -> SchemaProperty:
|
|
|
206
206
|
if url in _definition_cache:
|
|
207
207
|
return _definition_cache[url]
|
|
208
208
|
|
|
209
|
-
target_url, headers = _build_request(url, type_)
|
|
209
|
+
target_url, headers, host_hint = _build_request(url, type_)
|
|
210
210
|
|
|
211
211
|
try:
|
|
212
212
|
response = requests.get(target_url, headers=headers, timeout=10)
|
|
213
213
|
except requests.RequestException as e:
|
|
214
|
-
raise _definition_resolution_error(url, target_url, str(e), original_exception=e)
|
|
214
|
+
raise _definition_resolution_error(url, target_url, str(e), original_exception=e, hint=host_hint)
|
|
215
215
|
|
|
216
216
|
if response.status_code != 200:
|
|
217
|
-
|
|
217
|
+
# 401/403 here almost always means the configured host is the wrong
|
|
218
|
+
# deployment for this IRI, so surface the ENTROPY_DATA_HOST hint.
|
|
219
|
+
hint = host_hint if response.status_code in (401, 403) else None
|
|
220
|
+
raise _definition_resolution_error(url, target_url, f"HTTP {response.status_code} {response.reason}", hint=hint)
|
|
218
221
|
|
|
219
222
|
try:
|
|
220
223
|
definition = SchemaProperty.model_validate_json(response.content)
|
|
@@ -227,8 +230,13 @@ def _resolve_definition(url: str, type_: str) -> SchemaProperty:
|
|
|
227
230
|
return definition
|
|
228
231
|
|
|
229
232
|
|
|
230
|
-
def _build_request(url: str, type_: str) -> tuple[str, dict[str, str]]:
|
|
231
|
-
"""Return the URL to fetch
|
|
233
|
+
def _build_request(url: str, type_: str) -> tuple[str, dict[str, str], str | None]:
|
|
234
|
+
"""Return the URL to fetch, the headers to use, and an optional host hint.
|
|
235
|
+
|
|
236
|
+
The third element is a copy-pasteable ENTROPY_DATA_HOST suggestion that
|
|
237
|
+
callers append to any auth/transport error from the lookup. It is only set
|
|
238
|
+
for the off-host semantics IRI case below, where a host mismatch is the most
|
|
239
|
+
common reason the lookup fails (401/403); it is None otherwise.
|
|
232
240
|
|
|
233
241
|
Three cases:
|
|
234
242
|
- URL on the configured host (relative path or matching absolute URL):
|
|
@@ -252,25 +260,26 @@ def _build_request(url: str, type_: str) -> tuple[str, dict[str, str]]:
|
|
|
252
260
|
api_key = _get_api_key_or_none()
|
|
253
261
|
if api_key is not None:
|
|
254
262
|
headers["x-api-key"] = api_key
|
|
255
|
-
return direct_url, headers
|
|
263
|
+
return direct_url, headers, None
|
|
256
264
|
|
|
257
265
|
if type_ == "definition":
|
|
258
266
|
# Third-party REST URL: fetch anonymously, no IRI fallback.
|
|
259
|
-
return direct_url, headers
|
|
267
|
+
return direct_url, headers, None
|
|
260
268
|
|
|
261
269
|
# Off-host semantics reference: IRI lookup against the configured host.
|
|
270
|
+
host_hint = _host_mismatch_hint(url, configured_host)
|
|
262
271
|
api_key = _get_api_key_or_none()
|
|
263
272
|
if api_key is None:
|
|
264
273
|
raise _definition_resolution_error(
|
|
265
274
|
url,
|
|
266
275
|
f"{configured_host.rstrip('/')}/api/semantics",
|
|
267
|
-
"the reference looks like an IRI
|
|
268
|
-
"
|
|
269
|
-
|
|
276
|
+
"the reference looks like an IRI, so it is resolved through /api/semantics, "
|
|
277
|
+
"which requires an API key: set ENTROPY_DATA_API_KEY",
|
|
278
|
+
hint=host_hint,
|
|
270
279
|
)
|
|
271
280
|
headers["x-api-key"] = api_key
|
|
272
281
|
lookup_url = f"{configured_host.rstrip('/')}/api/semantics?iri={quote(url, safe='')}"
|
|
273
|
-
return lookup_url, headers
|
|
282
|
+
return lookup_url, headers, host_hint
|
|
274
283
|
|
|
275
284
|
|
|
276
285
|
def _apply_definition_to_property(prop: SchemaProperty, definition: SchemaProperty):
|
|
@@ -291,10 +300,29 @@ def _hosts_match(url: str, host: str) -> bool:
|
|
|
291
300
|
return urlparse(url).netloc == urlparse(host).netloc
|
|
292
301
|
|
|
293
302
|
|
|
303
|
+
def _host_mismatch_hint(url: str, configured_host: str) -> str:
|
|
304
|
+
"""Actionable hint for the usual cause of a failed IRI lookup: the
|
|
305
|
+
configured entropy-data host (default https://api.entropy-data.com) is not
|
|
306
|
+
the deployment that serves this IRI. Names the exact ENTROPY_DATA_HOST value
|
|
307
|
+
to set -- derived from the IRI's own host -- so the fix is copy-pasteable
|
|
308
|
+
instead of leaving the user to guess that the host, not the API key, is wrong.
|
|
309
|
+
"""
|
|
310
|
+
iri = urlparse(url)
|
|
311
|
+
suggested = f"{iri.scheme}://{iri.netloc}" if iri.scheme and iri.netloc else iri.netloc
|
|
312
|
+
return (
|
|
313
|
+
f"the IRI's host '{iri.netloc}' does not match the configured entropy-data host "
|
|
314
|
+
f"'{urlparse(configured_host).netloc}'; if your contract is served from "
|
|
315
|
+
f"'{iri.netloc}', set ENTROPY_DATA_HOST={suggested} so the /api/semantics lookup "
|
|
316
|
+
f"and your API key target that deployment"
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
294
320
|
def _definition_resolution_error(
|
|
295
|
-
url: str, target_url: str, detail: str, original_exception: Exception | None = None
|
|
321
|
+
url: str, target_url: str, detail: str, original_exception: Exception | None = None, hint: str | None = None
|
|
296
322
|
) -> DataContractException:
|
|
297
323
|
reason = f"Could not resolve business definition '{url}' from {target_url}: {detail}"
|
|
324
|
+
if hint:
|
|
325
|
+
reason = f"{reason} — {hint}"
|
|
298
326
|
logging.warning(reason)
|
|
299
327
|
return DataContractException(
|
|
300
328
|
type="lint",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.12
|
|
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
|
|
@@ -133,6 +133,7 @@ datacontract/engines/ibis/__init__.py
|
|
|
133
133
|
datacontract/engines/ibis/dtype_category.py
|
|
134
134
|
datacontract/engines/ibis/ibis_check_execute.py
|
|
135
135
|
datacontract/engines/ibis/native_type.py
|
|
136
|
+
datacontract/engines/ibis/snowflake_structured_types.py
|
|
136
137
|
datacontract/engines/ibis/connections/__init__.py
|
|
137
138
|
datacontract/engines/ibis/connections/connect.py
|
|
138
139
|
datacontract/engines/ibis/connections/duckdb_connection.py
|
|
@@ -328,6 +329,7 @@ tests/test_require_env.py
|
|
|
328
329
|
tests/test_resolve.py
|
|
329
330
|
tests/test_resolve_definitions.py
|
|
330
331
|
tests/test_roundtrip_jsonschema.py
|
|
332
|
+
tests/test_snowflake_structured_types.py
|
|
331
333
|
tests/test_sql_type_converter_physicaltype.py
|
|
332
334
|
tests/test_test_api.py
|
|
333
335
|
tests/test_test_athena_iceberg.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datacontract-cli"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.12"
|
|
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"
|