datacontract-cli 1.0.4__tar.gz → 1.0.6__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.4/datacontract_cli.egg-info → datacontract_cli-1.0.6}/PKG-INFO +1 -1
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/checks/check_spec.py +6 -2
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/checks/create_checks.py +4 -10
- datacontract_cli-1.0.6/datacontract/engines/checks/type_normalize.py +214 -0
- datacontract_cli-1.0.6/datacontract/engines/ibis/dtype_category.py +93 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/ibis_check_execute.py +45 -15
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/dcs_importer.py +15 -8
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6/datacontract_cli.egg-info}/PKG-INFO +1 -1
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract_cli.egg-info/SOURCES.txt +1 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/pyproject.toml +1 -1
- datacontract_cli-1.0.6/tests/test_ibis_oracle_schema.py +98 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_diagnostics.py +4 -2
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_parquet.py +1 -1
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_type_normalize.py +1 -11
- datacontract_cli-1.0.4/datacontract/engines/checks/type_normalize.py +0 -139
- datacontract_cli-1.0.4/datacontract/engines/ibis/dtype_category.py +0 -41
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/LICENSE +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/MANIFEST.in +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/README.md +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/api.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/catalog/catalog.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/changelog/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/changelog/changelog.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/changelog/normalize.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/cli.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_api.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_catalog.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_changelog.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_ci.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_dbt.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_edit.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_export.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_import.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_init.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_lint.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_publish.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/command_test.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/data_contract.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/VERSION +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/abap-Bs8kvjsq.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/apex-Dspwrl5m.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/azcli-k1BiOau1.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/bat-BIP72KWc.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/bicep-VhQeYhS3.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/cameligo-DnuAXtHg.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/clojure-BAuDPsal.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/coffee-BV06qSnj.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/cpp-Cz8Jeyrf.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/csharp-F6hhlXFb.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/csp-KzlEHCyI.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/css-e4FKntZ3.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/cssMode-BNkTa2xp.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/cypher-CpvDGKRr.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/dart-DdHeFWR0.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/datacontract-editor.css +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/datacontract-editor.es.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/dockerfile-aoNXDcio.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/ecl-C4Q0DYuA.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/elixir-C9X42b0T.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/flow9-Bff42pfB.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/freemarker2-Dyfzmb5A.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/fsharp-C6vPAsHG.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/go-DEr8zx9f.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/graphql-BiNBBRFh.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/handlebars-BtDNI-uC.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/hcl-2T9lKuFg.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/html-Cn4TGw_o.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/htmlMode-Bf84vbo2.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/index.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/ini-CZGtssYM.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/java-B260NeH3.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/javascript-B86Kac07.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/jsonMode-Ckgg5lAE.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/julia-kuNLM9c5.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/kotlin-Bz6kAefA.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/less-AZUtS89I.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/lexon-BcmgnyRb.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/liquid-D0NPwuu_.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/lua-Dz1RbATg.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/m3-CIMooLFn.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/markdown-C1BsCK9P.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/mdx-QFRSBtVQ.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/mips-BovsnfLQ.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/monaco-4.7.0.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/msdax-CiRB2ZB-.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/mysql-BwdpPE19.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/objective-c-D4nfHfso.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/odcs.svg +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/pascal--j5-PYtz.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/pascaligo-C7TcJxNL.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/perl-BzEWqUb5.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/pgsql-B_KZ0mGX.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/php-A19QHzQV.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/pla-COeKY1hA.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/postiats-BfMp7zJL.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/powerquery-B0TS_5Gb.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/powershell-5jSbKdYB.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/protobuf-YgnOutn3.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/pug-DLej6kn5.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/python-C8RW9B6A.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/qsharp-AhjqtSHB.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/r-D-F4P80w.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/razor-CLZqdY_r.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/redis-hwwIlMnV.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/redshift-Bcm_kjEG.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/restructuredtext-CrdzfPP-.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/ruby-QC2UNm1s.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/rust-5aqiQ3L5.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/sb-B1g1ZfLJ.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/scala-C2U4R5Gb.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/scheme-DeFRbslr.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/scss-RSTCiCmI.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/shell-BpF-iNu8.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/solidity-C00r2mbQ.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/sophia-DVW5ZKDB.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/sparql-B0nmpxeX.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/sql-CJwKPERn.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/st-DPlKG5DT.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/swift-YZBAbVHV.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/systemverilog-CDQSaH63.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/tcl-Dlu8sp6Q.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/tsMode-yleMwhPq.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/twig-C5TO7-kw.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/typescript-CJBeebKU.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/typespec-BsmjDEu7.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/vb-ChHvIDrk.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/wgsl-XEp1ju8c.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/xml-vC-NMVX1.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/editor_assets/yaml-Dlf2VF-T.js +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/checks/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/data_contract_test.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/connections/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/connections/connect.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/connections/duckdb_connection.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/connections/kafka.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/avro_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/avro_idl_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/bigquery_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/custom_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/data_caterer_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/dbml_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/dbt_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/dcs_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/dqx_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/duckdb_type_converter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/excel_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/exporter_factory.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/go_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/great_expectations_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/html_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/iceberg_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/jsonschema_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/markdown_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/mermaid_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/odcs_export_helper.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/odcs_v3_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/pandas_type_converter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/protobuf_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/pydantic_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/rdf_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/sodacl_check_builder.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/sodacl_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/spark_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/sql_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/sql_type_converter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/export/sqlalchemy_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/avro_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/bigquery_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/csv_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/dbml_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/dbt_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/excel_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/glue_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/iceberg_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/importer_factory.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/json_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/jsonschema_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/odcs_helper.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/odcs_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/parquet_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/powerbi_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/protobuf_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/snowflake_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/spark_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/sql_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/imports/unity_importer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/init/init_template.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/integration/dbt_sync.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/integration/dbt_test_mapping.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/integration/entropy_data.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/lint/files.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/lint/resolve.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/lint/resources.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/lint/schema.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/lint/urls.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/model/changelog.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/model/exceptions.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/model/odcs.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/model/run.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/model/server.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/output/__init__.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/output/ci_output.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/output/json_test_results.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/output/junit_test_results.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/output/output_format.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/output/test_results_writer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/output/text_changelog_results.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/py.typed +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/odcs-3.1.0.init.yaml +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/datacontract.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/datacontract_odcs.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/index.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/datacontract_information.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/datacontract_terms.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/definition.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/example.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/model_field.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/quality.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/partials/server.html +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/templates/style/output.css +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract_cli.egg-info/dependency_links.txt +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract_cli.egg-info/entry_points.txt +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract_cli.egg-info/requires.txt +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract_cli.egg-info/top_level.txt +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/setup.cfg +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_api.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_catalog.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_changelog.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_changelog_engine.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_changelog_normalize.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_changelog_output_text.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_ci_output.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_cli.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_connect_databricks.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_connect_sqlserver.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_connect_trino.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_data_contract.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_data_contract_checks.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_data_contract_specification.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_dbt_sync.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_dbt_test_mapping.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_description_linter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_download_datacontract_file.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_duckdb_json.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_edit.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_avro.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_avro_idl.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_bigquery.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_complex_data_contract.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_custom.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_custom_exporter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_custom_model.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_data_caterer.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_dbml.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_dbt_models.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_dbt_sources.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_dbt_staging_sql.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_dqx.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_excel.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_go.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_great_expectations.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_html.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_iceberg.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_jsonschema.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_markdown.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_mermaid.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_odcs_v3.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_protobuf.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_pydantic.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_rdf.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_sodacl.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_spark.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_sql.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_sql_clickhouse.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_sql_query.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_export_sqlalchemy.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_ibis_mssql_pattern.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_avro.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_bigquery.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_csv.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_dbml.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_dbt.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_excel.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_glue.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_iceberg.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_json.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_jsonschema.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_odcs_v3.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_parquet.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_powerbi.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_protobuf.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_snowflake.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_spark.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_sql_oracle.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_sql_postgres.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_sql_snowflake.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_sql_sqlserver.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_import_unity_file.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_integration_entropydata.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_lint.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_oracle_patch.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_require_env.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_resolve.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_resolve_definitions.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_roundtrip_jsonschema.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_sql_type_converter_physicaltype.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_api.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_athena_iceberg.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_azure_blob_file.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_azure_remote.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_bigquery.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_checks_filter.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_databricks.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_dataframe.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_delta.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_failed_samples.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_gcs_csv_remote.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_gcs_json_remote.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_kafka.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_kafka_remote.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_local_json.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_local_json_nd.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_mysql.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_oracle.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_oracle_xe.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_output_json.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_output_junit.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_postgres.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_quality.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_quality_local_fallback.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_quality_percent_severity.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_s3_csv.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_s3_delta.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_s3_json.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_s3_json_complex.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_s3_json_multiple_models.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_s3_json_remote.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_schema_evolution.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_server_not_found.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_snowflake.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_soda_connection_error.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/tests/test_test_sqlserver.py +0 -0
- {datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/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.6
|
|
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
|
|
@@ -14,7 +14,10 @@ from __future__ import annotations
|
|
|
14
14
|
|
|
15
15
|
from dataclasses import dataclass
|
|
16
16
|
from enum import Enum
|
|
17
|
-
from typing import Any, List, Optional
|
|
17
|
+
from typing import TYPE_CHECKING, Any, List, Optional
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from open_data_contract_standard.model import SchemaProperty
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
class MetricType(str, Enum):
|
|
@@ -116,8 +119,9 @@ class CheckSpec:
|
|
|
116
119
|
valid_min_length: Optional[int] = None # INVALID_COUNT
|
|
117
120
|
valid_max_length: Optional[int] = None # INVALID_COUNT
|
|
118
121
|
|
|
119
|
-
expected_category: Optional[str] = None # FIELD_TYPE:
|
|
122
|
+
expected_category: Optional[str] = None # FIELD_TYPE: human-readable label (display only)
|
|
120
123
|
expected_type_label: Optional[str] = None # FIELD_TYPE: human-readable expected type
|
|
124
|
+
expected_schema_property: Optional["SchemaProperty"] = None # FIELD_TYPE: structural comparison
|
|
121
125
|
|
|
122
126
|
columns: Optional[List[str]] = None # DUPLICATE_COUNT across multiple columns
|
|
123
127
|
|
{datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/checks/create_checks.py
RENAMED
|
@@ -22,7 +22,6 @@ 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
|
|
26
25
|
|
|
27
26
|
logger = logging.getLogger(__name__)
|
|
28
27
|
|
|
@@ -54,12 +53,6 @@ def to_schema_name(schema_object: SchemaObject, server_type: Optional[str]) -> s
|
|
|
54
53
|
return schema_object.name
|
|
55
54
|
|
|
56
55
|
|
|
57
|
-
def expected_type_category(prop: SchemaProperty) -> tuple[str, str]:
|
|
58
|
-
"""Return (normalized category, human label) for a property's declared type."""
|
|
59
|
-
label = prop.physicalType or prop.logicalType
|
|
60
|
-
return normalize_type_name(label), (label or "")
|
|
61
|
-
|
|
62
|
-
|
|
63
56
|
_PERCENT_UNITS = {"percent", "percentage", "%"}
|
|
64
57
|
|
|
65
58
|
|
|
@@ -178,8 +171,8 @@ def _to_schema_checks(schema_object: SchemaObject, server: Optional[Server]) ->
|
|
|
178
171
|
)
|
|
179
172
|
)
|
|
180
173
|
|
|
181
|
-
if check_types and
|
|
182
|
-
|
|
174
|
+
if check_types and prop.logicalType is not None:
|
|
175
|
+
schema_prop, label = prop, prop.logicalType or ""
|
|
183
176
|
checks.append(
|
|
184
177
|
CheckSpec(
|
|
185
178
|
key=f"{model}__{field}__field_type",
|
|
@@ -189,8 +182,9 @@ def _to_schema_checks(schema_object: SchemaObject, server: Optional[Server]) ->
|
|
|
189
182
|
model=model,
|
|
190
183
|
field=field,
|
|
191
184
|
metric=MetricType.FIELD_TYPE,
|
|
192
|
-
expected_category=
|
|
185
|
+
expected_category=label,
|
|
193
186
|
expected_type_label=label,
|
|
187
|
+
expected_schema_property=schema_prop,
|
|
194
188
|
)
|
|
195
189
|
)
|
|
196
190
|
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Type normalization and structural comparison for schema ``field_type`` checks.
|
|
2
|
+
|
|
3
|
+
``normalize_type_name`` maps a raw type string (logical or physical) to one of
|
|
4
|
+
the nine ODCS logical-type categories.
|
|
5
|
+
|
|
6
|
+
``schema_property_matches`` compares two ``SchemaProperty`` trees — one from the
|
|
7
|
+
contract, one reconstructed from the ibis-reported dtype — and returns True when
|
|
8
|
+
the actual type is structurally compatible with the expected one.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
from open_data_contract_standard.model import SchemaProperty
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def normalize_type_name(type_name: str | None) -> str | None:
|
|
19
|
+
"""Map a contract type name (logical or physical) to one of the 9 ODCS categories.
|
|
20
|
+
|
|
21
|
+
Returns ``None`` for types that are unsupported or unrecognized (binary,
|
|
22
|
+
map, null, interval …) so they can be silently ignored rather than
|
|
23
|
+
producing false type-check failures.
|
|
24
|
+
"""
|
|
25
|
+
if not type_name:
|
|
26
|
+
return None
|
|
27
|
+
name = type_name.strip().lower()
|
|
28
|
+
# strip parameters like varchar(10) / decimal(10,2) and array<...> wrappers
|
|
29
|
+
name = re.sub(r"\(.*\)", "", name)
|
|
30
|
+
name = re.sub(r"<.*>", "", name).strip()
|
|
31
|
+
|
|
32
|
+
if name in {
|
|
33
|
+
"varchar",
|
|
34
|
+
"varchar2",
|
|
35
|
+
"char",
|
|
36
|
+
"character",
|
|
37
|
+
"character varying",
|
|
38
|
+
"nvarchar",
|
|
39
|
+
"nvarchar2",
|
|
40
|
+
"nchar",
|
|
41
|
+
"text",
|
|
42
|
+
"string",
|
|
43
|
+
"str",
|
|
44
|
+
"clob",
|
|
45
|
+
"nclob",
|
|
46
|
+
"uuid",
|
|
47
|
+
"enum",
|
|
48
|
+
}:
|
|
49
|
+
return "string"
|
|
50
|
+
if name in {
|
|
51
|
+
"int",
|
|
52
|
+
"integer",
|
|
53
|
+
"bigint",
|
|
54
|
+
"smallint",
|
|
55
|
+
"tinyint",
|
|
56
|
+
"long",
|
|
57
|
+
"short",
|
|
58
|
+
"int2",
|
|
59
|
+
"int4",
|
|
60
|
+
"int8",
|
|
61
|
+
"serial",
|
|
62
|
+
"bigserial",
|
|
63
|
+
"smallserial",
|
|
64
|
+
"int64",
|
|
65
|
+
"int32",
|
|
66
|
+
"int16",
|
|
67
|
+
"int8",
|
|
68
|
+
"byteint",
|
|
69
|
+
}:
|
|
70
|
+
return "integer"
|
|
71
|
+
if name in {
|
|
72
|
+
"decimal",
|
|
73
|
+
"numeric",
|
|
74
|
+
"dec",
|
|
75
|
+
"float",
|
|
76
|
+
"double",
|
|
77
|
+
"double precision",
|
|
78
|
+
"real",
|
|
79
|
+
"float4",
|
|
80
|
+
"float8",
|
|
81
|
+
"float32",
|
|
82
|
+
"float64",
|
|
83
|
+
"binary_float",
|
|
84
|
+
"binary_double",
|
|
85
|
+
"number",
|
|
86
|
+
}:
|
|
87
|
+
return "number"
|
|
88
|
+
if name in {"bool", "boolean", "bit", "logical"}:
|
|
89
|
+
return "boolean"
|
|
90
|
+
if name in {
|
|
91
|
+
"timestamp",
|
|
92
|
+
"timestamptz",
|
|
93
|
+
"timestamp without time zone",
|
|
94
|
+
"timestamp with time zone",
|
|
95
|
+
"timestamp_tz",
|
|
96
|
+
"timestamp_ntz",
|
|
97
|
+
"timestamp_ltz",
|
|
98
|
+
"datetime",
|
|
99
|
+
"datetime2",
|
|
100
|
+
"smalldatetime",
|
|
101
|
+
}:
|
|
102
|
+
return "timestamp"
|
|
103
|
+
if name in {"date"}:
|
|
104
|
+
return "date"
|
|
105
|
+
if name in {"time", "time without time zone", "time with time zone"}:
|
|
106
|
+
return "time"
|
|
107
|
+
if name in {"struct", "record", "object", "row", "json", "jsonb", "variant"}:
|
|
108
|
+
return "object"
|
|
109
|
+
if name in {"array", "list"}:
|
|
110
|
+
return "array"
|
|
111
|
+
# binary, map, null, interval and other unrecognized types are not in the
|
|
112
|
+
# 9 allowed categories; return None so they are silently ignored.
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
_NUMERIC = {"integer", "number"}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def schema_property_matches(expected: SchemaProperty | None, actual: SchemaProperty | None) -> bool:
|
|
120
|
+
"""Return True if ``actual`` is structurally compatible with ``expected``.
|
|
121
|
+
|
|
122
|
+
Lenient by design:
|
|
123
|
+
|
|
124
|
+
- If expected is ``None`` (unsupported/unrecognized type) always passes.
|
|
125
|
+
- ``integer`` and ``number`` are mutually compatible (ODCS "number" is
|
|
126
|
+
intentionally ambiguous across numeric storage classes).
|
|
127
|
+
- A bare ``object`` or ``array`` on the expected side (no nested detail)
|
|
128
|
+
matches any actual structure with the same base (underdeclared contract).
|
|
129
|
+
- Extra actual fields inside an ``object`` are ignored.
|
|
130
|
+
"""
|
|
131
|
+
if expected is None:
|
|
132
|
+
return True
|
|
133
|
+
if actual is None:
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
expected_base = normalize_type_name(expected.logicalType or expected.physicalType)
|
|
137
|
+
actual_base = normalize_type_name(actual.logicalType or actual.physicalType)
|
|
138
|
+
|
|
139
|
+
if expected_base is None:
|
|
140
|
+
return True
|
|
141
|
+
if actual_base is None:
|
|
142
|
+
return False
|
|
143
|
+
if expected_base != actual_base and not (expected_base in _NUMERIC and actual_base in _NUMERIC):
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
if expected_base == "array":
|
|
147
|
+
if expected.items is None:
|
|
148
|
+
return True
|
|
149
|
+
return schema_property_matches(expected.items, actual.items)
|
|
150
|
+
|
|
151
|
+
if expected_base == "object":
|
|
152
|
+
if not expected.properties:
|
|
153
|
+
return True
|
|
154
|
+
actual_by_name = {p.name.lower(): p for p in (actual.properties or []) if p.name}
|
|
155
|
+
for exp_field in expected.properties:
|
|
156
|
+
if not exp_field.name:
|
|
157
|
+
continue
|
|
158
|
+
act_field = actual_by_name.get(exp_field.name.lower())
|
|
159
|
+
if act_field is None:
|
|
160
|
+
return False
|
|
161
|
+
if not schema_property_matches(exp_field, act_field):
|
|
162
|
+
return False
|
|
163
|
+
return True
|
|
164
|
+
|
|
165
|
+
return True
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def schema_property_mismatch_reason(
|
|
169
|
+
expected: SchemaProperty | None,
|
|
170
|
+
actual: SchemaProperty | None,
|
|
171
|
+
path: str = "",
|
|
172
|
+
) -> str:
|
|
173
|
+
"""Return a human-readable description of the first structural mismatch, or '' if none."""
|
|
174
|
+
if expected is None:
|
|
175
|
+
return ""
|
|
176
|
+
field_label = f"field '{path}'" if path else "column"
|
|
177
|
+
if actual is None:
|
|
178
|
+
exp_str = expected.logicalType or expected.physicalType
|
|
179
|
+
return f"{field_label}: expected type '{exp_str}' but the column type could not be determined"
|
|
180
|
+
|
|
181
|
+
expected_base = normalize_type_name(expected.logicalType or expected.physicalType)
|
|
182
|
+
actual_base = normalize_type_name(actual.logicalType or actual.physicalType)
|
|
183
|
+
|
|
184
|
+
if expected_base is None:
|
|
185
|
+
return ""
|
|
186
|
+
|
|
187
|
+
if expected_base != actual_base and not (expected_base in _NUMERIC and actual_base in _NUMERIC):
|
|
188
|
+
exp_str = expected.logicalType or expected.physicalType
|
|
189
|
+
act_str = actual.logicalType or actual.physicalType
|
|
190
|
+
return f"{field_label}: expected type '{exp_str}' but got '{act_str}'"
|
|
191
|
+
|
|
192
|
+
if expected_base == "array":
|
|
193
|
+
if expected.items is not None:
|
|
194
|
+
child_path = f"{path}[]" if path else "[]"
|
|
195
|
+
return schema_property_mismatch_reason(expected.items, actual.items, child_path)
|
|
196
|
+
return ""
|
|
197
|
+
|
|
198
|
+
if expected_base == "object":
|
|
199
|
+
if not expected.properties:
|
|
200
|
+
return ""
|
|
201
|
+
actual_by_name = {p.name.lower(): p for p in (actual.properties or []) if p.name}
|
|
202
|
+
for exp_field in expected.properties:
|
|
203
|
+
if not exp_field.name:
|
|
204
|
+
continue
|
|
205
|
+
child_path = f"{path}.{exp_field.name}" if path else exp_field.name
|
|
206
|
+
act_field = actual_by_name.get(exp_field.name.lower())
|
|
207
|
+
if act_field is None:
|
|
208
|
+
return f"field '{child_path}' is missing"
|
|
209
|
+
reason = schema_property_mismatch_reason(exp_field, act_field, child_path)
|
|
210
|
+
if reason:
|
|
211
|
+
return reason
|
|
212
|
+
return ""
|
|
213
|
+
|
|
214
|
+
return ""
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Map an ibis dtype to the coarse category used by ``field_type`` checks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from open_data_contract_standard.model import SchemaProperty
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ibis.expr.datatypes import DataType
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def ibis_dtype_category(dtype) -> str:
|
|
14
|
+
"""Return the normalized category for an ibis ``DataType``.
|
|
15
|
+
|
|
16
|
+
Order matters: boolean is checked before integer (some engines model bool as
|
|
17
|
+
a 1-bit int), and decimal before floating.
|
|
18
|
+
"""
|
|
19
|
+
try:
|
|
20
|
+
if dtype.is_boolean():
|
|
21
|
+
return "boolean"
|
|
22
|
+
if dtype.is_integer():
|
|
23
|
+
return "integer"
|
|
24
|
+
if dtype.is_decimal():
|
|
25
|
+
return "decimal"
|
|
26
|
+
if dtype.is_floating():
|
|
27
|
+
return "float"
|
|
28
|
+
if dtype.is_string():
|
|
29
|
+
return "string"
|
|
30
|
+
if dtype.is_timestamp():
|
|
31
|
+
return "timestamp"
|
|
32
|
+
if dtype.is_date():
|
|
33
|
+
return "date"
|
|
34
|
+
if dtype.is_time():
|
|
35
|
+
return "time"
|
|
36
|
+
if dtype.is_binary():
|
|
37
|
+
return "binary"
|
|
38
|
+
if dtype.is_struct():
|
|
39
|
+
return "struct"
|
|
40
|
+
if dtype.is_array():
|
|
41
|
+
return "array"
|
|
42
|
+
if dtype.is_map():
|
|
43
|
+
return "map"
|
|
44
|
+
if dtype.is_null():
|
|
45
|
+
return "null"
|
|
46
|
+
except AttributeError:
|
|
47
|
+
return "other"
|
|
48
|
+
return "other"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def ibis_dtype_to_schema_property(dtype: DataType) -> SchemaProperty | None:
|
|
52
|
+
"""Map an ibis DataType to a SchemaProperty for structural type comparison.
|
|
53
|
+
|
|
54
|
+
Returns a ``SchemaProperty`` with ``logicalType`` set to one of the 9 ODCS
|
|
55
|
+
categories, recursively populating ``properties`` for structs and ``items``
|
|
56
|
+
for arrays. Returns ``None`` for unsupported types (binary, map, null, etc.)
|
|
57
|
+
so the caller can skip comparison rather than raising a false failure.
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
if dtype.is_boolean():
|
|
61
|
+
return SchemaProperty(logicalType="boolean")
|
|
62
|
+
if dtype.is_integer():
|
|
63
|
+
return SchemaProperty(logicalType="integer")
|
|
64
|
+
if dtype.is_decimal() or dtype.is_floating():
|
|
65
|
+
return SchemaProperty(logicalType="number")
|
|
66
|
+
if dtype.is_string():
|
|
67
|
+
return SchemaProperty(logicalType="string")
|
|
68
|
+
if dtype.is_timestamp():
|
|
69
|
+
return SchemaProperty(logicalType="timestamp")
|
|
70
|
+
if dtype.is_date():
|
|
71
|
+
return SchemaProperty(logicalType="date")
|
|
72
|
+
if dtype.is_time():
|
|
73
|
+
return SchemaProperty(logicalType="time")
|
|
74
|
+
if dtype.is_struct():
|
|
75
|
+
properties = []
|
|
76
|
+
for field_name, ftype in dtype.fields.items():
|
|
77
|
+
child = ibis_dtype_to_schema_property(ftype)
|
|
78
|
+
if child is not None:
|
|
79
|
+
properties.append(
|
|
80
|
+
SchemaProperty(
|
|
81
|
+
name=field_name,
|
|
82
|
+
logicalType=child.logicalType,
|
|
83
|
+
items=child.items,
|
|
84
|
+
properties=child.properties,
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
return SchemaProperty(logicalType="object", properties=properties if properties else None)
|
|
88
|
+
if dtype.is_array():
|
|
89
|
+
element = ibis_dtype_to_schema_property(dtype.value_type)
|
|
90
|
+
return SchemaProperty(logicalType="array", items=element)
|
|
91
|
+
except AttributeError:
|
|
92
|
+
return None
|
|
93
|
+
return None
|
{datacontract_cli-1.0.4 → datacontract_cli-1.0.6}/datacontract/engines/ibis/ibis_check_execute.py
RENAMED
|
@@ -17,9 +17,9 @@ from typing import List, Optional
|
|
|
17
17
|
from open_data_contract_standard.model import OpenDataContractStandard, Server
|
|
18
18
|
|
|
19
19
|
from datacontract.engines.checks.check_spec import CheckSpec, MetricType
|
|
20
|
-
from datacontract.engines.checks.type_normalize import
|
|
20
|
+
from datacontract.engines.checks.type_normalize import schema_property_matches, schema_property_mismatch_reason
|
|
21
21
|
from datacontract.engines.ibis.connections.connect import connect_ibis
|
|
22
|
-
from datacontract.engines.ibis.dtype_category import
|
|
22
|
+
from datacontract.engines.ibis.dtype_category import ibis_dtype_to_schema_property
|
|
23
23
|
from datacontract.model.exceptions import DataContractException
|
|
24
24
|
from datacontract.model.run import Check, ResultEnum, Run
|
|
25
25
|
from datacontract.model.server import get_server_type
|
|
@@ -177,7 +177,7 @@ def _run_model(
|
|
|
177
177
|
include_failed_samples: bool = False,
|
|
178
178
|
):
|
|
179
179
|
try:
|
|
180
|
-
t = _resolve_table(con, model)
|
|
180
|
+
t = _resolve_table(con, model, _table_database(con, server))
|
|
181
181
|
except Exception as e:
|
|
182
182
|
logger.warning("Could not read model '%s': %s", model, e)
|
|
183
183
|
_fail_all(run, specs, ResultEnum.failed, f"Could not read model '{model}': {e}")
|
|
@@ -607,31 +607,30 @@ def _run_type(run: Run, schema, columns, spec: CheckSpec):
|
|
|
607
607
|
_set_impl(
|
|
608
608
|
run,
|
|
609
609
|
spec.key,
|
|
610
|
-
f"type of '{spec.field}' is compatible with '{spec.expected_type_label}'
|
|
610
|
+
f"type of '{spec.field}' is compatible with '{spec.expected_type_label}'",
|
|
611
611
|
"introspection",
|
|
612
612
|
)
|
|
613
|
-
expected_label = f"{spec.expected_type_label} ({spec.expected_category})"
|
|
614
613
|
actual_col = columns.get(spec.field.lower())
|
|
615
614
|
if actual_col is None:
|
|
616
|
-
_set_diagnostics(run, spec.key, _diag(metric="field_type", field=spec.field, expected=
|
|
615
|
+
_set_diagnostics(run, spec.key, _diag(metric="field_type", field=spec.field, expected=spec.expected_type_label))
|
|
617
616
|
_set_result(run, spec.key, ResultEnum.failed, f"Column '{spec.field}' is missing")
|
|
618
617
|
return
|
|
619
618
|
dtype = schema[actual_col]
|
|
620
|
-
|
|
619
|
+
actual_prop = ibis_dtype_to_schema_property(dtype)
|
|
621
620
|
_set_diagnostics(
|
|
622
621
|
run,
|
|
623
622
|
spec.key,
|
|
624
|
-
_diag(metric="field_type", field=spec.field, expected=
|
|
623
|
+
_diag(metric="field_type", field=spec.field, expected=spec.expected_type_label, actual=str(dtype)),
|
|
625
624
|
)
|
|
626
|
-
if
|
|
625
|
+
if schema_property_matches(spec.expected_schema_property, actual_prop):
|
|
627
626
|
_set_result(run, spec.key, ResultEnum.passed, None)
|
|
628
627
|
else:
|
|
628
|
+
reason = schema_property_mismatch_reason(spec.expected_schema_property, actual_prop)
|
|
629
629
|
_set_result(
|
|
630
630
|
run,
|
|
631
631
|
spec.key,
|
|
632
632
|
ResultEnum.failed,
|
|
633
|
-
f"Expected type '{spec.expected_type_label}'
|
|
634
|
-
f"but column is '{dtype}' ({actual_category})",
|
|
633
|
+
reason or f"Expected type '{spec.expected_type_label}' but column is '{dtype}'",
|
|
635
634
|
)
|
|
636
635
|
|
|
637
636
|
|
|
@@ -849,21 +848,52 @@ def _resolve_col(columns: dict, field: str) -> str:
|
|
|
849
848
|
return actual
|
|
850
849
|
|
|
851
850
|
|
|
852
|
-
def
|
|
851
|
+
def _table_database(con, server: Optional[Server]) -> Optional[str]:
|
|
852
|
+
"""The schema to qualify the table with during introspection, or ``None``.
|
|
853
|
+
|
|
854
|
+
Two backends need the contract's ``server.schema`` passed explicitly instead
|
|
855
|
+
of relying on ibis's default:
|
|
856
|
+
|
|
857
|
+
- **Oracle** logs in as one user but the tables may be owned by a different
|
|
858
|
+
schema (``server.schema``). ibis defaults the owner to the login user, so
|
|
859
|
+
an unqualified lookup raises ``TableNotFound``.
|
|
860
|
+
- **Redshift** has no dedicated ibis backend and goes through the Postgres
|
|
861
|
+
backend (``con.name == "postgres"``). When no schema is passed, ibis's
|
|
862
|
+
Postgres introspection resolves the active schema with ``SELECT
|
|
863
|
+
current_schema`` (no parentheses) — valid on PostgreSQL but rejected by
|
|
864
|
+
Redshift with ``column "current_schema" does not exist``, since Redshift
|
|
865
|
+
only supports the parenthesized ``current_schema()``. Passing the schema
|
|
866
|
+
explicitly skips that query.
|
|
867
|
+
|
|
868
|
+
Other backends pin the schema at connect time and need no qualifier.
|
|
869
|
+
"""
|
|
870
|
+
if server is None or not server.schema_:
|
|
871
|
+
return None
|
|
872
|
+
if getattr(con, "name", None) == "oracle":
|
|
873
|
+
return server.schema_
|
|
874
|
+
# Redshift rides the Postgres backend, so detect it by the contract's server
|
|
875
|
+
# type rather than con.name.
|
|
876
|
+
if get_server_type(server) == "redshift":
|
|
877
|
+
return server.schema_
|
|
878
|
+
return None
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
def _resolve_table(con, model: str, database: Optional[str] = None):
|
|
853
882
|
"""Resolve a table by name, tolerating case differences across dialects."""
|
|
854
883
|
if getattr(con, "name", None) == "pyspark":
|
|
855
884
|
return _pyspark_table_unconvertible_as_unknown(con, model)
|
|
885
|
+
kwargs = {"database": database} if database else {}
|
|
856
886
|
try:
|
|
857
|
-
return con.table(model)
|
|
887
|
+
return con.table(model, **kwargs)
|
|
858
888
|
except Exception:
|
|
859
889
|
try:
|
|
860
|
-
available = con.list_tables()
|
|
890
|
+
available = con.list_tables(**kwargs)
|
|
861
891
|
except Exception:
|
|
862
892
|
raise
|
|
863
893
|
match = next((name for name in available if name.lower() == model.lower()), None)
|
|
864
894
|
if match is None:
|
|
865
895
|
raise
|
|
866
|
-
return con.table(match)
|
|
896
|
+
return con.table(match, **kwargs)
|
|
867
897
|
|
|
868
898
|
|
|
869
899
|
def _pyspark_table_unconvertible_as_unknown(con, name: str):
|
|
@@ -570,10 +570,10 @@ def _convert_field_to_property(
|
|
|
570
570
|
return prop
|
|
571
571
|
|
|
572
572
|
|
|
573
|
-
def _convert_type_to_logical_type(dcs_type: str) -> str:
|
|
573
|
+
def _convert_type_to_logical_type(dcs_type: str) -> str | None:
|
|
574
574
|
"""Convert DCS type to ODCS logical type."""
|
|
575
575
|
if dcs_type is None:
|
|
576
|
-
return
|
|
576
|
+
return None
|
|
577
577
|
|
|
578
578
|
t = dcs_type.lower()
|
|
579
579
|
|
|
@@ -598,19 +598,26 @@ def _convert_type_to_logical_type(dcs_type: str) -> str:
|
|
|
598
598
|
"timestamp_tz": "timestamp",
|
|
599
599
|
"timestamp_ntz": "timestamp",
|
|
600
600
|
"date": "date",
|
|
601
|
-
"time":
|
|
601
|
+
"time": None, # not supported in ODCS
|
|
602
602
|
"datetime": "timestamp",
|
|
603
603
|
"array": "array",
|
|
604
604
|
"object": "object",
|
|
605
605
|
"record": "object",
|
|
606
606
|
"struct": "object",
|
|
607
|
-
"map":
|
|
608
|
-
"
|
|
609
|
-
"
|
|
610
|
-
"
|
|
607
|
+
"map": None, # not supported in ODCS
|
|
608
|
+
"interval": None, # not supported in ODCS
|
|
609
|
+
"bytes": None, # not supported in ODCS
|
|
610
|
+
"binary": None, # not supported in ODCS
|
|
611
|
+
"varbinary": None, # not supported in ODCS
|
|
612
|
+
"blob": None, # not supported in ODCS
|
|
613
|
+
"bytea": None, # not supported in ODCS
|
|
614
|
+
"raw": None, # not supported in ODCS
|
|
615
|
+
"null": None, # not supported in ODCS
|
|
616
|
+
"none": None, # not supported in ODCS
|
|
617
|
+
"void": None, # not supported in ODCS
|
|
611
618
|
}
|
|
612
619
|
|
|
613
|
-
return type_mapping.get(t,
|
|
620
|
+
return type_mapping.get(t, None)
|
|
614
621
|
|
|
615
622
|
|
|
616
623
|
def _convert_quality_list(quality_list: list) -> List[DataQuality]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datacontract-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
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
|
|
@@ -292,6 +292,7 @@ tests/test_export_sql_clickhouse.py
|
|
|
292
292
|
tests/test_export_sql_query.py
|
|
293
293
|
tests/test_export_sqlalchemy.py
|
|
294
294
|
tests/test_ibis_mssql_pattern.py
|
|
295
|
+
tests/test_ibis_oracle_schema.py
|
|
295
296
|
tests/test_import_avro.py
|
|
296
297
|
tests/test_import_bigquery.py
|
|
297
298
|
tests/test_import_csv.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datacontract-cli"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.6"
|
|
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"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Unit tests for Oracle table resolution across schemas (owners).
|
|
2
|
+
|
|
3
|
+
Oracle logs in as one user but the contract's tables may be owned by a different
|
|
4
|
+
schema (``server.schema``). ibis defaults the owner to the login user during
|
|
5
|
+
introspection, so an unqualified lookup raises ``TableNotFound``. The engine
|
|
6
|
+
must qualify the table with the configured schema. See issue: cross-schema
|
|
7
|
+
Oracle test fails with "Could not read model '<table>': <table>".
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from open_data_contract_standard.model import Server
|
|
11
|
+
|
|
12
|
+
from datacontract.engines.ibis.ibis_check_execute import _resolve_table, _table_database
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _FakeBackend:
|
|
16
|
+
"""Minimal stand-in for an ibis backend that records how it is queried."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, name, tables):
|
|
19
|
+
self.name = name
|
|
20
|
+
# tables: {database_or_None: {table_name: object}}
|
|
21
|
+
self._tables = tables
|
|
22
|
+
self.table_calls = []
|
|
23
|
+
|
|
24
|
+
def table(self, name, database=None):
|
|
25
|
+
self.table_calls.append((name, database))
|
|
26
|
+
try:
|
|
27
|
+
return self._tables[database][name]
|
|
28
|
+
except KeyError:
|
|
29
|
+
raise Exception(name)
|
|
30
|
+
|
|
31
|
+
def list_tables(self, database=None):
|
|
32
|
+
return list(self._tables.get(database, {}))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_table_database_uses_server_schema_for_oracle():
|
|
36
|
+
server = Server(type="oracle", schema="PSD1_VERBIS")
|
|
37
|
+
con = _FakeBackend("oracle", {})
|
|
38
|
+
assert _table_database(con, server) == "PSD1_VERBIS"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_table_database_none_for_oracle_without_schema():
|
|
42
|
+
server = Server(type="oracle")
|
|
43
|
+
con = _FakeBackend("oracle", {})
|
|
44
|
+
assert _table_database(con, server) is None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_table_database_none_for_non_oracle_backend():
|
|
48
|
+
# Postgres/snowflake pin the schema at connect time, so no qualifier is added.
|
|
49
|
+
server = Server(type="postgres", schema="public")
|
|
50
|
+
con = _FakeBackend("postgres", {})
|
|
51
|
+
assert _table_database(con, server) is None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_table_database_uses_server_schema_for_redshift():
|
|
55
|
+
# Redshift rides the Postgres ibis backend (con.name == "postgres"). Without
|
|
56
|
+
# an explicit schema, ibis introspects via `SELECT current_schema` (no
|
|
57
|
+
# parens), which Redshift rejects ("column current_schema does not exist").
|
|
58
|
+
# Passing the schema explicitly avoids that query.
|
|
59
|
+
server = Server(type="redshift", schema="dwh_academic")
|
|
60
|
+
con = _FakeBackend("postgres", {})
|
|
61
|
+
assert _table_database(con, server) == "dwh_academic"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_table_database_none_for_redshift_without_schema():
|
|
65
|
+
server = Server(type="redshift")
|
|
66
|
+
con = _FakeBackend("postgres", {})
|
|
67
|
+
assert _table_database(con, server) is None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_table_database_none_without_server():
|
|
71
|
+
con = _FakeBackend("oracle", {})
|
|
72
|
+
assert _table_database(con, None) is None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_resolve_table_qualifies_with_schema():
|
|
76
|
+
sentinel = object()
|
|
77
|
+
con = _FakeBackend("oracle", {"PSD1_VERBIS": {"BERUF": sentinel}})
|
|
78
|
+
|
|
79
|
+
assert _resolve_table(con, "BERUF", "PSD1_VERBIS") is sentinel
|
|
80
|
+
assert ("BERUF", "PSD1_VERBIS") in con.table_calls
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_resolve_table_without_schema_does_not_pass_database():
|
|
84
|
+
sentinel = object()
|
|
85
|
+
con = _FakeBackend("oracle", {None: {"BERUF": sentinel}})
|
|
86
|
+
|
|
87
|
+
assert _resolve_table(con, "BERUF") is sentinel
|
|
88
|
+
assert con.table_calls == [("BERUF", None)]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_resolve_table_case_insensitive_fallback_keeps_schema():
|
|
92
|
+
sentinel = object()
|
|
93
|
+
con = _FakeBackend("oracle", {"PSD1_VERBIS": {"BERUF": sentinel}})
|
|
94
|
+
|
|
95
|
+
# Contract uses lowercase; the actual table is uppercase in the schema.
|
|
96
|
+
assert _resolve_table(con, "beruf", "PSD1_VERBIS") is sentinel
|
|
97
|
+
# The successful resolution still targets the qualifying schema.
|
|
98
|
+
assert con.table_calls[-1] == ("BERUF", "PSD1_VERBIS")
|