datacontract-cli 1.2.1__tar.gz → 1.2.2__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 (455) hide show
  1. {datacontract_cli-1.2.1/datacontract_cli.egg-info → datacontract_cli-1.2.2}/PKG-INFO +1 -1
  2. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/api.py +12 -2
  3. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_api.py +25 -0
  4. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_import.py +49 -0
  5. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_init.py +1 -1
  6. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/config/settings.py +1 -1
  7. datacontract_cli-1.2.2/datacontract/config/variables.py +256 -0
  8. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/data_contract.py +53 -0
  9. datacontract_cli-1.2.2/datacontract/editor_assets/VERSION +1 -0
  10. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/datacontract-editor.css +1 -1
  11. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/datacontract-editor.es.js +27133 -25620
  12. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/index.html +9 -5
  13. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/check_spec.py +2 -2
  14. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/create_checks.py +164 -92
  15. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/sql_guard.py +42 -17
  16. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/data_contract_test.py +29 -15
  17. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/hana/hana_quality_check.py +47 -12
  18. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/connect.py +17 -7
  19. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/ibis_check_execute.py +6 -2
  20. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/sodacl_exporter.py +24 -1
  21. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/sql_type_converter.py +6 -0
  22. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/avro_importer.py +1 -1
  23. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/bigquery_importer.py +1 -1
  24. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/dbml_importer.py +1 -1
  25. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/dcs_importer.py +3 -1
  26. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/iceberg_importer.py +1 -1
  27. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/importer.py +1 -0
  28. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/importer_factory.py +5 -0
  29. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/jsonschema_importer.py +61 -14
  30. datacontract_cli-1.2.2/datacontract/imports/odata_importer.py +506 -0
  31. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/protobuf_importer.py +2 -2
  32. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/spark_importer.py +43 -38
  33. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/sql_importer.py +1 -1
  34. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/unity_importer.py +1 -1
  35. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/init/init_template.py +2 -2
  36. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/lint/files.py +1 -1
  37. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/lint/resolve.py +48 -28
  38. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/lint/schema.py +2 -2
  39. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/run.py +2 -0
  40. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/vector_type.py +5 -1
  41. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/test_results_writer.py +24 -20
  42. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2/datacontract_cli.egg-info}/PKG-INFO +1 -1
  43. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract_cli.egg-info/SOURCES.txt +9 -0
  44. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/pyproject.toml +1 -1
  45. datacontract_cli-1.2.2/tests/test_command_api_options.py +49 -0
  46. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_config.py +1 -0
  47. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_create_checks_nested.py +20 -3
  48. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_create_checks_physical_type.py +1 -1
  49. datacontract_cli-1.2.2/tests/test_create_checks_sql_placeholders.py +160 -0
  50. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_sodacl.py +37 -0
  51. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_hana_quality_check.py +47 -5
  52. datacontract_cli-1.2.2/tests/test_import_jsonschema.py +151 -0
  53. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_object_storage.py +1 -1
  54. datacontract_cli-1.2.2/tests/test_import_odata.py +873 -0
  55. datacontract_cli-1.2.2/tests/test_lint_files.py +10 -0
  56. datacontract_cli-1.2.2/tests/test_lint_schema.py +20 -0
  57. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_quality_sql_dialects.py +3 -3
  58. datacontract_cli-1.2.2/tests/test_quality_unrunnable_rules.py +240 -0
  59. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_checks_filter.py +2 -1
  60. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_dry_run.py +31 -0
  61. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_iceberg_rest.py +1 -1
  62. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_kafka.py +17 -0
  63. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_metadata_only.py +11 -11
  64. datacontract_cli-1.2.2/tests/test_test_nested_checks.py +154 -0
  65. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_parquet.py +22 -32
  66. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_quality_percent_severity.py +12 -8
  67. datacontract_cli-1.2.2/tests/test_test_results_writer.py +44 -0
  68. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_s3_csv.py +1 -1
  69. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_s3_delta.py +1 -1
  70. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_s3_json.py +1 -1
  71. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_s3_json_complex.py +1 -1
  72. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_s3_json_multiple_models.py +1 -1
  73. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_schema_evolution.py +6 -4
  74. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_variables.py +60 -0
  75. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_untrusted_contract.py +64 -12
  76. datacontract_cli-1.2.2/tests/test_untrusted_contract_variables.py +209 -0
  77. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_vector_type.py +3 -0
  78. datacontract_cli-1.2.1/datacontract/config/variables.py +0 -133
  79. datacontract_cli-1.2.1/datacontract/editor_assets/VERSION +0 -1
  80. datacontract_cli-1.2.1/tests/test_create_checks_sql_placeholders.py +0 -44
  81. datacontract_cli-1.2.1/tests/test_import_jsonschema.py +0 -78
  82. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/LICENSE +0 -0
  83. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/MANIFEST.in +0 -0
  84. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/README.md +0 -0
  85. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/__init__.py +0 -0
  86. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/breaking/__init__.py +0 -0
  87. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/breaking/detector.py +0 -0
  88. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/breaking/rules.py +0 -0
  89. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/catalog/catalog.py +0 -0
  90. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/changelog/__init__.py +0 -0
  91. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/changelog/changelog.py +0 -0
  92. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/changelog/normalize.py +0 -0
  93. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/cli.py +0 -0
  94. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_breaking.py +0 -0
  95. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_catalog.py +0 -0
  96. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_changelog.py +0 -0
  97. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_ci.py +0 -0
  98. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_dbt.py +0 -0
  99. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_edit.py +0 -0
  100. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_export.py +0 -0
  101. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_lint.py +0 -0
  102. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_publish.py +0 -0
  103. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/command_test.py +0 -0
  104. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/config/__init__.py +0 -0
  105. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/config/cli_context.py +0 -0
  106. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/assets/editor.worker-4.7.0.js +0 -0
  107. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/assets/yaml.worker-4.7.0.js +0 -0
  108. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/logo_fuchsia_v2.svg +0 -0
  109. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/monaco-4.7.0.js +0 -0
  110. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/odcs.svg +0 -0
  111. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/robots.txt +0 -0
  112. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/rolldown-runtime-DY7j01NX.js +0 -0
  113. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/editor_assets/sitemap.xml +0 -0
  114. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/__init__.py +0 -0
  115. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/__init__.py +0 -0
  116. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/check_filter.py +0 -0
  117. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/dimensions.py +0 -0
  118. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/physical_type_match.py +0 -0
  119. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/severity.py +0 -0
  120. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/checks/type_normalize.py +0 -0
  121. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/datacontract/check_azure_blob_file.py +0 -0
  122. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
  123. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
  124. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
  125. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
  126. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/hana/__init__.py +0 -0
  127. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/hana/check_hana_execute.py +0 -0
  128. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/hana/hana_check_selection.py +0 -0
  129. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/hana/hana_connection.py +0 -0
  130. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/hana/hana_schema_check.py +0 -0
  131. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/hana/hana_type_mapping.py +0 -0
  132. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/__init__.py +0 -0
  133. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/__init__.py +0 -0
  134. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/aws_credentials.py +0 -0
  135. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/databricks_patch.py +0 -0
  136. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/duckdb_connection.py +0 -0
  137. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/exasol_patch.py +0 -0
  138. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/iceberg.py +0 -0
  139. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/kafka.py +0 -0
  140. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/oracle_patch.py +0 -0
  141. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/redshift_credentials.py +0 -0
  142. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/connections/redshift_patch.py +0 -0
  143. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/dtype_category.py +0 -0
  144. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/native_type.py +0 -0
  145. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/engines/ibis/snowflake_structured_types.py +0 -0
  146. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/__init__.py +0 -0
  147. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/avro_exporter.py +0 -0
  148. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/avro_idl_exporter.py +0 -0
  149. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/bigquery_exporter.py +0 -0
  150. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/custom_exporter.py +0 -0
  151. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/data_caterer_exporter.py +0 -0
  152. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/dbml_exporter.py +0 -0
  153. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/dbt_exporter.py +0 -0
  154. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/dcs_exporter.py +0 -0
  155. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/dqx_exporter.py +0 -0
  156. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/duckdb_type_converter.py +0 -0
  157. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/excel_exporter.py +0 -0
  158. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/exporter.py +0 -0
  159. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/exporter_factory.py +0 -0
  160. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/go_exporter.py +0 -0
  161. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/great_expectations_exporter.py +0 -0
  162. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/html_exporter.py +0 -0
  163. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/iceberg_exporter.py +0 -0
  164. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/jsonschema_exporter.py +0 -0
  165. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/markdown_exporter.py +0 -0
  166. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/mermaid_exporter.py +0 -0
  167. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/odcs_v3_exporter.py +0 -0
  168. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/pandas_type_converter.py +0 -0
  169. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/protobuf_exporter.py +0 -0
  170. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/pydantic_exporter.py +0 -0
  171. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/rdf_exporter.py +0 -0
  172. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/sodacl_check_builder.py +0 -0
  173. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/spark_exporter.py +0 -0
  174. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/sql_exporter.py +0 -0
  175. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/export/sqlalchemy_exporter.py +0 -0
  176. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/athena_importer.py +0 -0
  177. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/csv_importer.py +0 -0
  178. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/dbt_importer.py +0 -0
  179. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/excel_importer.py +0 -0
  180. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/glue_importer.py +0 -0
  181. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/json_importer.py +0 -0
  182. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/mysql_importer.py +0 -0
  183. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/object_storage_importer.py +0 -0
  184. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/odcs_helper.py +0 -0
  185. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/odcs_importer.py +0 -0
  186. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/oracle_importer.py +0 -0
  187. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/parquet_importer.py +0 -0
  188. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/postgres_importer.py +0 -0
  189. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/powerbi_importer.py +0 -0
  190. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/pydantic_importer.py +0 -0
  191. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/redshift_importer.py +0 -0
  192. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/snowflake_importer.py +0 -0
  193. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/spark_type_json.py +0 -0
  194. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/sqlserver_importer.py +0 -0
  195. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/imports/trino_importer.py +0 -0
  196. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/integration/dbt_sync.py +0 -0
  197. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/integration/dbt_test_mapping.py +0 -0
  198. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/integration/entropy_data.py +0 -0
  199. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/lint/constraints.py +0 -0
  200. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/lint/resources.py +0 -0
  201. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/lint/s3.py +0 -0
  202. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/lint/urls.py +0 -0
  203. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/breaking.py +0 -0
  204. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/changelog.py +0 -0
  205. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/enum_values.py +0 -0
  206. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/exceptions.py +0 -0
  207. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/map_type.py +0 -0
  208. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/natural_keys.py +0 -0
  209. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/odcs.py +0 -0
  210. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/server.py +0 -0
  211. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/model/workbook.py +0 -0
  212. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/__init__.py +0 -0
  213. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/ci_output.py +0 -0
  214. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/json_test_results.py +0 -0
  215. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/junit_test_results.py +0 -0
  216. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/output_format.py +0 -0
  217. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/text_breaking_results.py +0 -0
  218. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/output/text_changelog_results.py +0 -0
  219. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/py.typed +0 -0
  220. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
  221. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
  222. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/datacontract-1.2.0.init.yaml +0 -0
  223. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/datacontract-1.2.0.schema.json +0 -0
  224. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/datacontract-1.2.1.init.yaml +0 -0
  225. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/datacontract-1.2.1.schema.json +0 -0
  226. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/odcs-3.0.2.schema.json +0 -0
  227. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/odcs-3.1.0.schema.json +0 -0
  228. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/odcs-3.2.0.init.yaml +0 -0
  229. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/schemas/odcs-3.2.0.schema.json +0 -0
  230. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/datacontract.html +0 -0
  231. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/datacontract_odcs.html +0 -0
  232. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/excel/odcs-template-v3.0.xlsx +0 -0
  233. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/excel/odcs-template-v3.1.xlsx +0 -0
  234. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/excel/odcs-template-v3.2.xlsx +0 -0
  235. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/index.html +0 -0
  236. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/macros/authoritative_definitions.html +0 -0
  237. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/macros/context.html +0 -0
  238. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/macros/schema.html +0 -0
  239. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/macros/server.html +0 -0
  240. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/macros/support.html +0 -0
  241. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/datacontract_information.html +0 -0
  242. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
  243. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/datacontract_terms.html +0 -0
  244. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/definition.html +0 -0
  245. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/example.html +0 -0
  246. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/model_field.html +0 -0
  247. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/quality.html +0 -0
  248. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials/server.html +0 -0
  249. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/context.html +0 -0
  250. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/custom_properties.html +0 -0
  251. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/diagram.html +0 -0
  252. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/dialog_yaml.html +0 -0
  253. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/footer.html +0 -0
  254. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/fundamentals.html +0 -0
  255. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/header.html +0 -0
  256. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/pricing.html +0 -0
  257. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/roles.html +0 -0
  258. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/schema.html +0 -0
  259. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/servers.html +0 -0
  260. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/sla.html +0 -0
  261. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/support.html +0 -0
  262. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/team.html +0 -0
  263. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/term_of_use.html +0 -0
  264. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/partials_odcs/title.html +0 -0
  265. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract/templates/style/output.css +0 -0
  266. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract_cli.egg-info/dependency_links.txt +0 -0
  267. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract_cli.egg-info/entry_points.txt +0 -0
  268. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract_cli.egg-info/requires.txt +0 -0
  269. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/datacontract_cli.egg-info/top_level.txt +0 -0
  270. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/setup.cfg +0 -0
  271. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_api.py +0 -0
  272. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_api_openapi.py +0 -0
  273. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_breaking.py +0 -0
  274. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_breaking_odcs_3_2.py +0 -0
  275. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_catalog.py +0 -0
  276. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_changelog.py +0 -0
  277. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_changelog_engine.py +0 -0
  278. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_changelog_normalize.py +0 -0
  279. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_changelog_output_text.py +0 -0
  280. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_check_quality_provenance.py +0 -0
  281. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_ci_output.py +0 -0
  282. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_cli.py +0 -0
  283. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_command_api.py +0 -0
  284. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_config_file.py +0 -0
  285. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_config_require.py +0 -0
  286. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_config_threading.py +0 -0
  287. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_athena.py +0 -0
  288. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_bigquery.py +0 -0
  289. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_databricks.py +0 -0
  290. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_exasol.py +0 -0
  291. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_impala.py +0 -0
  292. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_mysql.py +0 -0
  293. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_oracle.py +0 -0
  294. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_postgres.py +0 -0
  295. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_redshift.py +0 -0
  296. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_s3_credentials.py +0 -0
  297. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_snowflake.py +0 -0
  298. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_sqlserver.py +0 -0
  299. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_connect_trino.py +0 -0
  300. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_create_checks_array_items.py +0 -0
  301. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_create_checks_nested_type.py +0 -0
  302. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_create_checks_primary_key.py +0 -0
  303. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_create_checks_retention_period.py +0 -0
  304. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_create_checks_servicelevel.py +0 -0
  305. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_data_contract.py +0 -0
  306. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_data_contract_checks.py +0 -0
  307. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_data_contract_specification.py +0 -0
  308. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_dbt_sync.py +0 -0
  309. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_dbt_test_mapping.py +0 -0
  310. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_description_linter.py +0 -0
  311. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_docs_commands.py +0 -0
  312. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_docs_config_options.py +0 -0
  313. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_docs_ordering.py +0 -0
  314. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_download_datacontract_file.py +0 -0
  315. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_dtype_category.py +0 -0
  316. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_duckdb_json.py +0 -0
  317. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_edit.py +0 -0
  318. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_enum_values.py +0 -0
  319. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_avro.py +0 -0
  320. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_avro_idl.py +0 -0
  321. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_bigquery.py +0 -0
  322. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_complex_data_contract.py +0 -0
  323. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_custom.py +0 -0
  324. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_custom_exporter.py +0 -0
  325. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_custom_model.py +0 -0
  326. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_data_caterer.py +0 -0
  327. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_dbml.py +0 -0
  328. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_dbt_models.py +0 -0
  329. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_dbt_sources.py +0 -0
  330. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_dbt_staging_sql.py +0 -0
  331. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_dcs.py +0 -0
  332. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_dqx.py +0 -0
  333. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_excel.py +0 -0
  334. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_go.py +0 -0
  335. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_great_expectations.py +0 -0
  336. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_html.py +0 -0
  337. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_iceberg.py +0 -0
  338. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_jsonschema.py +0 -0
  339. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_large_contract.py +0 -0
  340. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_markdown.py +0 -0
  341. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_mermaid.py +0 -0
  342. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_odcs_v3.py +0 -0
  343. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_protobuf.py +0 -0
  344. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_pydantic.py +0 -0
  345. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_rdf.py +0 -0
  346. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_spark.py +0 -0
  347. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_sql.py +0 -0
  348. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_sql_clickhouse.py +0 -0
  349. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_sql_query.py +0 -0
  350. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_export_sqlalchemy.py +0 -0
  351. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_hana_connection.py +0 -0
  352. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_hana_schema_check.py +0 -0
  353. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_hana_type_mapping.py +0 -0
  354. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_ibis_check_execute.py +0 -0
  355. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_ibis_mssql_pattern.py +0 -0
  356. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_ibis_mssql_schema.py +0 -0
  357. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_ibis_oracle_schema.py +0 -0
  358. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_athena.py +0 -0
  359. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_avro.py +0 -0
  360. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_bigquery.py +0 -0
  361. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_csv.py +0 -0
  362. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_dbml.py +0 -0
  363. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_dbt.py +0 -0
  364. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_excel.py +0 -0
  365. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_glue.py +0 -0
  366. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_iceberg.py +0 -0
  367. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_json.py +0 -0
  368. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_mysql.py +0 -0
  369. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_odcs_v3.py +0 -0
  370. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_oracle.py +0 -0
  371. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_parquet.py +0 -0
  372. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_postgres.py +0 -0
  373. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_powerbi.py +0 -0
  374. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_protobuf.py +0 -0
  375. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_pydantic_model.py +0 -0
  376. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_redshift.py +0 -0
  377. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_snowflake.py +0 -0
  378. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_spark_type_json.py +0 -0
  379. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_sql_oracle.py +0 -0
  380. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_sql_postgres.py +0 -0
  381. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_sql_snowflake.py +0 -0
  382. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_sql_sqlserver.py +0 -0
  383. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_sqlserver.py +0 -0
  384. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_trino.py +0 -0
  385. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_unity_file.py +0 -0
  386. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_import_unmapped_types.py +0 -0
  387. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_install_extras.py +0 -0
  388. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_integration_entropydata.py +0 -0
  389. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_lint.py +0 -0
  390. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_lint_odcs_3_2_constraints.py +0 -0
  391. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_lint_urls.py +0 -0
  392. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_map_type.py +0 -0
  393. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_metadata_fields.py +0 -0
  394. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_native_type_schema_scope.py +0 -0
  395. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_nested_path_checks.py +0 -0
  396. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_oracle_patch.py +0 -0
  397. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_physical_type_match.py +0 -0
  398. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_publish_test_results.py +0 -0
  399. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_publish_test_results_payload.py +0 -0
  400. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_redshift_credentials.py +0 -0
  401. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_redshift_patch.py +0 -0
  402. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_resolve.py +0 -0
  403. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_resolve_definitions.py +0 -0
  404. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_resolve_local_definitions.py +0 -0
  405. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_roundtrip_jsonschema.py +0 -0
  406. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_roundtrip_pydantic_model.py +0 -0
  407. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_row_filter_duplicate_count.py +0 -0
  408. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_run_check_deprecated_fields.py +0 -0
  409. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_run_check_engine.py +0 -0
  410. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_server_overrides.py +0 -0
  411. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_server_type_mssql.py +0 -0
  412. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_server_type_synonyms.py +0 -0
  413. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_servers_3_2_0.py +0 -0
  414. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_snowflake_structured_types.py +0 -0
  415. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_sql_type_converter_physicaltype.py +0 -0
  416. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_api.py +0 -0
  417. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_array_items.py +0 -0
  418. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_athena_iceberg.py +0 -0
  419. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_azure_blob_file.py +0 -0
  420. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_azure_remote.py +0 -0
  421. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_bigquery.py +0 -0
  422. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_databricks.py +0 -0
  423. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_delta.py +0 -0
  424. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_diagnostics.py +0 -0
  425. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_dimension_filter.py +0 -0
  426. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_duckdb.py +0 -0
  427. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_failed_samples.py +0 -0
  428. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_gcs_csv_remote.py +0 -0
  429. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_gcs_json_remote.py +0 -0
  430. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_hana.py +0 -0
  431. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_iceberg.py +0 -0
  432. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_iceberg_s3tables.py +0 -0
  433. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_kafka_decoding.py +0 -0
  434. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_kafka_remote.py +0 -0
  435. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_local_json.py +0 -0
  436. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_local_json_nd.py +0 -0
  437. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_mysql.py +0 -0
  438. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_oracle.py +0 -0
  439. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_oracle_xe.py +0 -0
  440. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_output_json.py +0 -0
  441. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_output_junit.py +0 -0
  442. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_postgres.py +0 -0
  443. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_quality.py +0 -0
  444. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_quality_id_and_tag_filter.py +0 -0
  445. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_quality_local_fallback.py +0 -0
  446. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_redshift.py +0 -0
  447. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_row_filter.py +0 -0
  448. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_s3_json_remote.py +0 -0
  449. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_server_not_found.py +0 -0
  450. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_snowflake.py +0 -0
  451. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_soda_connection_error.py +0 -0
  452. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_sqlserver.py +0 -0
  453. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_test_trino.py +0 -0
  454. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_type_normalize.py +0 -0
  455. {datacontract_cli-1.2.1 → datacontract_cli-1.2.2}/tests/test_variables.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datacontract-cli
3
- Version: 1.2.1
3
+ Version: 1.2.2
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
@@ -12,6 +12,7 @@ from fastapi.security.api_key import APIKeyHeader
12
12
  from pydantic import BaseModel, Field, ValidationError
13
13
 
14
14
  from datacontract.config import Config, known_env_names
15
+ from datacontract.config.variables import CONTRACT_VARIABLES_ENV, allowed_environment, resolve_variables
15
16
  from datacontract.data_contract import DataContract, ExportFormat
16
17
  from datacontract.model.breaking import BreakingChangeEntry
17
18
  from datacontract.model.changelog import ChangelogEntry
@@ -527,7 +528,10 @@ def _selected_server(body: str, server_name: str | None, config):
527
528
 
528
529
  try:
529
530
  data_contract = resolve.resolve_data_contract(data_contract_str=body, config=config)
530
- return get_server(data_contract, server_name)
531
+ server = get_server(data_contract, server_name)
532
+ # Guard the server type the test will run against, not a ${VAR:-local} reference to it.
533
+ variables = allowed_environment(_allowed_contract_variables())
534
+ return server and server.model_copy(update={"type": resolve_variables(server.type, variables=variables)})
531
535
  except Exception:
532
536
  return None
533
537
 
@@ -540,6 +544,11 @@ ALLOW_LOCAL_FILES_ENV = "DATACONTRACT_CLI_API_ALLOW_LOCAL_FILES"
540
544
  _TRUTHY = frozenset({"1", "true", "yes", "on"})
541
545
 
542
546
 
547
+ def _allowed_contract_variables() -> list[str]:
548
+ """The variable-name globs a posted contract may resolve; none by default."""
549
+ return (os.getenv(CONTRACT_VARIABLES_ENV) or "").split(",")
550
+
551
+
543
552
  def _local_files_allowed() -> bool:
544
553
  """Whether the operator opted in to serving data from the server's own disk.
545
554
 
@@ -569,7 +578,7 @@ def _reject_local_server_type(body: str, server_name: str | None, config) -> Non
569
578
  detail=(
570
579
  f"Server type '{server.type}' reads from the file system of the server running this API, "
571
580
  f"so it is refused. Use a server type that names a data source, such as s3, gcs, azure, "
572
- f"postgres, or snowflake — or set {ALLOW_LOCAL_FILES_ENV}=true if this deployment serves "
581
+ f"postgres, or snowflake — or start the API server with --allow-local-files if this deployment serves "
573
582
  f"its own files on purpose."
574
583
  ),
575
584
  )
@@ -814,6 +823,7 @@ async def test(
814
823
  filter=filter,
815
824
  filters=parsed_filters,
816
825
  untrusted_contract=untrusted_contract,
826
+ allowed_variables=_allowed_contract_variables(),
817
827
  ).test()
818
828
 
819
829
 
@@ -1,7 +1,10 @@
1
+ import os
2
+
1
3
  import typer
2
4
  from typing_extensions import Annotated
3
5
 
4
6
  from datacontract.cli import app, debug_option, enable_debug_logging
7
+ from datacontract.config.variables import CONTRACT_VARIABLES_ENV
5
8
 
6
9
 
7
10
  def _get_uvicorn_arguments(port: int, host: str, reload: bool, context: typer.Context) -> dict:
@@ -40,6 +43,20 @@ def api(
40
43
  help="Watch the source files and restart the server on changes. For development only; off by default.",
41
44
  ),
42
45
  ] = False,
46
+ contract_variables: Annotated[
47
+ str | None,
48
+ typer.Option(
49
+ help="Environment variables a posted data contract may read through ${VAR} references, "
50
+ "as comma-separated fnmatch globs (e.g. 'TABLE_*,CUTOFF_DATE', or '*' to allow all). Empty by default.",
51
+ ),
52
+ ] = None,
53
+ allow_local_files: Annotated[
54
+ bool | None,
55
+ typer.Option(
56
+ "--allow-local-files/--no-allow-local-files",
57
+ help="Let a posted data contract read the server's own disk through servers[].type: local. Off by default.",
58
+ ),
59
+ ] = None,
43
60
  debug: debug_option = None,
44
61
  ):
45
62
  """
@@ -60,6 +77,14 @@ def api(
60
77
  """
61
78
  enable_debug_logging(debug)
62
79
 
80
+ # Passed through the environment, which survives uvicorn's --reload respawn.
81
+ from datacontract.api import ALLOW_LOCAL_FILES_ENV
82
+
83
+ if contract_variables is not None:
84
+ os.environ[CONTRACT_VARIABLES_ENV] = contract_variables
85
+ if allow_local_files is not None:
86
+ os.environ[ALLOW_LOCAL_FILES_ENV] = "true" if allow_local_files else "false"
87
+
63
88
  import uvicorn
64
89
  from uvicorn.config import LOGGING_CONFIG
65
90
 
@@ -909,3 +909,52 @@ def import_athena(
909
909
  id=id,
910
910
  )
911
911
  _write_result(result, output)
912
+
913
+
914
+ @import_app.command(
915
+ name="odata",
916
+ epilog="Example: datacontract import odata --service-root-url https://example.com/odata/ --entity-set Products --output datacontract.yaml",
917
+ )
918
+ def import_odata(
919
+ service_root_url: Annotated[str, typer.Option(help="HTTP(S) root URL of the OData service.")],
920
+ service_document_file: Annotated[
921
+ Optional[Path],
922
+ typer.Option(help="Local JSON service document. Ignored when --entity-set is supplied."),
923
+ ] = None,
924
+ entity_set: Annotated[
925
+ Optional[List[str]],
926
+ typer.Option(
927
+ help="EntitySet to import (repeat for multiple sets). If omitted, will import all sets from the service document."
928
+ ),
929
+ ] = None,
930
+ metadata_url: Annotated[
931
+ Optional[str],
932
+ typer.Option(
933
+ help="CSDL XML or JSON URL. Defaults to SERVICE_ROOT_URL/$metadata.",
934
+ ),
935
+ ] = None,
936
+ metadata_file: Annotated[
937
+ Optional[Path],
938
+ typer.Option(
939
+ help="Path to a local OData CSDL XML or JSON file. Use either --metadata-file or --metadata-url.",
940
+ ),
941
+ ] = None,
942
+ output: output_option = None,
943
+ owner: owner_option = None,
944
+ id: id_option = None,
945
+ debug: debug_option = None,
946
+ ):
947
+ """Import a data contract from OData 4.x CSDL XML or JSON metadata, using a URL or local file."""
948
+ enable_debug_logging(debug)
949
+ result = DataContract.import_from_source(
950
+ config=cli_config(),
951
+ format="odata",
952
+ source=service_root_url,
953
+ odata_service_document_file=service_document_file,
954
+ odata_entity_set=entity_set,
955
+ odata_metadata_url=metadata_url,
956
+ odata_metadata_file=metadata_file,
957
+ owner=owner,
958
+ id=id,
959
+ )
960
+ _write_result(result, output)
@@ -28,6 +28,6 @@ def init(
28
28
  console.print("File already exists, use --overwrite to overwrite")
29
29
  raise typer.Exit(code=1)
30
30
  template_str = get_init_template(template)
31
- with open(location, "w") as f:
31
+ with open(location, "w", encoding="utf-8") as f:
32
32
  f.write(template_str)
33
33
  console.print("📄 data contract written to " + location)
@@ -356,7 +356,7 @@ class Config(BaseSettings):
356
356
 
357
357
  path = Path(path)
358
358
  try:
359
- data = yaml.safe_load(path.read_text())
359
+ data = yaml.safe_load(path.read_text(encoding="utf-8"))
360
360
  except yaml.YAMLError as e:
361
361
  raise ValueError(f"Config file {path} is not valid YAML: {e}")
362
362
  if data is None:
@@ -0,0 +1,256 @@
1
+ """Variable references in string values, per ODCS v3.2.0 (RFC 0050).
2
+
3
+ Any string value in a data contract may contain ``${VAR_NAME}`` or, with an
4
+ inline default, ``${VAR_NAME:-default}``. References are resolved from the
5
+ process environment (which includes a loaded ``.env`` file) at the moment a
6
+ value is *used*: when a connection is opened or a quality query is executed.
7
+ The loaded contract itself is never mutated, so ``export`` and ``publish``
8
+ write the references back verbatim.
9
+
10
+ A reference to an unset or empty variable without a default is an error;
11
+ an empty string is never substituted silently.
12
+ An untrusted contract resolves only the allow-listed part of the environment.
13
+ """
14
+
15
+ import fnmatch
16
+ import os
17
+ import re
18
+ from typing import Iterable, Mapping, Optional
19
+
20
+ from open_data_contract_standard.model import Server
21
+ from pydantic import BaseModel
22
+
23
+ _VARIABLE = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}")
24
+
25
+ CONTRACT_VARIABLES_ENV = "DATACONTRACT_CLI_API_CONTRACT_VARIABLES"
26
+
27
+
28
+ class VariableError(ValueError):
29
+ """A ``${VAR}`` reference could not be turned into a usable value."""
30
+
31
+
32
+ class UnresolvedVariableError(VariableError):
33
+ """A ``${VAR}`` reference names a variable that is unset and has no default."""
34
+
35
+ def __init__(self, name: str, source: str = "", restricted: bool = False):
36
+ self.name = name
37
+ where = f" in {source}" if source else ""
38
+ # "Not listed" must read like "not set", or the message enumerates the host's environment.
39
+ if restricted:
40
+ reason = "is not available. Check if the API permits the resolution (--contract-variables needs to be set)."
41
+ else:
42
+ reason = f"is not set. Set it in the environment or a .env file, or use ${{{name}:-default}}."
43
+ super().__init__(f"Variable {name} referenced{where} {reason}")
44
+
45
+
46
+ def allowed_environment(patterns: Iterable[str]) -> dict[str, str]:
47
+ """The environment entries whose names match one of the ``fnmatch`` ``patterns``."""
48
+ globs = [pattern.strip() for pattern in patterns if pattern and pattern.strip()]
49
+ return {name: value for name, value in os.environ.items() if any(fnmatch.fnmatchcase(name, glob) for glob in globs)}
50
+
51
+
52
+ # The ODCS enums a reference must resolve into, by (model, field); a test keeps them in step with the schema.
53
+ _ENUM_VALUES: dict[tuple[str, str], frozenset[str]] = {
54
+ ("Server", "type"): frozenset(
55
+ {
56
+ "api",
57
+ "athena",
58
+ "azure",
59
+ "bigquery",
60
+ "btrieve",
61
+ "clickhouse",
62
+ "databricks",
63
+ "denodo",
64
+ "dremio",
65
+ "duckdb",
66
+ "exasol",
67
+ "fastobjects",
68
+ "glue",
69
+ "hana",
70
+ "cloudsql",
71
+ "db2",
72
+ "hive",
73
+ "iceberg",
74
+ "impala",
75
+ "informix",
76
+ "ingres",
77
+ "kafka",
78
+ "kinesis",
79
+ "local",
80
+ "mysql",
81
+ "oracle",
82
+ "poet",
83
+ "postgresql",
84
+ "postgres",
85
+ "presto",
86
+ "pubsub",
87
+ "redshift",
88
+ "s3",
89
+ "sftp",
90
+ "snowflake",
91
+ "sqlserver",
92
+ "synapse",
93
+ "teradata",
94
+ "trino",
95
+ "vectorwise",
96
+ "versant",
97
+ "vertica",
98
+ "zen",
99
+ "custom",
100
+ }
101
+ ),
102
+ ("DataQuality", "metric"): frozenset(
103
+ {"nullValues", "missingValues", "invalidValues", "duplicateValues", "rowCount"}
104
+ ),
105
+ ("DataQuality", "type"): frozenset({"text", "library", "sql", "custom"}),
106
+ ("DataQuality", "dimension"): frozenset(
107
+ {"accuracy", "completeness", "conformity", "consistency", "coverage", "timeliness", "uniqueness"}
108
+ ),
109
+ ("SchemaObject", "logicalType"): frozenset({"object", "blob"}),
110
+ ("SchemaProperty", "logicalType"): frozenset(
111
+ {
112
+ "string",
113
+ "date",
114
+ "timestamp",
115
+ "time",
116
+ "number",
117
+ "integer",
118
+ "boolean",
119
+ "object",
120
+ "array",
121
+ "map",
122
+ "vector",
123
+ }
124
+ ),
125
+ }
126
+
127
+
128
+ class InvalidVariableValueError(VariableError):
129
+ """A reference resolved outside the field's enum. Never quotes the value: it may be a secret."""
130
+
131
+ def __init__(self, reference: str, source: str, allowed: frozenset[str]):
132
+ super().__init__(
133
+ f"{source} resolved {reference} into an invalid value. Expected one of: {', '.join(sorted(allowed))}."
134
+ )
135
+
136
+
137
+ def _checked(original, resolved, owner: str, field: str, source: str):
138
+ """Reject a resolved value the field's ODCS enum does not accept."""
139
+ allowed = _ENUM_VALUES.get((owner, field))
140
+ if allowed is None or not contains_variables(original) or resolved in allowed:
141
+ return resolved
142
+ raise InvalidVariableValueError(original, source, allowed)
143
+
144
+
145
+ def contains_variables(value) -> bool:
146
+ """True if ``value`` is a string holding at least one ``${VAR}`` reference."""
147
+ return isinstance(value, str) and _VARIABLE.search(value) is not None
148
+
149
+
150
+ def resolve_variables(value, source: str = "", variables: Optional[Mapping[str, str]] = None):
151
+ """Return ``value`` with every ``${VAR}`` reference replaced.
152
+
153
+ Non-string values pass through unchanged. ``source`` names the value in
154
+ the error message (``"server 'prod' host"``, ``"config file x.yaml"``).
155
+ ``variables`` replaces the process environment for an untrusted contract.
156
+ """
157
+ if not isinstance(value, str):
158
+ return value
159
+ environment = os.environ if variables is None else variables
160
+
161
+ def replace(match: re.Match) -> str:
162
+ name, default = match.group(1), match.group(2)
163
+ env_value = environment.get(name)
164
+ if env_value:
165
+ return env_value
166
+ if default is not None:
167
+ return default
168
+ raise UnresolvedVariableError(name, source, restricted=variables is not None)
169
+
170
+ return _VARIABLE.sub(replace, value)
171
+
172
+
173
+ def resolve_server_variables(server: Server, variables: Optional[Mapping[str, str]] = None) -> Server:
174
+ """Return a copy of ``server`` with the references in its string fields resolved.
175
+
176
+ ``port`` may hold a reference (the schema allows a string there for that
177
+ reason); a resolved all-digit port becomes an int again. Custom property
178
+ values are resolved too. The contract's server is not mutated.
179
+ """
180
+ updates = {}
181
+ for field in Server.model_fields:
182
+ value = getattr(server, field)
183
+ if contains_variables(value):
184
+ source = f"server '{server.server}' {_field_name(field)}"
185
+ updates[field] = _checked(
186
+ value, resolve_variables(value, source=source, variables=variables), "Server", field, source
187
+ )
188
+ port = updates.get("port", server.port)
189
+ if isinstance(port, str) and port.isdigit():
190
+ updates["port"] = int(port)
191
+ if server.customProperties:
192
+ custom_properties = []
193
+ changed = False
194
+ for prop in server.customProperties:
195
+ if contains_variables(prop.value):
196
+ changed = True
197
+ prop = prop.model_copy(
198
+ update={
199
+ "value": resolve_variables(
200
+ prop.value,
201
+ source=f"server '{server.server}' custom property '{prop.property}'",
202
+ variables=variables,
203
+ )
204
+ }
205
+ )
206
+ custom_properties.append(prop)
207
+ if changed:
208
+ updates["customProperties"] = custom_properties
209
+ return server.model_copy(update=updates) if updates else server
210
+
211
+
212
+ def _field_name(field: str) -> str:
213
+ return "schema" if field == "schema_" else field
214
+
215
+
216
+ # These fields document the contract rather than supply test inputs. SQL queries
217
+ # resolve separately, after the engine substitutes its ${model}/${field} tokens;
218
+ # servers resolve separately, after configuration overrides and server selection.
219
+ _DEFERRED_FIELDS = {
220
+ "authoritativeDefinitions",
221
+ "businessName",
222
+ "context",
223
+ "description",
224
+ "examples",
225
+ "implementation",
226
+ "query",
227
+ "servers",
228
+ "synonyms",
229
+ "transformLogic",
230
+ "transformSourceObjects",
231
+ }
232
+
233
+
234
+ def resolve_runtime_variables(value, source: str = "contract", variables: Optional[Mapping[str, str]] = None):
235
+ """Copy test inputs with variables resolved, recursively, without altering the contract.
236
+
237
+ Handles property names/types, enum values, logical type options, library
238
+ quality arguments, SLA values, and nested array/map definitions. Dictionary
239
+ keys are structural identifiers and are never interpolated.
240
+ """
241
+ if isinstance(value, BaseModel):
242
+ owner = type(value).__name__
243
+ updates = {}
244
+ for field in type(value).model_fields:
245
+ if field in _DEFERRED_FIELDS:
246
+ continue
247
+ original = getattr(value, field)
248
+ field_source = f"{source}.{_field_name(field)}"
249
+ resolved = resolve_runtime_variables(original, field_source, variables)
250
+ updates[field] = _checked(original, resolved, owner, field, field_source)
251
+ return value.model_copy(update=updates)
252
+ if isinstance(value, dict):
253
+ return {key: resolve_runtime_variables(item, f"{source}.{key}", variables) for key, item in value.items()}
254
+ if isinstance(value, list):
255
+ return [resolve_runtime_variables(item, f"{source}[{index}]", variables) for index, item in enumerate(value)]
256
+ return resolve_variables(value, source=source, variables=variables)
@@ -11,6 +11,7 @@ if typing.TYPE_CHECKING:
11
11
 
12
12
  from datacontract.breaking.detector import BreakingChangeDetector
13
13
  from datacontract.config import Config
14
+ from datacontract.engines.checks.create_checks import to_schema_name, unexecuted_check_name, unrunnable_reason
14
15
  from datacontract.engines.checks.dimensions import default_dimension
15
16
  from datacontract.engines.data_contract_test import execute_data_contract_test
16
17
  from datacontract.export.exporter import ExportFormat
@@ -31,6 +32,53 @@ from datacontract.model.run import Check, ResultEnum, Run
31
32
  logger = logging.getLogger(__name__)
32
33
 
33
34
 
35
+ def _unrunnable_rule_checks(data_contract: OpenDataContractStandard) -> list[Check]:
36
+ """Warnings for quality rules `datacontract test` would not be able to run."""
37
+ checks = []
38
+
39
+ def visit(properties, schema_name, prefix=None):
40
+ for prop in properties or []:
41
+ name = prop.physicalName or prop.name
42
+ field = f"{prefix}.{name}" if prefix else name
43
+ for quality in prop.quality or []:
44
+ reason = unrunnable_reason(quality, field)
45
+ if reason is not None:
46
+ checks.append(
47
+ Check(
48
+ type="lint",
49
+ result=ResultEnum.warning,
50
+ name=unexecuted_check_name(schema_name, field),
51
+ reason=reason,
52
+ model=schema_name,
53
+ field=field,
54
+ engine="datacontract-cli",
55
+ )
56
+ )
57
+ visit(prop.properties, schema_name, field)
58
+ # `[]` marks the array hop, as the check keys do.
59
+ if prop.items is not None:
60
+ visit(prop.items.properties, schema_name, f"{field}[]")
61
+
62
+ for schema_obj in data_contract.schema_ or []:
63
+ # Named like the checks `test` reports for the same rules.
64
+ schema_name = to_schema_name(schema_obj, None)
65
+ for quality in schema_obj.quality or []:
66
+ reason = unrunnable_reason(quality, None)
67
+ if reason is not None:
68
+ checks.append(
69
+ Check(
70
+ type="lint",
71
+ result=ResultEnum.warning,
72
+ name=unexecuted_check_name(schema_name, None),
73
+ reason=reason,
74
+ model=schema_name,
75
+ engine="datacontract-cli",
76
+ )
77
+ )
78
+ visit(schema_obj.properties, schema_name)
79
+ return checks
80
+
81
+
34
82
  class DataContract:
35
83
  def __init__(
36
84
  self,
@@ -58,6 +106,7 @@ class DataContract:
58
106
  metadata_only: bool = False,
59
107
  dry_run: bool = False,
60
108
  untrusted_contract: bool = False,
109
+ allowed_variables: list[str] | None = None,
61
110
  config: "Config | dict[str, str] | None" = None,
62
111
  ):
63
112
  self._data_contract_file = data_contract_file
@@ -87,6 +136,8 @@ class DataContract:
87
136
  # server): the SQL it carries must not reach the host running it, and its
88
137
  # authoritativeDefinitions are resolved against the configured host only.
89
138
  self._untrusted_contract = untrusted_contract
139
+ # fnmatch globs of the environment variables an untrusted contract may read.
140
+ self._allowed_variables = allowed_variables
90
141
  self._config = Config.resolve(config)
91
142
 
92
143
  @classmethod
@@ -120,6 +171,7 @@ class DataContract:
120
171
  engine="datacontract-cli",
121
172
  )
122
173
  )
174
+ run.checks.extend(_unrunnable_rule_checks(data_contract))
123
175
  run.dataContractId = data_contract.id
124
176
  run.dataContractVersion = data_contract.version
125
177
  except DataContractValidationErrors as e:
@@ -197,6 +249,7 @@ class DataContract:
197
249
  dry_run=self._dry_run,
198
250
  config=self._config,
199
251
  untrusted_contract=self._untrusted_contract,
252
+ allowed_variables=self._allowed_variables,
200
253
  )
201
254
 
202
255
  except DataContractException as e: