datacontract-cli 1.0.12__tar.gz → 1.0.13__tar.gz

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