datacontract-cli 1.1.2__tar.gz → 1.1.3__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 (482) hide show
  1. {datacontract_cli-1.1.2/datacontract_cli.egg-info → datacontract_cli-1.1.3}/PKG-INFO +7 -4
  2. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/README.md +3 -0
  3. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/api.py +72 -0
  4. datacontract_cli-1.1.3/datacontract/breaking/detector.py +74 -0
  5. datacontract_cli-1.1.3/datacontract/breaking/rules.py +196 -0
  6. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/cli.py +13 -3
  7. datacontract_cli-1.1.3/datacontract/command_breaking.py +39 -0
  8. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_ci.py +1 -1
  9. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_dbt.py +2 -2
  10. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_export.py +7 -0
  11. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_test.py +9 -1
  12. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/config/settings.py +4 -0
  13. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/data_contract.py +16 -3
  14. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/checks/check_spec.py +6 -0
  15. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/checks/create_checks.py +59 -15
  16. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/checks/dimensions.py +3 -0
  17. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/data_contract_test.py +96 -12
  18. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/fastjsonschema/check_jsonschema.py +16 -0
  19. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/duckdb_connection.py +7 -6
  20. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/kafka.py +2 -1
  21. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/ibis_check_execute.py +32 -0
  22. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/avro_exporter.py +1 -1
  23. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/duckdb_type_converter.py +1 -1
  24. datacontract_cli-1.1.3/datacontract/export/great_expectations_exporter.py +732 -0
  25. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/jsonschema_exporter.py +3 -3
  26. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/sodacl_check_builder.py +2 -2
  27. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/dcs_importer.py +2 -0
  28. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/sql_importer.py +79 -19
  29. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/lint/resolve.py +273 -22
  30. datacontract_cli-1.1.3/datacontract/model/breaking.py +33 -0
  31. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/model/run.py +15 -0
  32. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/output/test_results_writer.py +5 -0
  33. datacontract_cli-1.1.3/datacontract/output/text_breaking_results.py +81 -0
  34. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3/datacontract_cli.egg-info}/PKG-INFO +7 -4
  35. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract_cli.egg-info/SOURCES.txt +12 -0
  36. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract_cli.egg-info/requires.txt +3 -3
  37. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/pyproject.toml +4 -4
  38. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_api.py +22 -0
  39. datacontract_cli-1.1.3/tests/test_breaking.py +337 -0
  40. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_cli.py +30 -0
  41. datacontract_cli-1.1.3/tests/test_create_checks_array_items.py +71 -0
  42. datacontract_cli-1.1.3/tests/test_create_checks_retention_period.py +57 -0
  43. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_create_checks_servicelevel.py +25 -0
  44. datacontract_cli-1.1.3/tests/test_description_linter.py +0 -0
  45. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_duckdb_json.py +48 -0
  46. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_avro.py +17 -0
  47. datacontract_cli-1.1.3/tests/test_export_great_expectations.py +1508 -0
  48. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_jsonschema.py +19 -1
  49. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_sodacl.py +41 -3
  50. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_sql_oracle.py +1 -1
  51. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_sql_postgres.py +24 -1
  52. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_sql_snowflake.py +42 -1
  53. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_sql_sqlserver.py +1 -1
  54. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_resolve.py +37 -0
  55. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_resolve_definitions.py +45 -5
  56. datacontract_cli-1.1.3/tests/test_resolve_local_definitions.py +615 -0
  57. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_roundtrip_pydantic_model.py +33 -5
  58. datacontract_cli-1.1.3/tests/test_test_array_items.py +109 -0
  59. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_dimension_filter.py +3 -0
  60. datacontract_cli-1.1.3/tests/test_test_dry_run.py +175 -0
  61. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_kafka_decoding.py +20 -0
  62. datacontract_cli-1.1.2/datacontract/export/great_expectations_exporter.py +0 -357
  63. datacontract_cli-1.1.2/tests/test_export_great_expectations.py +0 -621
  64. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/LICENSE +0 -0
  65. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/MANIFEST.in +0 -0
  66. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/__init__.py +0 -0
  67. {datacontract_cli-1.1.2/datacontract/engines → datacontract_cli-1.1.3/datacontract/breaking}/__init__.py +0 -0
  68. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/catalog/catalog.py +0 -0
  69. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/changelog/__init__.py +0 -0
  70. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/changelog/changelog.py +0 -0
  71. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/changelog/normalize.py +0 -0
  72. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_api.py +0 -0
  73. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_catalog.py +0 -0
  74. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_changelog.py +0 -0
  75. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_edit.py +0 -0
  76. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_import.py +0 -0
  77. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_init.py +0 -0
  78. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_lint.py +0 -0
  79. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/command_publish.py +0 -0
  80. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/config/__init__.py +0 -0
  81. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/config/cli_context.py +0 -0
  82. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/VERSION +0 -0
  83. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/abap-Bs8kvjsq.js +0 -0
  84. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/apex-Dspwrl5m.js +0 -0
  85. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -0
  86. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -0
  87. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/azcli-k1BiOau1.js +0 -0
  88. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/bat-BIP72KWc.js +0 -0
  89. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/bicep-VhQeYhS3.js +0 -0
  90. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/cameligo-DnuAXtHg.js +0 -0
  91. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/clojure-BAuDPsal.js +0 -0
  92. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/coffee-BV06qSnj.js +0 -0
  93. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/cpp-Cz8Jeyrf.js +0 -0
  94. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/csharp-F6hhlXFb.js +0 -0
  95. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/csp-KzlEHCyI.js +0 -0
  96. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/css-e4FKntZ3.js +0 -0
  97. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/cssMode-BNkTa2xp.js +0 -0
  98. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/cypher-CpvDGKRr.js +0 -0
  99. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/dart-DdHeFWR0.js +0 -0
  100. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/datacontract-editor.css +0 -0
  101. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/datacontract-editor.es.js +0 -0
  102. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/dockerfile-aoNXDcio.js +0 -0
  103. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/ecl-C4Q0DYuA.js +0 -0
  104. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/elixir-C9X42b0T.js +0 -0
  105. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/flow9-Bff42pfB.js +0 -0
  106. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/freemarker2-Dyfzmb5A.js +0 -0
  107. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/fsharp-C6vPAsHG.js +0 -0
  108. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/go-DEr8zx9f.js +0 -0
  109. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/graphql-BiNBBRFh.js +0 -0
  110. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/handlebars-BtDNI-uC.js +0 -0
  111. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/hcl-2T9lKuFg.js +0 -0
  112. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/html-Cn4TGw_o.js +0 -0
  113. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/htmlMode-Bf84vbo2.js +0 -0
  114. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/index.html +0 -0
  115. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/ini-CZGtssYM.js +0 -0
  116. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/java-B260NeH3.js +0 -0
  117. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/javascript-B86Kac07.js +0 -0
  118. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/jsonMode-Ckgg5lAE.js +0 -0
  119. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/julia-kuNLM9c5.js +0 -0
  120. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/kotlin-Bz6kAefA.js +0 -0
  121. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/less-AZUtS89I.js +0 -0
  122. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/lexon-BcmgnyRb.js +0 -0
  123. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/liquid-D0NPwuu_.js +0 -0
  124. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
  125. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/lua-Dz1RbATg.js +0 -0
  126. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/m3-CIMooLFn.js +0 -0
  127. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/markdown-C1BsCK9P.js +0 -0
  128. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/mdx-QFRSBtVQ.js +0 -0
  129. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/mips-BovsnfLQ.js +0 -0
  130. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/monaco-4.7.0.js +0 -0
  131. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/msdax-CiRB2ZB-.js +0 -0
  132. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/mysql-BwdpPE19.js +0 -0
  133. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/objective-c-D4nfHfso.js +0 -0
  134. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/odcs.svg +0 -0
  135. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/pascal--j5-PYtz.js +0 -0
  136. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/pascaligo-C7TcJxNL.js +0 -0
  137. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/perl-BzEWqUb5.js +0 -0
  138. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/pgsql-B_KZ0mGX.js +0 -0
  139. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/php-A19QHzQV.js +0 -0
  140. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/pla-COeKY1hA.js +0 -0
  141. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/postiats-BfMp7zJL.js +0 -0
  142. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/powerquery-B0TS_5Gb.js +0 -0
  143. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/powershell-5jSbKdYB.js +0 -0
  144. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/protobuf-YgnOutn3.js +0 -0
  145. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/pug-DLej6kn5.js +0 -0
  146. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/python-C8RW9B6A.js +0 -0
  147. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/qsharp-AhjqtSHB.js +0 -0
  148. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/r-D-F4P80w.js +0 -0
  149. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/razor-CLZqdY_r.js +0 -0
  150. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/redis-hwwIlMnV.js +0 -0
  151. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/redshift-Bcm_kjEG.js +0 -0
  152. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/restructuredtext-CrdzfPP-.js +0 -0
  153. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/ruby-QC2UNm1s.js +0 -0
  154. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/rust-5aqiQ3L5.js +0 -0
  155. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/sb-B1g1ZfLJ.js +0 -0
  156. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/scala-C2U4R5Gb.js +0 -0
  157. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/scheme-DeFRbslr.js +0 -0
  158. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/scss-RSTCiCmI.js +0 -0
  159. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/shell-BpF-iNu8.js +0 -0
  160. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/solidity-C00r2mbQ.js +0 -0
  161. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/sophia-DVW5ZKDB.js +0 -0
  162. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/sparql-B0nmpxeX.js +0 -0
  163. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/sql-CJwKPERn.js +0 -0
  164. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/st-DPlKG5DT.js +0 -0
  165. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/swift-YZBAbVHV.js +0 -0
  166. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/systemverilog-CDQSaH63.js +0 -0
  167. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/tcl-Dlu8sp6Q.js +0 -0
  168. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/tsMode-yleMwhPq.js +0 -0
  169. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/twig-C5TO7-kw.js +0 -0
  170. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/typescript-CJBeebKU.js +0 -0
  171. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/typespec-BsmjDEu7.js +0 -0
  172. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/vb-ChHvIDrk.js +0 -0
  173. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/wgsl-XEp1ju8c.js +0 -0
  174. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/xml-vC-NMVX1.js +0 -0
  175. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/editor_assets/yaml-Dlf2VF-T.js +0 -0
  176. {datacontract_cli-1.1.2/datacontract/engines/checks → datacontract_cli-1.1.3/datacontract/engines}/__init__.py +0 -0
  177. {datacontract_cli-1.1.2/datacontract/engines/ibis → datacontract_cli-1.1.3/datacontract/engines/checks}/__init__.py +0 -0
  178. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/checks/check_filter.py +0 -0
  179. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/checks/physical_type_match.py +0 -0
  180. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/checks/sql_guard.py +0 -0
  181. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/checks/type_normalize.py +0 -0
  182. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
  183. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
  184. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
  185. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
  186. {datacontract_cli-1.1.2/datacontract/engines/ibis/connections → datacontract_cli-1.1.3/datacontract/engines/ibis}/__init__.py +0 -0
  187. {datacontract_cli-1.1.2/datacontract/export → datacontract_cli-1.1.3/datacontract/engines/ibis/connections}/__init__.py +0 -0
  188. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/aws_credentials.py +0 -0
  189. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/connect.py +0 -0
  190. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/databricks_patch.py +0 -0
  191. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
  192. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/redshift_credentials.py +0 -0
  193. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/connections/redshift_patch.py +0 -0
  194. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/dtype_category.py +0 -0
  195. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/native_type.py +0 -0
  196. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/engines/ibis/snowflake_structured_types.py +0 -0
  197. {datacontract_cli-1.1.2/datacontract/output → datacontract_cli-1.1.3/datacontract/export}/__init__.py +0 -0
  198. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/avro_idl_exporter.py +0 -0
  199. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/bigquery_exporter.py +0 -0
  200. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/custom_exporter.py +0 -0
  201. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/data_caterer_exporter.py +0 -0
  202. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/dbml_exporter.py +0 -0
  203. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/dbt_exporter.py +0 -0
  204. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/dcs_exporter.py +0 -0
  205. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/dqx_exporter.py +0 -0
  206. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/excel_exporter.py +0 -0
  207. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/exporter.py +0 -0
  208. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/exporter_factory.py +0 -0
  209. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/go_exporter.py +0 -0
  210. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/html_exporter.py +0 -0
  211. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/iceberg_exporter.py +0 -0
  212. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/markdown_exporter.py +0 -0
  213. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/mermaid_exporter.py +0 -0
  214. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/odcs_v3_exporter.py +0 -0
  215. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/pandas_type_converter.py +0 -0
  216. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/protobuf_exporter.py +0 -0
  217. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/pydantic_exporter.py +0 -0
  218. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/rdf_exporter.py +0 -0
  219. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/sodacl_exporter.py +0 -0
  220. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/spark_exporter.py +0 -0
  221. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/sql_exporter.py +0 -0
  222. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/sql_type_converter.py +0 -0
  223. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/export/sqlalchemy_exporter.py +0 -0
  224. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/athena_importer.py +0 -0
  225. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/avro_importer.py +0 -0
  226. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/bigquery_importer.py +0 -0
  227. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/csv_importer.py +0 -0
  228. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/dbml_importer.py +0 -0
  229. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/dbt_importer.py +0 -0
  230. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/excel_importer.py +0 -0
  231. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/glue_importer.py +0 -0
  232. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/iceberg_importer.py +0 -0
  233. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/importer.py +0 -0
  234. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/importer_factory.py +0 -0
  235. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/json_importer.py +0 -0
  236. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/jsonschema_importer.py +0 -0
  237. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/mysql_importer.py +0 -0
  238. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/object_storage_importer.py +0 -0
  239. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/odcs_helper.py +0 -0
  240. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/odcs_importer.py +0 -0
  241. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/oracle_importer.py +0 -0
  242. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/parquet_importer.py +0 -0
  243. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/postgres_importer.py +0 -0
  244. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/powerbi_importer.py +0 -0
  245. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/protobuf_importer.py +0 -0
  246. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/pydantic_importer.py +0 -0
  247. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/redshift_importer.py +0 -0
  248. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/snowflake_importer.py +0 -0
  249. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/spark_importer.py +0 -0
  250. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/spark_type_json.py +0 -0
  251. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/sqlserver_importer.py +0 -0
  252. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/trino_importer.py +0 -0
  253. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/imports/unity_importer.py +0 -0
  254. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/init/init_template.py +0 -0
  255. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/integration/dbt_sync.py +0 -0
  256. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/integration/dbt_test_mapping.py +0 -0
  257. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/integration/entropy_data.py +0 -0
  258. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/lint/files.py +0 -0
  259. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/lint/resources.py +0 -0
  260. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/lint/s3.py +0 -0
  261. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/lint/schema.py +0 -0
  262. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/lint/urls.py +0 -0
  263. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/model/changelog.py +0 -0
  264. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/model/exceptions.py +0 -0
  265. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/model/odcs.py +0 -0
  266. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/model/server.py +0 -0
  267. /datacontract_cli-1.1.2/datacontract/py.typed → /datacontract_cli-1.1.3/datacontract/output/__init__.py +0 -0
  268. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/output/ci_output.py +0 -0
  269. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/output/json_test_results.py +0 -0
  270. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/output/junit_test_results.py +0 -0
  271. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/output/output_format.py +0 -0
  272. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/output/text_changelog_results.py +0 -0
  273. /datacontract_cli-1.1.2/tests/test_description_linter.py → /datacontract_cli-1.1.3/datacontract/py.typed +0 -0
  274. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
  275. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
  276. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
  277. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
  278. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
  279. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
  280. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
  281. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
  282. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/odcs-3.1.0.init.yaml +0 -0
  283. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
  284. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/datacontract.html +0 -0
  285. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/datacontract_odcs.html +0 -0
  286. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/excel/odcs-template.xlsx +0 -0
  287. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/index.html +0 -0
  288. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/macros/authoritative_definitions.html +0 -0
  289. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/macros/schema.html +0 -0
  290. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/macros/server.html +0 -0
  291. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/macros/support.html +0 -0
  292. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/datacontract_information.html +0 -0
  293. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
  294. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/datacontract_terms.html +0 -0
  295. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/definition.html +0 -0
  296. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/example.html +0 -0
  297. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/model_field.html +0 -0
  298. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/quality.html +0 -0
  299. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials/server.html +0 -0
  300. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/custom_properties.html +0 -0
  301. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/diagram.html +0 -0
  302. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/dialog_yaml.html +0 -0
  303. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/footer.html +0 -0
  304. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/fundamentals.html +0 -0
  305. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/header.html +0 -0
  306. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/pricing.html +0 -0
  307. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/roles.html +0 -0
  308. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/schema.html +0 -0
  309. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/servers.html +0 -0
  310. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/sla.html +0 -0
  311. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/support.html +0 -0
  312. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/team.html +0 -0
  313. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/term_of_use.html +0 -0
  314. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/partials_odcs/title.html +0 -0
  315. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract/templates/style/output.css +0 -0
  316. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract_cli.egg-info/dependency_links.txt +0 -0
  317. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract_cli.egg-info/entry_points.txt +0 -0
  318. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/datacontract_cli.egg-info/top_level.txt +0 -0
  319. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/setup.cfg +0 -0
  320. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_api_openapi.py +0 -0
  321. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_catalog.py +0 -0
  322. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_changelog.py +0 -0
  323. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_changelog_engine.py +0 -0
  324. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_changelog_normalize.py +0 -0
  325. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_changelog_output_text.py +0 -0
  326. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_check_quality_provenance.py +0 -0
  327. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_ci_output.py +0 -0
  328. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_command_api.py +0 -0
  329. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_config.py +0 -0
  330. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_config_file.py +0 -0
  331. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_config_require.py +0 -0
  332. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_config_threading.py +0 -0
  333. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_athena.py +0 -0
  334. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_bigquery.py +0 -0
  335. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_databricks.py +0 -0
  336. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_impala.py +0 -0
  337. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_mysql.py +0 -0
  338. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_oracle.py +0 -0
  339. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_postgres.py +0 -0
  340. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_redshift.py +0 -0
  341. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_s3_credentials.py +0 -0
  342. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_snowflake.py +0 -0
  343. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_sqlserver.py +0 -0
  344. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_connect_trino.py +0 -0
  345. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_create_checks_nested_type.py +0 -0
  346. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_create_checks_physical_type.py +0 -0
  347. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_create_checks_primary_key.py +0 -0
  348. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_create_checks_sql_placeholders.py +0 -0
  349. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_data_contract.py +0 -0
  350. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_data_contract_checks.py +0 -0
  351. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_data_contract_specification.py +0 -0
  352. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_dbt_sync.py +0 -0
  353. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_dbt_test_mapping.py +0 -0
  354. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_docs_commands.py +0 -0
  355. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_docs_config_options.py +0 -0
  356. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_docs_ordering.py +0 -0
  357. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_download_datacontract_file.py +0 -0
  358. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_dtype_category.py +0 -0
  359. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_edit.py +0 -0
  360. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_avro_idl.py +0 -0
  361. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_bigquery.py +0 -0
  362. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_complex_data_contract.py +0 -0
  363. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_custom.py +0 -0
  364. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_custom_exporter.py +0 -0
  365. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_custom_model.py +0 -0
  366. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_data_caterer.py +0 -0
  367. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_dbml.py +0 -0
  368. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_dbt_models.py +0 -0
  369. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_dbt_sources.py +0 -0
  370. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_dbt_staging_sql.py +0 -0
  371. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_dcs.py +0 -0
  372. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_dqx.py +0 -0
  373. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_excel.py +0 -0
  374. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_go.py +0 -0
  375. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_html.py +0 -0
  376. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_iceberg.py +0 -0
  377. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_large_contract.py +0 -0
  378. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_markdown.py +0 -0
  379. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_mermaid.py +0 -0
  380. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_odcs_v3.py +0 -0
  381. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_protobuf.py +0 -0
  382. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_pydantic.py +0 -0
  383. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_rdf.py +0 -0
  384. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_spark.py +0 -0
  385. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_sql.py +0 -0
  386. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_sql_clickhouse.py +0 -0
  387. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_sql_query.py +0 -0
  388. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_export_sqlalchemy.py +0 -0
  389. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_ibis_mssql_pattern.py +0 -0
  390. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_ibis_mssql_schema.py +0 -0
  391. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_ibis_oracle_schema.py +0 -0
  392. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_athena.py +0 -0
  393. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_avro.py +0 -0
  394. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_bigquery.py +0 -0
  395. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_csv.py +0 -0
  396. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_dbml.py +0 -0
  397. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_dbt.py +0 -0
  398. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_excel.py +0 -0
  399. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_glue.py +0 -0
  400. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_iceberg.py +0 -0
  401. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_json.py +0 -0
  402. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_jsonschema.py +0 -0
  403. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_mysql.py +0 -0
  404. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_object_storage.py +0 -0
  405. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_odcs_v3.py +0 -0
  406. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_oracle.py +0 -0
  407. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_parquet.py +0 -0
  408. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_postgres.py +0 -0
  409. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_powerbi.py +0 -0
  410. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_protobuf.py +0 -0
  411. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_pydantic_model.py +0 -0
  412. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_redshift.py +0 -0
  413. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_snowflake.py +0 -0
  414. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_spark_type_json.py +0 -0
  415. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_sqlserver.py +0 -0
  416. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_trino.py +0 -0
  417. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_import_unity_file.py +0 -0
  418. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_install_extras.py +0 -0
  419. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_integration_entropydata.py +0 -0
  420. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_lint.py +0 -0
  421. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_lint_urls.py +0 -0
  422. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_native_type_schema_scope.py +0 -0
  423. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_oracle_patch.py +0 -0
  424. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_physical_type_match.py +0 -0
  425. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_publish_test_results.py +0 -0
  426. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_publish_test_results_payload.py +0 -0
  427. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_quality_sql_dialects.py +0 -0
  428. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_redshift_credentials.py +0 -0
  429. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_redshift_patch.py +0 -0
  430. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_roundtrip_jsonschema.py +0 -0
  431. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_run_check_deprecated_fields.py +0 -0
  432. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_run_check_engine.py +0 -0
  433. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_server_overrides.py +0 -0
  434. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_server_type_mssql.py +0 -0
  435. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_server_type_synonyms.py +0 -0
  436. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_snowflake_structured_types.py +0 -0
  437. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_sql_type_converter_physicaltype.py +0 -0
  438. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_api.py +0 -0
  439. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_athena_iceberg.py +0 -0
  440. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_azure_blob_file.py +0 -0
  441. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_azure_remote.py +0 -0
  442. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_bigquery.py +0 -0
  443. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_checks_filter.py +0 -0
  444. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_databricks.py +0 -0
  445. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_delta.py +0 -0
  446. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_diagnostics.py +0 -0
  447. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_duckdb.py +0 -0
  448. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_failed_samples.py +0 -0
  449. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_gcs_csv_remote.py +0 -0
  450. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_gcs_json_remote.py +0 -0
  451. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_kafka.py +0 -0
  452. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_kafka_remote.py +0 -0
  453. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_local_json.py +0 -0
  454. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_local_json_nd.py +0 -0
  455. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_metadata_only.py +0 -0
  456. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_mysql.py +0 -0
  457. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_oracle.py +0 -0
  458. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_oracle_xe.py +0 -0
  459. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_output_json.py +0 -0
  460. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_output_junit.py +0 -0
  461. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_parquet.py +0 -0
  462. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_postgres.py +0 -0
  463. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_quality.py +0 -0
  464. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_quality_id_and_tag_filter.py +0 -0
  465. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_quality_local_fallback.py +0 -0
  466. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_quality_percent_severity.py +0 -0
  467. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_redshift.py +0 -0
  468. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_row_filter.py +0 -0
  469. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_s3_csv.py +0 -0
  470. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_s3_delta.py +0 -0
  471. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_s3_json.py +0 -0
  472. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_s3_json_complex.py +0 -0
  473. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_s3_json_multiple_models.py +0 -0
  474. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_s3_json_remote.py +0 -0
  475. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_schema_evolution.py +0 -0
  476. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_server_not_found.py +0 -0
  477. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_snowflake.py +0 -0
  478. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_soda_connection_error.py +0 -0
  479. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_sqlserver.py +0 -0
  480. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_test_trino.py +0 -0
  481. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_type_normalize.py +0 -0
  482. {datacontract_cli-1.1.2 → datacontract_cli-1.1.3}/tests/test_untrusted_contract.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datacontract-cli
3
- Version: 1.1.2
3
+ Version: 1.1.3
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@entropy-data.com>, Stefan Negele <stefan.negele@innoq.com>, Simon Harrer <simon.harrer@entropy-data.com>
6
6
  License-Expression: MIT
@@ -46,7 +46,7 @@ Requires-Dist: boto3<2.0.0,>=1.34.41
46
46
  Requires-Dist: Jinja2<4.0.0,>=3.1.5
47
47
  Requires-Dist: jinja_partials<1.0.0,>=0.2.1
48
48
  Requires-Dist: datacontract-specification<2.0.0,>=1.2.3
49
- Requires-Dist: open-data-contract-standard<4.0.0,>=3.1.2
49
+ Requires-Dist: open-data-contract-standard<3.2.0,>=3.1.2
50
50
  Requires-Dist: deepdiff<10.0.0,>=6.0.0
51
51
  Provides-Extra: avro
52
52
  Requires-Dist: avro==1.12.2; extra == "avro"
@@ -138,7 +138,7 @@ Requires-Dist: datacontract-cli[all]; extra == "dev"
138
138
  Requires-Dist: httpx==0.28.1; extra == "dev"
139
139
  Requires-Dist: kafka-python; extra == "dev"
140
140
  Requires-Dist: minio==7.2.20; extra == "dev"
141
- Requires-Dist: moto==5.2.2; extra == "dev"
141
+ Requires-Dist: moto==5.2.3; extra == "dev"
142
142
  Requires-Dist: openapi-spec-validator<0.10,>=0.7; extra == "dev"
143
143
  Requires-Dist: pandas>=2.1.0; extra == "dev"
144
144
  Requires-Dist: pre-commit<4.7.0,>=3.7.1; extra == "dev"
@@ -148,7 +148,7 @@ Requires-Dist: pytest-xdist; extra == "dev"
148
148
  Requires-Dist: pymssql==2.3.13; extra == "dev"
149
149
  Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == "dev"
150
150
  Requires-Dist: mysql-connector-python<26.8.0,>=8.0.30; extra == "dev"
151
- Requires-Dist: ruff==0.16.4; extra == "dev"
151
+ Requires-Dist: ruff==0.16.5; extra == "dev"
152
152
  Requires-Dist: testcontainers[kafka,minio,mssql,mysql,postgres]==4.15.0; extra == "dev"
153
153
  Requires-Dist: trino==0.339.0; extra == "dev"
154
154
  Dynamic: license-file
@@ -296,6 +296,9 @@ $ datacontract lint odcs.yaml
296
296
  # show a changelog between two data contracts
297
297
  $ datacontract changelog v1.odcs.yaml v2.odcs.yaml
298
298
 
299
+ # fail when a contract change is backward-incompatible
300
+ $ datacontract breaking v1.odcs.yaml v2.odcs.yaml
301
+
299
302
  # execute schema and quality checks (define credentials as environment variables)
300
303
  $ datacontract test odcs.yaml
301
304
 
@@ -141,6 +141,9 @@ $ datacontract lint odcs.yaml
141
141
  # show a changelog between two data contracts
142
142
  $ datacontract changelog v1.odcs.yaml v2.odcs.yaml
143
143
 
144
+ # fail when a contract change is backward-incompatible
145
+ $ datacontract breaking v1.odcs.yaml v2.odcs.yaml
146
+
144
147
  # execute schema and quality checks (define credentials as environment variables)
145
148
  $ datacontract test odcs.yaml
146
149
 
@@ -15,6 +15,7 @@ from pydantic import BaseModel, Field, ValidationError
15
15
 
16
16
  from datacontract.config import Config, known_env_names
17
17
  from datacontract.data_contract import DataContract, ExportFormat
18
+ from datacontract.model.breaking import BreakingChangeEntry
18
19
  from datacontract.model.changelog import ChangelogEntry
19
20
  from datacontract.model.exceptions import DataContractException, DefinitionResolutionError
20
21
  from datacontract.model.run import Check, ResultEnum, Run
@@ -323,6 +324,14 @@ app = FastAPI(
323
324
  "url": "https://docs.datacontract.com/commands/changelog",
324
325
  },
325
326
  },
327
+ {
328
+ "name": "breaking",
329
+ "description": "Compare two versions of a data contract and grade each change by compatibility impact.",
330
+ "externalDocs": {
331
+ "description": "Documentation",
332
+ "url": "https://docs.datacontract.com/commands/breaking",
333
+ },
334
+ },
326
335
  ],
327
336
  )
328
337
 
@@ -881,6 +890,21 @@ class ChangelogResponse(BaseModel):
881
890
  )
882
891
 
883
892
 
893
+ class BreakingChangesResponse(BaseModel):
894
+ """Every change between two versions of a data contract, each graded `info`, `warning` or `error`."""
895
+
896
+ summary: list[BreakingChangeEntry] = Field(
897
+ description="One entry per changed element, graded by the most severe change. A property whose type and requiredness "
898
+ "both changed appears once.",
899
+ )
900
+ entries: list[BreakingChangeEntry] = Field(
901
+ description="Every single change with its grade and the old and new value.",
902
+ )
903
+ is_breaking: bool = Field(
904
+ description="Whether any detected change is classified as an error-level breaking change.",
905
+ )
906
+
907
+
884
908
  @app.post(
885
909
  "/changelog",
886
910
  tags=["changelog"],
@@ -935,6 +959,54 @@ async def changelog_endpoint(
935
959
  os.unlink(v2_path)
936
960
 
937
961
 
962
+ @app.post(
963
+ "/breaking",
964
+ tags=["breaking"],
965
+ operation_id="breakingChangesDataContracts",
966
+ summary="Show compatibility impact between two data contracts.",
967
+ description="""
968
+ Compare two versions of an ODCS data contract and detect backward-incompatible changes.
969
+
970
+ `POST` a JSON body with `v1` (before) and `v2` (after) as YAML strings. A contract that cannot be
971
+ parsed is answered with `422`.
972
+ """,
973
+ response_description="The breaking changes detected between the two data contracts.",
974
+ responses={
975
+ **AUTHENTICATION_RESPONSES,
976
+ 422: {
977
+ "description": "One of the two data contracts is not valid YAML or not a valid data contract.",
978
+ "model": UnprocessableEntityResponse,
979
+ "content": {"application/json": {"example": {"detail": "Invalid YAML: while parsing a block mapping"}}},
980
+ },
981
+ },
982
+ )
983
+ def breaking_endpoint(
984
+ body: ChangelogRequest,
985
+ api_key: Annotated[str | None, Depends(api_key_header)] = None,
986
+ ) -> BreakingChangesResponse:
987
+ check_api_key(api_key)
988
+
989
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f1:
990
+ f1.write(body.v1)
991
+ v1_path = f1.name
992
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f2:
993
+ f2.write(body.v2)
994
+ v2_path = f2.name
995
+
996
+ try:
997
+ result = DataContract(data_contract_file=v1_path).breaking(DataContract(data_contract_file=v2_path))
998
+ return BreakingChangesResponse(summary=result.summary, entries=result.entries, is_breaking=result.is_breaking)
999
+ except yaml.YAMLError as e:
1000
+ raise HTTPException(status_code=422, detail=f"Invalid YAML: {e}")
1001
+ except pydantic.ValidationError as e:
1002
+ raise HTTPException(status_code=422, detail=f"Invalid data contract: {e}")
1003
+ except DataContractException as e:
1004
+ raise HTTPException(status_code=422, detail=f"Data Contract Validation Failure: {e}")
1005
+ finally:
1006
+ os.unlink(v1_path)
1007
+ os.unlink(v2_path)
1008
+
1009
+
938
1010
  @app.post(
939
1011
  "/export",
940
1012
  tags=["export"],
@@ -0,0 +1,74 @@
1
+ from collections import defaultdict
2
+ from collections.abc import Iterable
3
+
4
+ from datacontract.breaking.rules import DEFAULT_RULES, BreakingChangeRule
5
+ from datacontract.model.breaking import BreakingChangeEntry, BreakingChangeLevel, BreakingChangeResult
6
+ from datacontract.model.changelog import ChangelogEntry, ChangelogResult, ChangelogType
7
+
8
+ _LEVEL_ORDER = {
9
+ BreakingChangeLevel.INFO: 0,
10
+ BreakingChangeLevel.WARNING: 1,
11
+ BreakingChangeLevel.ERROR: 2,
12
+ }
13
+
14
+
15
+ class BreakingChangeDetector:
16
+ """Classify detailed changelog entries using an ordered rule set."""
17
+
18
+ def __init__(self, rules: Iterable[BreakingChangeRule] = DEFAULT_RULES):
19
+ self._rules = tuple(rules)
20
+ if not self._rules:
21
+ raise ValueError("At least one breaking-change rule is required")
22
+
23
+ def detect(self, changelog: ChangelogResult) -> BreakingChangeResult:
24
+ entries = [self._classify(entry) for entry in changelog.entries]
25
+ # Nothing inside a newly added element can break a consumer: it did not exist before.
26
+ added = {entry.path for entry in entries if entry.change_type == ChangelogType.added}
27
+ for entry in entries:
28
+ segments = entry.path.split(".")
29
+ if any(".".join(segments[:i]) in added for i in range(1, len(segments))):
30
+ entry.level = BreakingChangeLevel.INFO
31
+ entries_by_prefix = defaultdict(list)
32
+ for entry in entries:
33
+ prefix = ""
34
+ for segment in entry.path.split("."):
35
+ prefix = f"{prefix}.{segment}" if prefix else segment
36
+ entries_by_prefix[prefix].append(entry)
37
+ summary = [self._summarize(entry, entries_by_prefix.get(entry.path, [])) for entry in changelog.summary]
38
+ return BreakingChangeResult(v1=changelog.v1, v2=changelog.v2, summary=summary, entries=entries)
39
+
40
+ def _classify(self, entry: ChangelogEntry) -> BreakingChangeEntry:
41
+ for rule in self._rules:
42
+ evaluation = rule.evaluate(entry)
43
+ if evaluation is not None:
44
+ return BreakingChangeEntry(
45
+ path=entry.path,
46
+ change_type=entry.type,
47
+ level=evaluation.level,
48
+ message=evaluation.message,
49
+ rule_id=evaluation.rule_id,
50
+ old_value=entry.old_value,
51
+ new_value=entry.new_value,
52
+ )
53
+ raise ValueError(f"No breaking-change rule classified {entry.path}")
54
+
55
+ @staticmethod
56
+ def _summarize(summary_entry: ChangelogEntry, entries: list[BreakingChangeEntry]) -> BreakingChangeEntry:
57
+ if not entries:
58
+ return BreakingChangeEntry(
59
+ path=summary_entry.path,
60
+ change_type=summary_entry.type,
61
+ level=BreakingChangeLevel.INFO,
62
+ message=f"Changed contract at {summary_entry.path}",
63
+ rule_id="summary-fallback",
64
+ )
65
+ highest = max(entries, key=lambda entry: _LEVEL_ORDER[entry.level])
66
+ return BreakingChangeEntry(
67
+ path=summary_entry.path,
68
+ change_type=summary_entry.type,
69
+ level=highest.level,
70
+ message=f"{highest.level.value.capitalize()} impact at {summary_entry.path}",
71
+ rule_id=f"summary:{highest.rule_id}",
72
+ old_value=highest.old_value,
73
+ new_value=highest.new_value,
74
+ )
@@ -0,0 +1,196 @@
1
+ from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass
3
+ from datetime import date
4
+
5
+ from datacontract.model.breaking import BreakingChangeLevel
6
+ from datacontract.model.changelog import ChangelogEntry, ChangelogType
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class RuleEvaluation:
11
+ rule_id: str
12
+ level: BreakingChangeLevel
13
+ message: str
14
+
15
+
16
+ class BreakingChangeRule(ABC):
17
+ rule_id: str
18
+
19
+ @abstractmethod
20
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
21
+ """Return a classification when this rule applies to ``entry``."""
22
+
23
+
24
+ class SchemaRemovedRule(BreakingChangeRule):
25
+ rule_id = "schema-removed"
26
+
27
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
28
+ segments = entry.path.split(".")
29
+ if entry.type == ChangelogType.removed and len(segments) == 2 and segments[0] == "schema":
30
+ return RuleEvaluation(self.rule_id, BreakingChangeLevel.ERROR, f"Removed schema {segments[1]}")
31
+ return None
32
+
33
+
34
+ class FieldRemovedRule(BreakingChangeRule):
35
+ rule_id = "field-removed"
36
+
37
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
38
+ segments = entry.path.split(".")
39
+ if entry.type != ChangelogType.removed or not _is_schema_property_path(segments):
40
+ return None
41
+ property_name = segments[-1]
42
+ return RuleEvaluation(self.rule_id, BreakingChangeLevel.ERROR, f"Removed property {property_name}")
43
+
44
+
45
+ class RequiredChangedRule(BreakingChangeRule):
46
+ rule_id = "required-changed"
47
+
48
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
49
+ if not entry.path.endswith(".required"):
50
+ return None
51
+ old = _parse_bool(entry.old_value)
52
+ new = _parse_bool(entry.new_value)
53
+ if entry.type == ChangelogType.added and new is True:
54
+ level = BreakingChangeLevel.ERROR
55
+ elif entry.type == ChangelogType.removed or new is False:
56
+ # Dropping the requirement, or writing out the optional default, only loosens the contract.
57
+ level = BreakingChangeLevel.INFO
58
+ elif entry.type == ChangelogType.updated and old is False and new is True:
59
+ level = BreakingChangeLevel.ERROR
60
+ elif entry.type in (ChangelogType.added, ChangelogType.updated):
61
+ level = BreakingChangeLevel.WARNING
62
+ else:
63
+ return None
64
+ return RuleEvaluation(self.rule_id, level, _change_message("requiredness", entry))
65
+
66
+
67
+ class TypeChangedRule(BreakingChangeRule):
68
+ rule_id = "type-changed"
69
+
70
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
71
+ if not entry.path.endswith((".logicalType", ".physicalType")):
72
+ return None
73
+ if entry.type == ChangelogType.updated:
74
+ level = BreakingChangeLevel.ERROR
75
+ elif entry.type == ChangelogType.added:
76
+ level = BreakingChangeLevel.INFO
77
+ elif entry.type == ChangelogType.removed:
78
+ level = BreakingChangeLevel.WARNING
79
+ else:
80
+ return None
81
+ return RuleEvaluation(self.rule_id, level, _change_message("type", entry))
82
+
83
+
84
+ class UniqueConstraintRule(BreakingChangeRule):
85
+ rule_id = "unique-constraint-changed"
86
+
87
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
88
+ if not entry.path.endswith(".unique"):
89
+ return None
90
+ old = _parse_bool(entry.old_value)
91
+ new = _parse_bool(entry.new_value)
92
+ if new is True and old is not True:
93
+ level = BreakingChangeLevel.ERROR
94
+ elif old is True and new is not True:
95
+ level = BreakingChangeLevel.INFO
96
+ else:
97
+ level = BreakingChangeLevel.WARNING
98
+ return RuleEvaluation(self.rule_id, level, _change_message("uniqueness", entry))
99
+
100
+
101
+ class KeyConstraintRule(BreakingChangeRule):
102
+ rule_id = "key-constraint-changed"
103
+
104
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
105
+ if not entry.path.endswith((".primaryKey", ".primary_key")):
106
+ return None
107
+ return RuleEvaluation(self.rule_id, BreakingChangeLevel.WARNING, _change_message("key constraint", entry))
108
+
109
+
110
+ class ValidationConstraintRule(BreakingChangeRule):
111
+ rule_id = "validation-constraint-changed"
112
+ _suffixes = (
113
+ ".pattern",
114
+ ".minLength",
115
+ ".maxLength",
116
+ ".minimum",
117
+ ".maximum",
118
+ ".exclusiveMinimum",
119
+ ".exclusiveMaximum",
120
+ )
121
+
122
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
123
+ if not entry.path.endswith(self._suffixes):
124
+ return None
125
+ old = _parse_number(entry.old_value)
126
+ new = _parse_number(entry.new_value)
127
+ if old is None or new is None:
128
+ level = BreakingChangeLevel.WARNING
129
+ elif _is_tightening(entry.path, old, new):
130
+ level = BreakingChangeLevel.ERROR
131
+ else:
132
+ level = BreakingChangeLevel.INFO
133
+ return RuleEvaluation(self.rule_id, level, _change_message("validation constraint", entry))
134
+
135
+
136
+ class MetadataFallbackRule(BreakingChangeRule):
137
+ rule_id = "metadata-or-unknown-change"
138
+
139
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation:
140
+ return RuleEvaluation(self.rule_id, BreakingChangeLevel.INFO, _change_message("contract", entry))
141
+
142
+
143
+ def _is_schema_property_path(segments: list[str]) -> bool:
144
+ return len(segments) >= 3 and segments[0] == "schema" and segments[-2] == "properties"
145
+
146
+
147
+ def _parse_bool(value: str | None) -> bool | None:
148
+ if value is None:
149
+ return None
150
+ normalized = value.strip().lower()
151
+ if normalized in {"true", "1"}:
152
+ return True
153
+ if normalized in {"false", "0"}:
154
+ return False
155
+ return None
156
+
157
+
158
+ def _parse_number(value: str | None) -> float | None:
159
+ if value is None:
160
+ return None
161
+ normalized = value.strip()
162
+ try:
163
+ return float(normalized)
164
+ except ValueError:
165
+ try:
166
+ return float(date.fromisoformat(normalized).toordinal())
167
+ except ValueError:
168
+ return None
169
+
170
+
171
+ def _is_tightening(path: str, old: float, new: float) -> bool:
172
+ if path.endswith((".minLength", ".minimum", ".exclusiveMinimum")):
173
+ return new > old
174
+ if path.endswith((".maxLength", ".maximum", ".exclusiveMaximum")):
175
+ return new < old
176
+ return True
177
+
178
+
179
+ def _change_message(subject: str, entry: ChangelogEntry) -> str:
180
+ if entry.type == ChangelogType.added:
181
+ return f"Added {subject} at {entry.path}"
182
+ if entry.type == ChangelogType.removed:
183
+ return f"Removed {subject} at {entry.path}"
184
+ return f"Changed {subject} at {entry.path} from {entry.old_value!r} to {entry.new_value!r}"
185
+
186
+
187
+ DEFAULT_RULES: tuple[BreakingChangeRule, ...] = (
188
+ RequiredChangedRule(),
189
+ SchemaRemovedRule(),
190
+ FieldRemovedRule(),
191
+ TypeChangedRule(),
192
+ UniqueConstraintRule(),
193
+ KeyConstraintRule(),
194
+ ValidationConstraintRule(),
195
+ MetadataFallbackRule(),
196
+ )
@@ -28,6 +28,7 @@ COMMAND_ORDER = [
28
28
  "edit",
29
29
  "lint",
30
30
  "changelog",
31
+ "breaking",
31
32
  "sync", # `dbt sync` subcommand; no top-level `sync`, so this only orders the dbt group
32
33
  "test",
33
34
  "ci",
@@ -217,11 +218,19 @@ def enable_debug_logging(debug: bool, otherwise_disable_stderr: bool = False):
217
218
  logging.getLogger(noisy_logger).setLevel(logging.ERROR)
218
219
 
219
220
 
220
- def validate_publish_url(publish: str | None) -> None:
221
- """Reject `--publish` values that aren't http/https before any real work runs."""
222
- if publish is not None and not (publish.startswith("http://") or publish.startswith("https://")):
221
+ def validate_publish_url(publish: str | None) -> str | None:
222
+ """Normalize `--publish` and reject values that aren't http/https before any real work runs.
223
+
224
+ An empty value means "don't publish". CI templates that render the URL from an unset variable
225
+ pass `--publish ''` rather than omitting the option, e.g. GitHub Actions container actions,
226
+ where an argument list cannot drop an entry conditionally.
227
+ """
228
+ if not publish:
229
+ return None
230
+ if not (publish.startswith("http://") or publish.startswith("https://")):
223
231
  console.print(f"[red]--publish URL must start with http:// or https:// (got: {publish!r}).[/red]")
224
232
  raise typer.Exit(code=1)
233
+ return publish
225
234
 
226
235
 
227
236
  def resolve_output_format(output_format: Optional[OutputFormat], output: Optional[Path]) -> Optional[OutputFormat]:
@@ -263,6 +272,7 @@ def _print_publish_failure(run, out=None):
263
272
  # Display order for `--help` is controlled by COMMAND_ORDER above, not by import order.
264
273
  from datacontract import ( # noqa: E402, F401
265
274
  command_api,
275
+ command_breaking,
266
276
  command_catalog,
267
277
  command_changelog,
268
278
  command_ci,
@@ -0,0 +1,39 @@
1
+ import typer
2
+ from typing_extensions import Annotated
3
+
4
+ from datacontract.cli import app, console, debug_option, enable_debug_logging
5
+ from datacontract.config import cli_config
6
+ from datacontract.data_contract import DataContract
7
+ from datacontract.output.text_breaking_results import write_text_breaking_results
8
+
9
+
10
+ @app.command(
11
+ name="breaking",
12
+ epilog="Example: datacontract breaking datacontract-v1.yaml datacontract-v2.yaml",
13
+ )
14
+ def breaking(
15
+ v1: Annotated[
16
+ str,
17
+ typer.Argument(help="The location (url, s3 url, or local path) of the source (before) data contract YAML."),
18
+ ],
19
+ v2: Annotated[
20
+ str,
21
+ typer.Argument(help="The location (url, s3 url, or local path) of the target (after) data contract YAML."),
22
+ ],
23
+ inline_references: Annotated[
24
+ bool,
25
+ typer.Option(
26
+ help="Resolve external references (currently: authoritativeDefinitions\\[type in {definition, semantics}]) "
27
+ "in the contract and inline the fetched content from the configured entropy-data host."
28
+ ),
29
+ ] = True,
30
+ debug: debug_option = None,
31
+ ):
32
+ """Show compatibility impact between two data contracts."""
33
+ enable_debug_logging(debug)
34
+ result = DataContract(config=cli_config(), data_contract_file=v1, inline_references=inline_references).breaking(
35
+ DataContract(config=cli_config(), data_contract_file=v2, inline_references=inline_references)
36
+ )
37
+ write_text_breaking_results(result, console)
38
+ if result.is_breaking:
39
+ raise typer.Exit(code=1)
@@ -92,7 +92,7 @@ def ci(
92
92
  Run tests for CI/CD pipelines. Emits GitHub Actions annotations and step summary.
93
93
  """
94
94
  enable_debug_logging(debug, otherwise_disable_stderr=True)
95
- validate_publish_url(publish)
95
+ publish = validate_publish_url(publish)
96
96
 
97
97
  if not locations:
98
98
  locations = ["datacontract.yaml"]
@@ -347,7 +347,7 @@ def sync_command(
347
347
  the generated tests.
348
348
  """
349
349
  enable_debug_logging(debug)
350
- validate_publish_url(publish)
350
+ publish = validate_publish_url(publish)
351
351
 
352
352
  if publish is not None and not run_tests_flag:
353
353
  console.print("[red]--publish requires --run-tests.[/red]")
@@ -476,7 +476,7 @@ def test_command(
476
476
  them. Use `datacontract dbt sync` to create and update the tests first.
477
477
  """
478
478
  enable_debug_logging(debug)
479
- validate_publish_url(publish)
479
+ publish = validate_publish_url(publish)
480
480
  check_dbt_on_path()
481
481
 
482
482
  explicit_project_dir = project_dir is not None
@@ -66,6 +66,7 @@ def _export(
66
66
  inline_references: bool = True,
67
67
  clickhouse_engine: Optional[str] = None,
68
68
  clickhouse_order_by: Optional[str] = None,
69
+ suite_name: Optional[str] = None,
69
70
  ):
70
71
  result = DataContract(
71
72
  config=cli_config(),
@@ -83,6 +84,7 @@ def _export(
83
84
  template=template,
84
85
  clickhouse_engine=clickhouse_engine,
85
86
  clickhouse_order_by=clickhouse_order_by,
87
+ suite_name=suite_name,
86
88
  )
87
89
  if output is None:
88
90
  console.print(result, markup=False, soft_wrap=True)
@@ -587,6 +589,10 @@ def export_great_expectations(
587
589
  schema: schema_option = None,
588
590
  inline_references: inline_references_option = True,
589
591
  debug: debug_option = None,
592
+ suite_name: Annotated[
593
+ Optional[str],
594
+ typer.Option(help="The suite name for the Great Expectations run."),
595
+ ] = None,
590
596
  ):
591
597
  """Export a data contract to Great Expectations suite."""
592
598
  enable_debug_logging(debug)
@@ -600,6 +606,7 @@ def export_great_expectations(
600
606
  engine=engine.value if engine is not None else None,
601
607
  sql_server_type=dialect.value,
602
608
  inline_references=inline_references,
609
+ suite_name=suite_name,
603
610
  )
604
611
 
605
612
 
@@ -218,6 +218,13 @@ def test(
218
218
  "Checks that read row values are skipped."
219
219
  ),
220
220
  ] = False,
221
+ dry_run: Annotated[
222
+ bool,
223
+ typer.Option(
224
+ help="Report the checks that would run, without connecting to the server or reading any data. "
225
+ "Reported checks have the result 'skipped', or 'warning' where a check could not be planned."
226
+ ),
227
+ ] = False,
221
228
  include_failed_samples: Annotated[
222
229
  bool,
223
230
  typer.Option(
@@ -243,7 +250,7 @@ def test(
243
250
  Run schema and quality tests on configured servers.
244
251
  """
245
252
  enable_debug_logging(debug, otherwise_disable_stderr=True)
246
- validate_publish_url(publish)
253
+ publish = validate_publish_url(publish)
247
254
 
248
255
  check_categories = _parse_enum_csv(
249
256
  checks,
@@ -284,6 +291,7 @@ def test(
284
291
  filter=filter,
285
292
  filters=parsed_filters,
286
293
  metadata_only=metadata_only,
294
+ dry_run=dry_run,
287
295
  ).test()
288
296
  if logs:
289
297
  _print_logs(run)
@@ -162,6 +162,7 @@ class Config(BaseSettings):
162
162
  kafka_schema_registry_password: SecretStr | None = None
163
163
  kafka_max_messages: int | None = None
164
164
  kafka_timeout: int | None = None
165
+ kafka_group_prefix: str | None = None
165
166
 
166
167
  # mysql
167
168
  mysql_username: str | None = None
@@ -588,6 +589,9 @@ class Config(BaseSettings):
588
589
  def get_kafka_timeout(self) -> int | None:
589
590
  return self._int_option("kafka_timeout")
590
591
 
592
+ def get_kafka_group_prefix(self, required: bool = False) -> str | None:
593
+ return self._str_option("kafka_group_prefix", required)
594
+
591
595
  # --- mysql ---
592
596
  def get_mysql_username(self, required: bool = False) -> str | None:
593
597
  return self._str_option("mysql_username", required)