datacontract-cli 1.1.2__tar.gz → 1.2.0__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 (513) hide show
  1. {datacontract_cli-1.1.2/datacontract_cli.egg-info → datacontract_cli-1.2.0}/PKG-INFO +12 -8
  2. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/README.md +3 -0
  3. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/api.py +73 -1
  4. datacontract_cli-1.2.0/datacontract/breaking/detector.py +101 -0
  5. datacontract_cli-1.2.0/datacontract/breaking/rules.py +235 -0
  6. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/changelog/normalize.py +70 -5
  7. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/cli.py +13 -3
  8. datacontract_cli-1.2.0/datacontract/command_breaking.py +39 -0
  9. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_ci.py +1 -1
  10. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_dbt.py +2 -2
  11. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_export.py +7 -0
  12. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_import.py +31 -5
  13. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_test.py +9 -1
  14. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/config/settings.py +64 -17
  15. datacontract_cli-1.2.0/datacontract/config/variables.py +133 -0
  16. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/data_contract.py +16 -3
  17. datacontract_cli-1.2.0/datacontract/editor_assets/VERSION +1 -0
  18. datacontract_cli-1.2.0/datacontract/editor_assets/assets/editor.worker-4.7.0.js +33 -0
  19. datacontract_cli-1.2.0/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +452 -0
  20. datacontract_cli-1.2.0/datacontract/editor_assets/datacontract-editor.css +2 -0
  21. datacontract_cli-1.2.0/datacontract/editor_assets/datacontract-editor.es.js +84438 -0
  22. datacontract_cli-1.2.0/datacontract/editor_assets/index.html +81 -0
  23. datacontract_cli-1.2.0/datacontract/editor_assets/monaco-4.7.0.js +114821 -0
  24. datacontract_cli-1.2.0/datacontract/editor_assets/robots.txt +17 -0
  25. datacontract_cli-1.2.0/datacontract/editor_assets/rolldown-runtime-DY7j01NX.js +30 -0
  26. datacontract_cli-1.2.0/datacontract/editor_assets/sitemap.xml +17 -0
  27. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/checks/check_spec.py +6 -0
  28. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/checks/create_checks.py +89 -30
  29. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/checks/dimensions.py +3 -0
  30. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/checks/type_normalize.py +76 -6
  31. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/data_contract_test.py +140 -12
  32. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/fastjsonschema/check_jsonschema.py +17 -1
  33. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/connect.py +25 -5
  34. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/duckdb_connection.py +51 -12
  35. datacontract_cli-1.2.0/datacontract/engines/ibis/connections/iceberg.py +216 -0
  36. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/kafka.py +17 -4
  37. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/dtype_category.py +17 -15
  38. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/ibis_check_execute.py +52 -3
  39. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/snowflake_structured_types.py +9 -4
  40. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/avro_exporter.py +37 -51
  41. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/avro_idl_exporter.py +36 -0
  42. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/bigquery_exporter.py +6 -1
  43. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/data_caterer_exporter.py +2 -28
  44. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/dcs_exporter.py +22 -2
  45. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/duckdb_type_converter.py +1 -1
  46. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/exporter.py +6 -1
  47. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/go_exporter.py +15 -0
  48. datacontract_cli-1.2.0/datacontract/export/great_expectations_exporter.py +716 -0
  49. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/iceberg_exporter.py +14 -30
  50. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/jsonschema_exporter.py +23 -29
  51. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/protobuf_exporter.py +29 -4
  52. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/pydantic_exporter.py +30 -0
  53. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/rdf_exporter.py +44 -9
  54. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/sodacl_check_builder.py +5 -4
  55. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/spark_exporter.py +14 -20
  56. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/sql_type_converter.py +86 -16
  57. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/sqlalchemy_exporter.py +5 -0
  58. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/avro_importer.py +9 -7
  59. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/dcs_importer.py +17 -26
  60. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/excel_importer.py +23 -5
  61. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/glue_importer.py +5 -2
  62. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/iceberg_importer.py +71 -22
  63. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/jsonschema_importer.py +2 -12
  64. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/odcs_helper.py +83 -4
  65. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/parquet_importer.py +17 -1
  66. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/postgres_importer.py +4 -1
  67. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/protobuf_importer.py +2 -1
  68. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/snowflake_importer.py +4 -1
  69. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/spark_importer.py +7 -1
  70. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/spark_type_json.py +12 -1
  71. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/sql_importer.py +111 -24
  72. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/unity_importer.py +17 -9
  73. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/init/init_template.py +1 -1
  74. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/integration/dbt_test_mapping.py +3 -28
  75. datacontract_cli-1.2.0/datacontract/lint/constraints.py +50 -0
  76. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/lint/resolve.py +286 -24
  77. datacontract_cli-1.2.0/datacontract/model/breaking.py +33 -0
  78. datacontract_cli-1.2.0/datacontract/model/enum_values.py +60 -0
  79. datacontract_cli-1.2.0/datacontract/model/map_type.py +74 -0
  80. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/model/run.py +15 -0
  81. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/model/server.py +25 -0
  82. datacontract_cli-1.2.0/datacontract/model/vector_type.py +110 -0
  83. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/output/test_results_writer.py +5 -0
  84. datacontract_cli-1.2.0/datacontract/output/text_breaking_results.py +81 -0
  85. datacontract_cli-1.1.2/datacontract/schemas/odcs-3.1.0.init.yaml → datacontract_cli-1.2.0/datacontract/schemas/odcs-3.2.0.init.yaml +1 -1
  86. datacontract_cli-1.2.0/datacontract/schemas/odcs-3.2.0.schema.json +4118 -0
  87. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/datacontract_odcs.html +1 -0
  88. datacontract_cli-1.2.0/datacontract/templates/macros/context.html +64 -0
  89. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/macros/schema.html +41 -0
  90. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/macros/server.html +11 -1
  91. datacontract_cli-1.2.0/datacontract/templates/partials_odcs/context.html +16 -0
  92. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/custom_properties.html +3 -0
  93. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/schema.html +17 -0
  94. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/sla.html +30 -0
  95. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0/datacontract_cli.egg-info}/PKG-INFO +12 -8
  96. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract_cli.egg-info/SOURCES.txt +38 -87
  97. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract_cli.egg-info/requires.txt +8 -7
  98. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/pyproject.toml +10 -8
  99. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_api.py +22 -0
  100. datacontract_cli-1.2.0/tests/test_breaking.py +337 -0
  101. datacontract_cli-1.2.0/tests/test_breaking_odcs_3_2.py +94 -0
  102. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_cli.py +30 -0
  103. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_config_file.py +7 -0
  104. datacontract_cli-1.2.0/tests/test_create_checks_array_items.py +71 -0
  105. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_create_checks_nested_type.py +21 -9
  106. datacontract_cli-1.2.0/tests/test_create_checks_retention_period.py +57 -0
  107. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_create_checks_servicelevel.py +25 -0
  108. datacontract_cli-1.2.0/tests/test_description_linter.py +0 -0
  109. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_dtype_category.py +13 -5
  110. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_duckdb_json.py +48 -0
  111. datacontract_cli-1.2.0/tests/test_enum_values.py +177 -0
  112. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_avro.py +17 -0
  113. datacontract_cli-1.2.0/tests/test_export_great_expectations.py +1508 -0
  114. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_jsonschema.py +19 -1
  115. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_odcs_v3.py +10 -0
  116. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_rdf.py +37 -30
  117. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_sodacl.py +41 -3
  118. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_athena.py +1 -1
  119. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_avro.py +53 -18
  120. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_csv.py +1 -1
  121. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_excel.py +10 -1
  122. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_iceberg.py +53 -18
  123. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_mysql.py +1 -1
  124. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_parquet.py +11 -2
  125. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_postgres.py +1 -1
  126. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_powerbi.py +1 -1
  127. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_redshift.py +1 -1
  128. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_snowflake.py +1 -1
  129. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_spark_type_json.py +1 -1
  130. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_sql_oracle.py +3 -3
  131. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_sql_postgres.py +26 -3
  132. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_sql_snowflake.py +43 -2
  133. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_sql_sqlserver.py +2 -2
  134. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_lint.py +10 -0
  135. datacontract_cli-1.2.0/tests/test_lint_odcs_3_2_constraints.py +94 -0
  136. datacontract_cli-1.2.0/tests/test_map_type.py +313 -0
  137. datacontract_cli-1.2.0/tests/test_metadata_fields.py +128 -0
  138. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_resolve.py +37 -0
  139. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_resolve_definitions.py +45 -5
  140. datacontract_cli-1.2.0/tests/test_resolve_local_definitions.py +615 -0
  141. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_roundtrip_pydantic_model.py +2 -1
  142. datacontract_cli-1.2.0/tests/test_servers_3_2_0.py +143 -0
  143. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_snowflake_structured_types.py +11 -4
  144. datacontract_cli-1.2.0/tests/test_test_array_items.py +109 -0
  145. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_dimension_filter.py +3 -0
  146. datacontract_cli-1.2.0/tests/test_test_dry_run.py +175 -0
  147. datacontract_cli-1.2.0/tests/test_test_iceberg.py +347 -0
  148. datacontract_cli-1.2.0/tests/test_test_iceberg_rest.py +187 -0
  149. datacontract_cli-1.2.0/tests/test_test_iceberg_s3tables.py +164 -0
  150. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_kafka_decoding.py +20 -0
  151. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_parquet.py +1 -1
  152. datacontract_cli-1.2.0/tests/test_test_variables.py +159 -0
  153. datacontract_cli-1.2.0/tests/test_variables.py +157 -0
  154. datacontract_cli-1.2.0/tests/test_vector_type.py +338 -0
  155. datacontract_cli-1.1.2/datacontract/editor_assets/VERSION +0 -1
  156. datacontract_cli-1.1.2/datacontract/editor_assets/abap-Bs8kvjsq.js +0 -1398
  157. datacontract_cli-1.1.2/datacontract/editor_assets/apex-Dspwrl5m.js +0 -326
  158. datacontract_cli-1.1.2/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -9037
  159. datacontract_cli-1.1.2/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -26455
  160. datacontract_cli-1.1.2/datacontract/editor_assets/azcli-k1BiOau1.js +0 -68
  161. datacontract_cli-1.1.2/datacontract/editor_assets/bat-BIP72KWc.js +0 -100
  162. datacontract_cli-1.1.2/datacontract/editor_assets/bicep-VhQeYhS3.js +0 -102
  163. datacontract_cli-1.1.2/datacontract/editor_assets/cameligo-DnuAXtHg.js +0 -174
  164. datacontract_cli-1.1.2/datacontract/editor_assets/clojure-BAuDPsal.js +0 -761
  165. datacontract_cli-1.1.2/datacontract/editor_assets/coffee-BV06qSnj.js +0 -232
  166. datacontract_cli-1.1.2/datacontract/editor_assets/cpp-Cz8Jeyrf.js +0 -389
  167. datacontract_cli-1.1.2/datacontract/editor_assets/csharp-F6hhlXFb.js +0 -326
  168. datacontract_cli-1.1.2/datacontract/editor_assets/csp-KzlEHCyI.js +0 -53
  169. datacontract_cli-1.1.2/datacontract/editor_assets/css-e4FKntZ3.js +0 -187
  170. datacontract_cli-1.1.2/datacontract/editor_assets/cssMode-BNkTa2xp.js +0 -1618
  171. datacontract_cli-1.1.2/datacontract/editor_assets/cypher-CpvDGKRr.js +0 -263
  172. datacontract_cli-1.1.2/datacontract/editor_assets/dart-DdHeFWR0.js +0 -281
  173. datacontract_cli-1.1.2/datacontract/editor_assets/datacontract-editor.css +0 -1
  174. datacontract_cli-1.1.2/datacontract/editor_assets/datacontract-editor.es.js +0 -78027
  175. datacontract_cli-1.1.2/datacontract/editor_assets/dockerfile-aoNXDcio.js +0 -130
  176. datacontract_cli-1.1.2/datacontract/editor_assets/ecl-C4Q0DYuA.js +0 -456
  177. datacontract_cli-1.1.2/datacontract/editor_assets/elixir-C9X42b0T.js +0 -569
  178. datacontract_cli-1.1.2/datacontract/editor_assets/flow9-Bff42pfB.js +0 -142
  179. datacontract_cli-1.1.2/datacontract/editor_assets/freemarker2-Dyfzmb5A.js +0 -989
  180. datacontract_cli-1.1.2/datacontract/editor_assets/fsharp-C6vPAsHG.js +0 -217
  181. datacontract_cli-1.1.2/datacontract/editor_assets/go-DEr8zx9f.js +0 -218
  182. datacontract_cli-1.1.2/datacontract/editor_assets/graphql-BiNBBRFh.js +0 -151
  183. datacontract_cli-1.1.2/datacontract/editor_assets/handlebars-BtDNI-uC.js +0 -419
  184. datacontract_cli-1.1.2/datacontract/editor_assets/hcl-2T9lKuFg.js +0 -183
  185. datacontract_cli-1.1.2/datacontract/editor_assets/html-Cn4TGw_o.js +0 -308
  186. datacontract_cli-1.1.2/datacontract/editor_assets/htmlMode-Bf84vbo2.js +0 -1628
  187. datacontract_cli-1.1.2/datacontract/editor_assets/index.html +0 -31
  188. datacontract_cli-1.1.2/datacontract/editor_assets/ini-CZGtssYM.js +0 -71
  189. datacontract_cli-1.1.2/datacontract/editor_assets/java-B260NeH3.js +0 -232
  190. datacontract_cli-1.1.2/datacontract/editor_assets/javascript-B86Kac07.js +0 -70
  191. datacontract_cli-1.1.2/datacontract/editor_assets/jsonMode-Ckgg5lAE.js +0 -2051
  192. datacontract_cli-1.1.2/datacontract/editor_assets/julia-kuNLM9c5.js +0 -511
  193. datacontract_cli-1.1.2/datacontract/editor_assets/kotlin-Bz6kAefA.js +0 -253
  194. datacontract_cli-1.1.2/datacontract/editor_assets/less-AZUtS89I.js +0 -162
  195. datacontract_cli-1.1.2/datacontract/editor_assets/lexon-BcmgnyRb.js +0 -157
  196. datacontract_cli-1.1.2/datacontract/editor_assets/liquid-D0NPwuu_.js +0 -240
  197. datacontract_cli-1.1.2/datacontract/editor_assets/lua-Dz1RbATg.js +0 -162
  198. datacontract_cli-1.1.2/datacontract/editor_assets/m3-CIMooLFn.js +0 -210
  199. datacontract_cli-1.1.2/datacontract/editor_assets/markdown-C1BsCK9P.js +0 -229
  200. datacontract_cli-1.1.2/datacontract/editor_assets/mdx-QFRSBtVQ.js +0 -165
  201. datacontract_cli-1.1.2/datacontract/editor_assets/mips-BovsnfLQ.js +0 -198
  202. datacontract_cli-1.1.2/datacontract/editor_assets/monaco-4.7.0.js +0 -125918
  203. datacontract_cli-1.1.2/datacontract/editor_assets/msdax-CiRB2ZB-.js +0 -375
  204. datacontract_cli-1.1.2/datacontract/editor_assets/mysql-BwdpPE19.js +0 -878
  205. datacontract_cli-1.1.2/datacontract/editor_assets/objective-c-D4nfHfso.js +0 -183
  206. datacontract_cli-1.1.2/datacontract/editor_assets/pascal--j5-PYtz.js +0 -251
  207. datacontract_cli-1.1.2/datacontract/editor_assets/pascaligo-C7TcJxNL.js +0 -164
  208. datacontract_cli-1.1.2/datacontract/editor_assets/perl-BzEWqUb5.js +0 -626
  209. datacontract_cli-1.1.2/datacontract/editor_assets/pgsql-B_KZ0mGX.js +0 -851
  210. datacontract_cli-1.1.2/datacontract/editor_assets/php-A19QHzQV.js +0 -500
  211. datacontract_cli-1.1.2/datacontract/editor_assets/pla-COeKY1hA.js +0 -137
  212. datacontract_cli-1.1.2/datacontract/editor_assets/postiats-BfMp7zJL.js +0 -907
  213. datacontract_cli-1.1.2/datacontract/editor_assets/powerquery-B0TS_5Gb.js +0 -890
  214. datacontract_cli-1.1.2/datacontract/editor_assets/powershell-5jSbKdYB.js +0 -239
  215. datacontract_cli-1.1.2/datacontract/editor_assets/protobuf-YgnOutn3.js +0 -420
  216. datacontract_cli-1.1.2/datacontract/editor_assets/pug-DLej6kn5.js +0 -402
  217. datacontract_cli-1.1.2/datacontract/editor_assets/python-C8RW9B6A.js +0 -301
  218. datacontract_cli-1.1.2/datacontract/editor_assets/qsharp-AhjqtSHB.js +0 -301
  219. datacontract_cli-1.1.2/datacontract/editor_assets/r-D-F4P80w.js +0 -243
  220. datacontract_cli-1.1.2/datacontract/editor_assets/razor-CLZqdY_r.js +0 -550
  221. datacontract_cli-1.1.2/datacontract/editor_assets/redis-hwwIlMnV.js +0 -302
  222. datacontract_cli-1.1.2/datacontract/editor_assets/redshift-Bcm_kjEG.js +0 -809
  223. datacontract_cli-1.1.2/datacontract/editor_assets/restructuredtext-CrdzfPP-.js +0 -174
  224. datacontract_cli-1.1.2/datacontract/editor_assets/ruby-QC2UNm1s.js +0 -511
  225. datacontract_cli-1.1.2/datacontract/editor_assets/rust-5aqiQ3L5.js +0 -343
  226. datacontract_cli-1.1.2/datacontract/editor_assets/sb-B1g1ZfLJ.js +0 -115
  227. datacontract_cli-1.1.2/datacontract/editor_assets/scala-C2U4R5Gb.js +0 -370
  228. datacontract_cli-1.1.2/datacontract/editor_assets/scheme-DeFRbslr.js +0 -108
  229. datacontract_cli-1.1.2/datacontract/editor_assets/scss-RSTCiCmI.js +0 -262
  230. datacontract_cli-1.1.2/datacontract/editor_assets/shell-BpF-iNu8.js +0 -221
  231. datacontract_cli-1.1.2/datacontract/editor_assets/solidity-C00r2mbQ.js +0 -1367
  232. datacontract_cli-1.1.2/datacontract/editor_assets/sophia-DVW5ZKDB.js +0 -199
  233. datacontract_cli-1.1.2/datacontract/editor_assets/sparql-B0nmpxeX.js +0 -201
  234. datacontract_cli-1.1.2/datacontract/editor_assets/sql-CJwKPERn.js +0 -853
  235. datacontract_cli-1.1.2/datacontract/editor_assets/st-DPlKG5DT.js +0 -416
  236. datacontract_cli-1.1.2/datacontract/editor_assets/swift-YZBAbVHV.js +0 -309
  237. datacontract_cli-1.1.2/datacontract/editor_assets/systemverilog-CDQSaH63.js +0 -576
  238. datacontract_cli-1.1.2/datacontract/editor_assets/tcl-Dlu8sp6Q.js +0 -232
  239. datacontract_cli-1.1.2/datacontract/editor_assets/tsMode-yleMwhPq.js +0 -933
  240. datacontract_cli-1.1.2/datacontract/editor_assets/twig-C5TO7-kw.js +0 -392
  241. datacontract_cli-1.1.2/datacontract/editor_assets/typescript-CJBeebKU.js +0 -343
  242. datacontract_cli-1.1.2/datacontract/editor_assets/typespec-BsmjDEu7.js +0 -117
  243. datacontract_cli-1.1.2/datacontract/editor_assets/vb-ChHvIDrk.js +0 -372
  244. datacontract_cli-1.1.2/datacontract/editor_assets/wgsl-XEp1ju8c.js +0 -439
  245. datacontract_cli-1.1.2/datacontract/editor_assets/xml-vC-NMVX1.js +0 -95
  246. datacontract_cli-1.1.2/datacontract/editor_assets/yaml-Dlf2VF-T.js +0 -206
  247. datacontract_cli-1.1.2/datacontract/export/great_expectations_exporter.py +0 -357
  248. datacontract_cli-1.1.2/tests/test_export_great_expectations.py +0 -621
  249. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/LICENSE +0 -0
  250. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/MANIFEST.in +0 -0
  251. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/__init__.py +0 -0
  252. {datacontract_cli-1.1.2/datacontract/engines → datacontract_cli-1.2.0/datacontract/breaking}/__init__.py +0 -0
  253. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/catalog/catalog.py +0 -0
  254. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/changelog/__init__.py +0 -0
  255. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/changelog/changelog.py +0 -0
  256. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_api.py +0 -0
  257. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_catalog.py +0 -0
  258. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_changelog.py +0 -0
  259. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_edit.py +0 -0
  260. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_init.py +0 -0
  261. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_lint.py +0 -0
  262. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/command_publish.py +0 -0
  263. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/config/__init__.py +0 -0
  264. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/config/cli_context.py +0 -0
  265. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
  266. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/editor_assets/odcs.svg +0 -0
  267. {datacontract_cli-1.1.2/datacontract/engines/checks → datacontract_cli-1.2.0/datacontract/engines}/__init__.py +0 -0
  268. {datacontract_cli-1.1.2/datacontract/engines/ibis → datacontract_cli-1.2.0/datacontract/engines/checks}/__init__.py +0 -0
  269. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/checks/check_filter.py +0 -0
  270. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/checks/physical_type_match.py +0 -0
  271. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/checks/sql_guard.py +0 -0
  272. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
  273. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
  274. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
  275. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
  276. {datacontract_cli-1.1.2/datacontract/engines/ibis/connections → datacontract_cli-1.2.0/datacontract/engines/ibis}/__init__.py +0 -0
  277. {datacontract_cli-1.1.2/datacontract/export → datacontract_cli-1.2.0/datacontract/engines/ibis/connections}/__init__.py +0 -0
  278. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/aws_credentials.py +0 -0
  279. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/databricks_patch.py +0 -0
  280. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
  281. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/redshift_credentials.py +0 -0
  282. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/connections/redshift_patch.py +0 -0
  283. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/engines/ibis/native_type.py +0 -0
  284. {datacontract_cli-1.1.2/datacontract/output → datacontract_cli-1.2.0/datacontract/export}/__init__.py +0 -0
  285. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/custom_exporter.py +0 -0
  286. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/dbml_exporter.py +0 -0
  287. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/dbt_exporter.py +0 -0
  288. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/dqx_exporter.py +0 -0
  289. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/excel_exporter.py +0 -0
  290. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/exporter_factory.py +0 -0
  291. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/html_exporter.py +0 -0
  292. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/markdown_exporter.py +0 -0
  293. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/mermaid_exporter.py +0 -0
  294. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/odcs_v3_exporter.py +0 -0
  295. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/pandas_type_converter.py +0 -0
  296. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/sodacl_exporter.py +0 -0
  297. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/export/sql_exporter.py +0 -0
  298. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/athena_importer.py +0 -0
  299. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/bigquery_importer.py +0 -0
  300. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/csv_importer.py +0 -0
  301. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/dbml_importer.py +0 -0
  302. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/dbt_importer.py +0 -0
  303. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/importer.py +0 -0
  304. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/importer_factory.py +0 -0
  305. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/json_importer.py +0 -0
  306. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/mysql_importer.py +0 -0
  307. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/object_storage_importer.py +0 -0
  308. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/odcs_importer.py +0 -0
  309. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/oracle_importer.py +0 -0
  310. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/powerbi_importer.py +0 -0
  311. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/pydantic_importer.py +0 -0
  312. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/redshift_importer.py +0 -0
  313. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/sqlserver_importer.py +0 -0
  314. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/imports/trino_importer.py +0 -0
  315. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/integration/dbt_sync.py +0 -0
  316. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/integration/entropy_data.py +0 -0
  317. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/lint/files.py +0 -0
  318. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/lint/resources.py +0 -0
  319. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/lint/s3.py +0 -0
  320. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/lint/schema.py +0 -0
  321. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/lint/urls.py +0 -0
  322. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/model/changelog.py +0 -0
  323. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/model/exceptions.py +0 -0
  324. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/model/odcs.py +0 -0
  325. /datacontract_cli-1.1.2/datacontract/py.typed → /datacontract_cli-1.2.0/datacontract/output/__init__.py +0 -0
  326. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/output/ci_output.py +0 -0
  327. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/output/json_test_results.py +0 -0
  328. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/output/junit_test_results.py +0 -0
  329. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/output/output_format.py +0 -0
  330. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/output/text_changelog_results.py +0 -0
  331. /datacontract_cli-1.1.2/tests/test_description_linter.py → /datacontract_cli-1.2.0/datacontract/py.typed +0 -0
  332. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
  333. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
  334. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
  335. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
  336. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
  337. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
  338. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
  339. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
  340. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
  341. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/datacontract.html +0 -0
  342. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/excel/odcs-template.xlsx +0 -0
  343. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/index.html +0 -0
  344. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/macros/authoritative_definitions.html +0 -0
  345. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/macros/support.html +0 -0
  346. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/datacontract_information.html +0 -0
  347. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
  348. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/datacontract_terms.html +0 -0
  349. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/definition.html +0 -0
  350. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/example.html +0 -0
  351. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/model_field.html +0 -0
  352. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/quality.html +0 -0
  353. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials/server.html +0 -0
  354. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/diagram.html +0 -0
  355. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/dialog_yaml.html +0 -0
  356. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/footer.html +0 -0
  357. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/fundamentals.html +0 -0
  358. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/header.html +0 -0
  359. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/pricing.html +0 -0
  360. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/roles.html +0 -0
  361. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/servers.html +0 -0
  362. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/support.html +0 -0
  363. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/team.html +0 -0
  364. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/term_of_use.html +0 -0
  365. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/partials_odcs/title.html +0 -0
  366. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract/templates/style/output.css +0 -0
  367. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract_cli.egg-info/dependency_links.txt +0 -0
  368. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract_cli.egg-info/entry_points.txt +0 -0
  369. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/datacontract_cli.egg-info/top_level.txt +0 -0
  370. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/setup.cfg +0 -0
  371. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_api_openapi.py +0 -0
  372. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_catalog.py +0 -0
  373. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_changelog.py +0 -0
  374. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_changelog_engine.py +0 -0
  375. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_changelog_normalize.py +0 -0
  376. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_changelog_output_text.py +0 -0
  377. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_check_quality_provenance.py +0 -0
  378. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_ci_output.py +0 -0
  379. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_command_api.py +0 -0
  380. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_config.py +0 -0
  381. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_config_require.py +0 -0
  382. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_config_threading.py +0 -0
  383. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_athena.py +0 -0
  384. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_bigquery.py +0 -0
  385. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_databricks.py +0 -0
  386. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_impala.py +0 -0
  387. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_mysql.py +0 -0
  388. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_oracle.py +0 -0
  389. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_postgres.py +0 -0
  390. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_redshift.py +0 -0
  391. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_s3_credentials.py +0 -0
  392. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_snowflake.py +0 -0
  393. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_sqlserver.py +0 -0
  394. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_connect_trino.py +0 -0
  395. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_create_checks_physical_type.py +0 -0
  396. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_create_checks_primary_key.py +0 -0
  397. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_create_checks_sql_placeholders.py +0 -0
  398. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_data_contract.py +0 -0
  399. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_data_contract_checks.py +0 -0
  400. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_data_contract_specification.py +0 -0
  401. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_dbt_sync.py +0 -0
  402. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_dbt_test_mapping.py +0 -0
  403. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_docs_commands.py +0 -0
  404. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_docs_config_options.py +0 -0
  405. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_docs_ordering.py +0 -0
  406. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_download_datacontract_file.py +0 -0
  407. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_edit.py +0 -0
  408. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_avro_idl.py +0 -0
  409. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_bigquery.py +0 -0
  410. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_complex_data_contract.py +0 -0
  411. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_custom.py +0 -0
  412. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_custom_exporter.py +0 -0
  413. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_custom_model.py +0 -0
  414. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_data_caterer.py +0 -0
  415. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_dbml.py +0 -0
  416. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_dbt_models.py +0 -0
  417. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_dbt_sources.py +0 -0
  418. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_dbt_staging_sql.py +0 -0
  419. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_dcs.py +0 -0
  420. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_dqx.py +0 -0
  421. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_excel.py +0 -0
  422. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_go.py +0 -0
  423. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_html.py +0 -0
  424. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_iceberg.py +0 -0
  425. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_large_contract.py +0 -0
  426. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_markdown.py +0 -0
  427. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_mermaid.py +0 -0
  428. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_protobuf.py +0 -0
  429. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_pydantic.py +0 -0
  430. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_spark.py +0 -0
  431. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_sql.py +0 -0
  432. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_sql_clickhouse.py +0 -0
  433. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_sql_query.py +0 -0
  434. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_export_sqlalchemy.py +0 -0
  435. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_ibis_mssql_pattern.py +0 -0
  436. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_ibis_mssql_schema.py +0 -0
  437. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_ibis_oracle_schema.py +0 -0
  438. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_bigquery.py +0 -0
  439. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_dbml.py +0 -0
  440. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_dbt.py +0 -0
  441. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_glue.py +0 -0
  442. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_json.py +0 -0
  443. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_jsonschema.py +0 -0
  444. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_object_storage.py +0 -0
  445. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_odcs_v3.py +0 -0
  446. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_oracle.py +0 -0
  447. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_protobuf.py +0 -0
  448. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_pydantic_model.py +0 -0
  449. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_sqlserver.py +0 -0
  450. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_trino.py +0 -0
  451. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_import_unity_file.py +0 -0
  452. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_install_extras.py +0 -0
  453. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_integration_entropydata.py +0 -0
  454. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_lint_urls.py +0 -0
  455. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_native_type_schema_scope.py +0 -0
  456. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_oracle_patch.py +0 -0
  457. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_physical_type_match.py +0 -0
  458. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_publish_test_results.py +0 -0
  459. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_publish_test_results_payload.py +0 -0
  460. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_quality_sql_dialects.py +0 -0
  461. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_redshift_credentials.py +0 -0
  462. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_redshift_patch.py +0 -0
  463. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_roundtrip_jsonschema.py +0 -0
  464. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_run_check_deprecated_fields.py +0 -0
  465. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_run_check_engine.py +0 -0
  466. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_server_overrides.py +0 -0
  467. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_server_type_mssql.py +0 -0
  468. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_server_type_synonyms.py +0 -0
  469. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_sql_type_converter_physicaltype.py +0 -0
  470. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_api.py +0 -0
  471. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_athena_iceberg.py +0 -0
  472. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_azure_blob_file.py +0 -0
  473. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_azure_remote.py +0 -0
  474. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_bigquery.py +0 -0
  475. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_checks_filter.py +0 -0
  476. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_databricks.py +0 -0
  477. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_delta.py +0 -0
  478. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_diagnostics.py +0 -0
  479. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_duckdb.py +0 -0
  480. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_failed_samples.py +0 -0
  481. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_gcs_csv_remote.py +0 -0
  482. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_gcs_json_remote.py +0 -0
  483. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_kafka.py +0 -0
  484. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_kafka_remote.py +0 -0
  485. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_local_json.py +0 -0
  486. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_local_json_nd.py +0 -0
  487. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_metadata_only.py +0 -0
  488. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_mysql.py +0 -0
  489. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_oracle.py +0 -0
  490. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_oracle_xe.py +0 -0
  491. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_output_json.py +0 -0
  492. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_output_junit.py +0 -0
  493. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_postgres.py +0 -0
  494. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_quality.py +0 -0
  495. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_quality_id_and_tag_filter.py +0 -0
  496. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_quality_local_fallback.py +0 -0
  497. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_quality_percent_severity.py +0 -0
  498. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_redshift.py +0 -0
  499. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_row_filter.py +0 -0
  500. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_s3_csv.py +0 -0
  501. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_s3_delta.py +0 -0
  502. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_s3_json.py +0 -0
  503. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_s3_json_complex.py +0 -0
  504. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_s3_json_multiple_models.py +0 -0
  505. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_s3_json_remote.py +0 -0
  506. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_schema_evolution.py +0 -0
  507. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_server_not_found.py +0 -0
  508. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_snowflake.py +0 -0
  509. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_soda_connection_error.py +0 -0
  510. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_sqlserver.py +0 -0
  511. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_test_trino.py +0 -0
  512. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/tests/test_type_normalize.py +0 -0
  513. {datacontract_cli-1.1.2 → datacontract_cli-1.2.0}/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.2.0
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
@@ -40,13 +40,13 @@ Requires-Dist: jsonschema<5.0.0,>=4.23.0
40
40
  Requires-Dist: pytz>=2024.1
41
41
  Requires-Dist: python-multipart<1.0.0,>=0.0.20
42
42
  Requires-Dist: rich<16.0,>=13.7
43
- Requires-Dist: sqlglot<31.0.0,>=26.6.0
43
+ Requires-Dist: sqlglot<30.18,>=26.6.0
44
44
  Requires-Dist: python-dotenv<2.0.0,>=1.0.0
45
45
  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.3.0,>=3.2.0
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"
@@ -67,12 +67,13 @@ Requires-Dist: rich>=12.4.4; extra == "dataframe"
67
67
  Provides-Extra: databricks
68
68
  Requires-Dist: ibis-framework[databricks]<13.0.0,>=10.0.0; extra == "databricks"
69
69
  Requires-Dist: databricks-sql-connector<4.5.0,>=3.7.0; extra == "databricks"
70
- Requires-Dist: databricks-sdk<0.134.0; extra == "databricks"
70
+ Requires-Dist: databricks-sdk<0.136.0; extra == "databricks"
71
71
  Requires-Dist: packaging<27.0,>=21.3; extra == "databricks"
72
72
  Provides-Extra: databricks-runtime
73
73
  Requires-Dist: datacontract-cli[databricks]; extra == "databricks-runtime"
74
74
  Provides-Extra: iceberg
75
- Requires-Dist: pyiceberg==0.11.1; extra == "iceberg"
75
+ Requires-Dist: pyiceberg[pyarrow,rest-sigv4]==0.12.0; extra == "iceberg"
76
+ Requires-Dist: datacontract-cli[duckdb]; extra == "iceberg"
76
77
  Provides-Extra: kafka
77
78
  Requires-Dist: datacontract-cli[duckdb,parquet]; extra == "kafka"
78
79
  Requires-Dist: confluent-kafka<3.0.0,>=2.6.0; extra == "kafka"
@@ -138,17 +139,17 @@ Requires-Dist: datacontract-cli[all]; extra == "dev"
138
139
  Requires-Dist: httpx==0.28.1; extra == "dev"
139
140
  Requires-Dist: kafka-python; extra == "dev"
140
141
  Requires-Dist: minio==7.2.20; extra == "dev"
141
- Requires-Dist: moto==5.2.2; extra == "dev"
142
+ Requires-Dist: moto==5.2.3; extra == "dev"
142
143
  Requires-Dist: openapi-spec-validator<0.10,>=0.7; extra == "dev"
143
144
  Requires-Dist: pandas>=2.1.0; extra == "dev"
144
145
  Requires-Dist: pre-commit<4.7.0,>=3.7.1; extra == "dev"
145
146
  Requires-Dist: pytest; extra == "dev"
146
147
  Requires-Dist: pytest-cov; extra == "dev"
147
148
  Requires-Dist: pytest-xdist; extra == "dev"
148
- Requires-Dist: pymssql==2.3.13; extra == "dev"
149
+ Requires-Dist: pymssql==2.4.0; extra == "dev"
149
150
  Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == "dev"
150
151
  Requires-Dist: mysql-connector-python<26.8.0,>=8.0.30; extra == "dev"
151
- Requires-Dist: ruff==0.16.4; extra == "dev"
152
+ Requires-Dist: ruff==0.16.6; extra == "dev"
152
153
  Requires-Dist: testcontainers[kafka,minio,mssql,mysql,postgres]==4.15.0; extra == "dev"
153
154
  Requires-Dist: trino==0.339.0; extra == "dev"
154
155
  Dynamic: license-file
@@ -296,6 +297,9 @@ $ datacontract lint odcs.yaml
296
297
  # show a changelog between two data contracts
297
298
  $ datacontract changelog v1.odcs.yaml v2.odcs.yaml
298
299
 
300
+ # fail when a contract change is backward-incompatible
301
+ $ datacontract breaking v1.odcs.yaml v2.odcs.yaml
302
+
299
303
  # execute schema and quality checks (define credentials as environment variables)
300
304
  $ datacontract test odcs.yaml
301
305
 
@@ -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,11 +15,12 @@ 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
21
22
 
22
- DATA_CONTRACT_EXAMPLE_PAYLOAD = """apiVersion: v3.1.0
23
+ DATA_CONTRACT_EXAMPLE_PAYLOAD = """apiVersion: v3.2.0
23
24
  kind: DataContract
24
25
  id: orders
25
26
  name: Orders
@@ -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,101 @@
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 = {
27
+ entry.path
28
+ for entry in entries
29
+ if entry.change_type == ChangelogType.added
30
+ and (
31
+ entry.path.startswith("schema.")
32
+ and (len(entry.path.split(".")) == 2 or entry.path.split(".")[-2] == "properties")
33
+ )
34
+ }
35
+ removed_enums = {
36
+ entry.path
37
+ for entry in entries
38
+ if entry.change_type == ChangelogType.removed and entry.path.endswith(".enum")
39
+ }
40
+ # Stable IDs may change or swap without changing the set of allowed
41
+ # values. Match removed/updated values against additions in the same enum.
42
+ added_values = defaultdict(set)
43
+ for entry in entries:
44
+ if entry.rule_id == "enum-constraint-changed" and entry.path.endswith(".value"):
45
+ if entry.change_type in (ChangelogType.added, ChangelogType.updated):
46
+ added_values[entry.path.rsplit(".enum.", 1)[0]].add(entry.new_value)
47
+ for entry in entries:
48
+ segments = entry.path.split(".")
49
+ if any(".".join(segments[:i]) in added for i in range(1, len(segments))):
50
+ entry.level = BreakingChangeLevel.INFO
51
+ if entry.rule_id == "enum-constraint-changed":
52
+ if any(entry.path.startswith(path + ".") for path in removed_enums):
53
+ entry.level = BreakingChangeLevel.INFO
54
+ elif entry.path.endswith(".value") and entry.old_value in added_values.get(
55
+ entry.path.rsplit(".enum.", 1)[0], set()
56
+ ):
57
+ entry.level = BreakingChangeLevel.INFO
58
+ entries_by_prefix = defaultdict(list)
59
+ for entry in entries:
60
+ prefix = ""
61
+ for segment in entry.path.split("."):
62
+ prefix = f"{prefix}.{segment}" if prefix else segment
63
+ entries_by_prefix[prefix].append(entry)
64
+ summary = [self._summarize(entry, entries_by_prefix.get(entry.path, [])) for entry in changelog.summary]
65
+ return BreakingChangeResult(v1=changelog.v1, v2=changelog.v2, summary=summary, entries=entries)
66
+
67
+ def _classify(self, entry: ChangelogEntry) -> BreakingChangeEntry:
68
+ for rule in self._rules:
69
+ evaluation = rule.evaluate(entry)
70
+ if evaluation is not None:
71
+ return BreakingChangeEntry(
72
+ path=entry.path,
73
+ change_type=entry.type,
74
+ level=evaluation.level,
75
+ message=evaluation.message,
76
+ rule_id=evaluation.rule_id,
77
+ old_value=entry.old_value,
78
+ new_value=entry.new_value,
79
+ )
80
+ raise ValueError(f"No breaking-change rule classified {entry.path}")
81
+
82
+ @staticmethod
83
+ def _summarize(summary_entry: ChangelogEntry, entries: list[BreakingChangeEntry]) -> BreakingChangeEntry:
84
+ if not entries:
85
+ return BreakingChangeEntry(
86
+ path=summary_entry.path,
87
+ change_type=summary_entry.type,
88
+ level=BreakingChangeLevel.INFO,
89
+ message=f"Changed contract at {summary_entry.path}",
90
+ rule_id="summary-fallback",
91
+ )
92
+ highest = max(entries, key=lambda entry: _LEVEL_ORDER[entry.level])
93
+ return BreakingChangeEntry(
94
+ path=summary_entry.path,
95
+ change_type=summary_entry.type,
96
+ level=highest.level,
97
+ message=f"{highest.level.value.capitalize()} impact at {summary_entry.path}",
98
+ rule_id=f"summary:{highest.rule_id}",
99
+ old_value=highest.old_value,
100
+ new_value=highest.new_value,
101
+ )
@@ -0,0 +1,235 @@
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
+ class EnumConstraintRule(BreakingChangeRule):
144
+ rule_id = "enum-constraint-changed"
145
+
146
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
147
+ if not entry.path.startswith("schema.") or ".properties." not in entry.path:
148
+ return None
149
+ if entry.path.endswith(".enum"):
150
+ level = BreakingChangeLevel.ERROR if entry.type == ChangelogType.added else BreakingChangeLevel.INFO
151
+ elif (
152
+ ".enum." in entry.path
153
+ and entry.path.endswith(".value")
154
+ and ".customProperties." not in entry.path.rsplit(".enum.", 1)[1]
155
+ and ".authoritativeDefinitions." not in entry.path.rsplit(".enum.", 1)[1]
156
+ ):
157
+ level = BreakingChangeLevel.INFO if entry.type == ChangelogType.added else BreakingChangeLevel.ERROR
158
+ else:
159
+ return None
160
+ return RuleEvaluation(self.rule_id, level, _change_message("allowed values", entry))
161
+
162
+
163
+ class VectorShapeRule(BreakingChangeRule):
164
+ rule_id = "vector-shape-changed"
165
+
166
+ def evaluate(self, entry: ChangelogEntry) -> RuleEvaluation | None:
167
+ if not entry.path.startswith("schema.") or not entry.path.endswith(
168
+ (".logicalTypeOptions.dimensions", ".logicalTypeOptions.elementType")
169
+ ):
170
+ return None
171
+ if entry.path.endswith(".elementType"):
172
+ old = entry.old_value or "float32"
173
+ new = entry.new_value or "float32"
174
+ level = BreakingChangeLevel.INFO if old == new else BreakingChangeLevel.ERROR
175
+ else:
176
+ level = BreakingChangeLevel.WARNING if entry.type == ChangelogType.removed else BreakingChangeLevel.ERROR
177
+ return RuleEvaluation(self.rule_id, level, _change_message("vector shape", entry))
178
+
179
+
180
+ def _is_schema_property_path(segments: list[str]) -> bool:
181
+ return len(segments) >= 3 and segments[0] == "schema" and segments[-2] == "properties"
182
+
183
+
184
+ def _parse_bool(value: str | None) -> bool | None:
185
+ if value is None:
186
+ return None
187
+ normalized = value.strip().lower()
188
+ if normalized in {"true", "1"}:
189
+ return True
190
+ if normalized in {"false", "0"}:
191
+ return False
192
+ return None
193
+
194
+
195
+ def _parse_number(value: str | None) -> float | None:
196
+ if value is None:
197
+ return None
198
+ normalized = value.strip()
199
+ try:
200
+ return float(normalized)
201
+ except ValueError:
202
+ try:
203
+ return float(date.fromisoformat(normalized).toordinal())
204
+ except ValueError:
205
+ return None
206
+
207
+
208
+ def _is_tightening(path: str, old: float, new: float) -> bool:
209
+ if path.endswith((".minLength", ".minimum", ".exclusiveMinimum")):
210
+ return new > old
211
+ if path.endswith((".maxLength", ".maximum", ".exclusiveMaximum")):
212
+ return new < old
213
+ return True
214
+
215
+
216
+ def _change_message(subject: str, entry: ChangelogEntry) -> str:
217
+ if entry.type == ChangelogType.added:
218
+ return f"Added {subject} at {entry.path}"
219
+ if entry.type == ChangelogType.removed:
220
+ return f"Removed {subject} at {entry.path}"
221
+ return f"Changed {subject} at {entry.path} from {entry.old_value!r} to {entry.new_value!r}"
222
+
223
+
224
+ DEFAULT_RULES: tuple[BreakingChangeRule, ...] = (
225
+ RequiredChangedRule(),
226
+ SchemaRemovedRule(),
227
+ FieldRemovedRule(),
228
+ TypeChangedRule(),
229
+ UniqueConstraintRule(),
230
+ KeyConstraintRule(),
231
+ ValidationConstraintRule(),
232
+ EnumConstraintRule(),
233
+ VectorShapeRule(),
234
+ MetadataFallbackRule(),
235
+ )
@@ -44,6 +44,13 @@ Current hardcoded natural keys:
44
44
  schema[] SchemaObject -> .name (required: [name])
45
45
  schema[].properties[] SchemaProperty -> .name (required: [name], recursive)
46
46
  slaProperties[] SLAProperty -> .property
47
+ slaProperties[].customProperties[] CustomProperty -> .property
48
+ slaProperties[].authoritativeDefinitions[] AuthoritativeDefinition -> .url
49
+ schema[].properties[].enum[] EnumValue -> .value (or .id)
50
+ schema[]/properties[].synonyms[] Synonym -> .synonym (or .id)
51
+ schema[]/properties[].relationships[] Relationship -> .id, else from:to
52
+ context.verifiedStatements[] VerifiedStatement -> .question (or .id)
53
+ context.constraints[] Constraint -> .constraint (or .id)
47
54
  servers[] Server -> .server
48
55
  servers[].roles[] Role -> .role
49
56
  servers[].customProperties[] CustomProperty -> .property
@@ -82,15 +89,41 @@ def _normalize_auth_defs(items: list[dict]) -> dict:
82
89
  return result
83
90
 
84
91
 
92
+ def _normalize_keyed(items: list[dict], *keys: str) -> dict:
93
+ """Key a list of dicts by the first of ``keys`` an item carries, keeping the key in the value.
94
+
95
+ Falls back to the list index if none of the key fields is present.
96
+ """
97
+ result = {}
98
+ for i, item in enumerate(items):
99
+ key = next((str(item[k]) for k in keys if item.get(k) is not None), None) or f"__pos_{i}__"
100
+ result[key] = item
101
+ return result
102
+
103
+
104
+ def _normalize_context(context) -> object:
105
+ """Key the lists of a context block; a plain-string context is returned unchanged."""
106
+ if not isinstance(context, dict):
107
+ return context
108
+ entry = dict(context)
109
+ if isinstance(entry.get("verifiedStatements"), list):
110
+ entry["verifiedStatements"] = _normalize_keyed(entry["verifiedStatements"], "id", "question")
111
+ if isinstance(entry.get("constraints"), list):
112
+ entry["constraints"] = _normalize_keyed(entry["constraints"], "id", "constraint")
113
+ return entry
114
+
115
+
85
116
  def _normalize_relationships(items: list[dict], schema_level: bool = True) -> dict:
86
- """Key relationships by a stable composite key.
117
+ """Key relationships by their id (ODCS v3.2.0), else by a stable composite key.
87
118
 
88
119
  Schema-level: from:to composite. Property-level: to only.
89
120
  Falls back to positional index if key fields are absent.
90
121
  """
91
122
  result = {}
92
123
  for i, item in enumerate(items):
93
- if schema_level:
124
+ if item.get("id"):
125
+ key = str(item["id"])
126
+ elif schema_level:
94
127
  from_val = str(item.get("from", ""))
95
128
  to_val = str(item.get("to", ""))
96
129
  key = f"{from_val}:{to_val}" if (from_val or to_val) else f"__pos_{i}__"
@@ -125,6 +158,12 @@ def _normalize_schema_fields(entry: dict, *, schema_level: bool) -> dict:
125
158
  entry["authoritativeDefinitions"] = _normalize_auth_defs(entry["authoritativeDefinitions"])
126
159
  if "relationships" in entry and isinstance(entry["relationships"], list):
127
160
  entry["relationships"] = _normalize_relationships(entry["relationships"], schema_level=schema_level)
161
+ if "synonyms" in entry and isinstance(entry["synonyms"], list):
162
+ entry["synonyms"] = _normalize_keyed(entry["synonyms"], "id", "synonym")
163
+ if "enum" in entry and isinstance(entry["enum"], list):
164
+ entry["enum"] = _normalize_keyed(entry["enum"], "id", "value")
165
+ if "context" in entry:
166
+ entry["context"] = _normalize_context(entry["context"])
128
167
  return entry
129
168
 
130
169
 
@@ -134,13 +173,30 @@ def _normalize_properties(properties: list[dict]) -> dict:
134
173
  for prop in properties:
135
174
  key = prop.get("name", prop.get("id", str(prop)))
136
175
  entry = {k: v for k, v in prop.items() if k != "name"}
137
- if "properties" in entry and isinstance(entry["properties"], list):
138
- entry["properties"] = _normalize_properties(entry["properties"])
176
+ entry = _normalize_property_children(entry)
139
177
  entry = _normalize_schema_fields(entry, schema_level=False)
140
178
  result[key] = entry
141
179
  return result
142
180
 
143
181
 
182
+ def _normalize_property_children(entry: dict) -> dict:
183
+ """Recurse into the nested property definitions of a property: properties, items, map key and value."""
184
+ if "properties" in entry and isinstance(entry["properties"], list):
185
+ entry["properties"] = _normalize_properties(entry["properties"])
186
+ if isinstance(entry.get("items"), dict):
187
+ entry["items"] = _normalize_schema_fields(
188
+ _normalize_property_children(dict(entry["items"])), schema_level=False
189
+ )
190
+ if isinstance(entry.get("map"), dict):
191
+ entry["map"] = {
192
+ side: _normalize_schema_fields(_normalize_property_children(dict(definition)), schema_level=False)
193
+ if isinstance(definition, dict)
194
+ else definition
195
+ for side, definition in entry["map"].items()
196
+ }
197
+ return entry
198
+
199
+
144
200
  def normalize(contract: dict) -> dict:
145
201
  """Convert named lists to dicts keyed by their natural key field.
146
202
 
@@ -161,7 +217,16 @@ def normalize(contract: dict) -> dict:
161
217
  out["schema"] = normalized_schema
162
218
 
163
219
  if "slaProperties" in out and isinstance(out["slaProperties"], list):
164
- out["slaProperties"] = _normalize_by(out["slaProperties"], "property")
220
+ sla_properties = _normalize_by(out["slaProperties"], "property")
221
+ for entry in sla_properties.values():
222
+ if isinstance(entry.get("customProperties"), list):
223
+ entry["customProperties"] = _normalize_by(entry["customProperties"], "property")
224
+ if isinstance(entry.get("authoritativeDefinitions"), list):
225
+ entry["authoritativeDefinitions"] = _normalize_auth_defs(entry["authoritativeDefinitions"])
226
+ out["slaProperties"] = sla_properties
227
+
228
+ if "context" in out:
229
+ out["context"] = _normalize_context(out["context"])
165
230
 
166
231
  if "servers" in out and isinstance(out["servers"], list):
167
232
  normalized_servers = {}