datacontract-cli 0.10.20__tar.gz → 0.10.21__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.

Potentially problematic release.


This version of datacontract-cli might be problematic. Click here for more details.

Files changed (209) hide show
  1. {datacontract_cli-0.10.20/datacontract_cli.egg-info → datacontract_cli-0.10.21}/PKG-INFO +103 -22
  2. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/README.md +94 -15
  3. datacontract_cli-0.10.20/datacontract/web.py → datacontract_cli-0.10.21/datacontract/api.py +55 -3
  4. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/cli.py +27 -5
  5. datacontract_cli-0.10.21/datacontract/export/custom_converter.py +40 -0
  6. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/exporter.py +1 -0
  7. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/exporter_factory.py +4 -0
  8. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/urls.py +4 -4
  9. datacontract_cli-0.10.21/datacontract/model/data_contract_specification.py +327 -0
  10. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/run.py +18 -18
  11. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/datacontract.html +16 -2
  12. datacontract_cli-0.10.21/datacontract/templates/partials/definition.html +25 -0
  13. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/model_field.html +13 -0
  14. datacontract_cli-0.10.21/datacontract/templates/partials/quality.html +49 -0
  15. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/style/output.css +151 -152
  16. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21/datacontract_cli.egg-info}/PKG-INFO +103 -22
  17. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/SOURCES.txt +6 -3
  18. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/requires.txt +10 -7
  19. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/pyproject.toml +9 -5
  20. datacontract_cli-0.10.20/tests/test_web.py → datacontract_cli-0.10.21/tests/test_api.py +1 -1
  21. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_catalog.py +1 -0
  22. datacontract_cli-0.10.21/tests/test_export_custom.py +34 -0
  23. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_custom_exporter.py +2 -2
  24. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_html.py +0 -11
  25. datacontract_cli-0.10.20/datacontract/model/data_contract_specification.py +0 -326
  26. datacontract_cli-0.10.20/datacontract/templates/partials/definition.html +0 -117
  27. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/LICENSE +0 -0
  28. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/MANIFEST.in +0 -0
  29. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/__init__.py +0 -0
  30. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/breaking/breaking.py +0 -0
  31. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/breaking/breaking_rules.py +0 -0
  32. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/catalog/catalog.py +0 -0
  33. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/data_contract.py +0 -0
  34. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/__init__.py +0 -0
  35. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +0 -0
  36. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/datacontract/check_that_datacontract_file_exists.py +0 -0
  37. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/fastjsonschema/check_jsonschema.py +0 -0
  38. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/fastjsonschema/s3/s3_read_files.py +0 -0
  39. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/__init__.py +0 -0
  40. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/check_soda_execute.py +0 -0
  41. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/bigquery.py +0 -0
  42. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/dask.py +0 -0
  43. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/databricks.py +0 -0
  44. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/duckdb.py +0 -0
  45. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/kafka.py +0 -0
  46. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/postgres.py +0 -0
  47. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/snowflake.py +0 -0
  48. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/sqlserver.py +0 -0
  49. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/engines/soda/connections/trino.py +0 -0
  50. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/__init__.py +0 -0
  51. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/avro_converter.py +0 -0
  52. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/avro_idl_converter.py +0 -0
  53. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/bigquery_converter.py +0 -0
  54. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/csv_type_converter.py +0 -0
  55. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/data_caterer_converter.py +0 -0
  56. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/dbml_converter.py +0 -0
  57. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/dbt_converter.py +0 -0
  58. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/dcs_exporter.py +0 -0
  59. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/go_converter.py +0 -0
  60. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/great_expectations_converter.py +0 -0
  61. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/html_export.py +0 -0
  62. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/iceberg_converter.py +0 -0
  63. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/jsonschema_converter.py +0 -0
  64. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/markdown_converter.py +0 -0
  65. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/odcs_v2_exporter.py +0 -0
  66. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/odcs_v3_exporter.py +0 -0
  67. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/pandas_type_converter.py +0 -0
  68. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/protobuf_converter.py +0 -0
  69. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/pydantic_converter.py +0 -0
  70. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/rdf_converter.py +0 -0
  71. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sodacl_converter.py +0 -0
  72. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/spark_converter.py +0 -0
  73. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sql_converter.py +0 -0
  74. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sql_type_converter.py +0 -0
  75. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/sqlalchemy_converter.py +0 -0
  76. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/export/terraform_converter.py +0 -0
  77. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/avro_importer.py +0 -0
  78. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/bigquery_importer.py +0 -0
  79. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/csv_importer.py +0 -0
  80. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/dbml_importer.py +0 -0
  81. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/dbt_importer.py +0 -0
  82. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/glue_importer.py +0 -0
  83. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/iceberg_importer.py +0 -0
  84. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/importer.py +0 -0
  85. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/importer_factory.py +0 -0
  86. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/jsonschema_importer.py +0 -0
  87. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/odcs_importer.py +0 -0
  88. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/odcs_v2_importer.py +0 -0
  89. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/odcs_v3_importer.py +0 -0
  90. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/parquet_importer.py +0 -0
  91. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/spark_importer.py +0 -0
  92. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/sql_importer.py +0 -0
  93. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/imports/unity_importer.py +0 -0
  94. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/init/init_template.py +0 -0
  95. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/integration/datamesh_manager.py +0 -0
  96. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/files.py +0 -0
  97. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/lint.py +0 -0
  98. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/__init__.py +0 -0
  99. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/description_linter.py +0 -0
  100. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/example_model_linter.py +0 -0
  101. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/field_pattern_linter.py +0 -0
  102. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/field_reference_linter.py +0 -0
  103. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/notice_period_linter.py +0 -0
  104. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/quality_schema_linter.py +0 -0
  105. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/linters/valid_constraints_linter.py +0 -0
  106. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/resolve.py +0 -0
  107. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/resources.py +0 -0
  108. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/lint/schema.py +0 -0
  109. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/breaking_change.py +0 -0
  110. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/exceptions.py +0 -0
  111. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/model/odcs.py +0 -0
  112. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/py.typed +0 -0
  113. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/schemas/datacontract-1.1.0.init.yaml +0 -0
  114. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/schemas/datacontract-1.1.0.schema.json +0 -0
  115. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/schemas/odcs-3.0.1.schema.json +0 -0
  116. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/index.html +0 -0
  117. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_information.html +0 -0
  118. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_servicelevels.html +0 -0
  119. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/datacontract_terms.html +0 -0
  120. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/example.html +0 -0
  121. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract/templates/partials/server.html +0 -0
  122. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/dependency_links.txt +0 -0
  123. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/entry_points.txt +0 -0
  124. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/datacontract_cli.egg-info/top_level.txt +0 -0
  125. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/setup.cfg +0 -0
  126. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_breaking.py +0 -0
  127. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_changelog.py +0 -0
  128. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_cli.py +0 -0
  129. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_data_contract_specification.py +0 -0
  130. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_description_linter.py +0 -0
  131. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_documentation_linter.py +0 -0
  132. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_download_datacontract_file.py +0 -0
  133. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_example_model_linter.py +0 -0
  134. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_avro.py +0 -0
  135. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_avro_idl.py +0 -0
  136. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_bigquery.py +0 -0
  137. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_complex_data_contract.py +0 -0
  138. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_data_caterer.py +0 -0
  139. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbml.py +0 -0
  140. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbt_models.py +0 -0
  141. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbt_sources.py +0 -0
  142. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_dbt_staging_sql.py +0 -0
  143. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_go.py +0 -0
  144. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_great_expectations.py +0 -0
  145. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_iceberg.py +0 -0
  146. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_jsonschema.py +0 -0
  147. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_markdown.py +0 -0
  148. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_odcs_v2.py +0 -0
  149. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_odcs_v3.py +0 -0
  150. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_protobuf.py +0 -0
  151. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_pydantic.py +0 -0
  152. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_rdf.py +0 -0
  153. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sodacl.py +0 -0
  154. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_spark.py +0 -0
  155. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sql.py +0 -0
  156. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sql_query.py +0 -0
  157. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_sqlalchemy.py +0 -0
  158. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_export_terraform.py +0 -0
  159. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_field_constraint_linter.py +0 -0
  160. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_field_pattern_linter.py +0 -0
  161. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_field_reference_linter.py +0 -0
  162. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_avro.py +0 -0
  163. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_bigquery.py +0 -0
  164. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_csv.py +0 -0
  165. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_dbml.py +0 -0
  166. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_dbt.py +0 -0
  167. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_glue.py +0 -0
  168. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_iceberg.py +0 -0
  169. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_jsonschema.py +0 -0
  170. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_odcs_v2.py +0 -0
  171. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_odcs_v3.py +0 -0
  172. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_parquet.py +0 -0
  173. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_spark.py +0 -0
  174. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_sql.py +0 -0
  175. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_import_unity_file.py +0 -0
  176. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_integration_datameshmanager.py +0 -0
  177. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_lint.py +0 -0
  178. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_notice_period_linter.py +0 -0
  179. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_quality_schema_linter.py +0 -0
  180. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_resolve.py +0 -0
  181. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_roundtrip_jsonschema.py +0 -0
  182. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_spec_fields_field.py +0 -0
  183. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_spec_ref.py +0 -0
  184. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_azure_remote.py +0 -0
  185. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_bigquery.py +0 -0
  186. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_databricks.py +0 -0
  187. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_dataframe.py +0 -0
  188. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_delta.py +0 -0
  189. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_csv.py +0 -0
  190. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_formats_valid.py +0 -0
  191. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_inline.py +0 -0
  192. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_json.py +0 -0
  193. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_examples_missing.py +0 -0
  194. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_gcs_json_remote.py +0 -0
  195. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_kafka.py +0 -0
  196. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_kafka_remote.py +0 -0
  197. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_local_json.py +0 -0
  198. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_parquet.py +0 -0
  199. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_postgres.py +0 -0
  200. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_quality.py +0 -0
  201. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_csv.py +0 -0
  202. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_delta.py +0 -0
  203. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json.py +0 -0
  204. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json_complex.py +0 -0
  205. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json_multiple_models.py +0 -0
  206. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_s3_json_remote.py +0 -0
  207. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_snowflake.py +0 -0
  208. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_sqlserver.py +0 -0
  209. {datacontract_cli-0.10.20 → datacontract_cli-0.10.21}/tests/test_test_trino.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: datacontract-cli
3
- Version: 0.10.20
3
+ Version: 0.10.21
4
4
  Summary: The datacontract CLI is an open source command-line tool for working with Data Contracts. It uses data contract YAML files to lint the data contract, connect to data sources and execute schema and quality tests, detect breaking changes, and export to different formats. The tool is written in Python. It can be used as a standalone CLI tool, in a CI/CD pipeline, or directly as a Python library.
5
5
  Author-email: Jochen Christ <jochen.christ@innoq.com>, Stefan Negele <stefan.negele@innoq.com>, Simon Harrer <simon.harrer@innoq.com>
6
6
  Project-URL: Homepage, https://cli.datacontract.com
@@ -49,7 +49,7 @@ Provides-Extra: postgres
49
49
  Requires-Dist: soda-core-postgres<3.4.0,>=3.3.20; extra == "postgres"
50
50
  Provides-Extra: s3
51
51
  Requires-Dist: s3fs==2024.12.0; extra == "s3"
52
- Requires-Dist: aiobotocore<2.18.0,>=2.17.0; extra == "s3"
52
+ Requires-Dist: aiobotocore<2.20.0,>=2.17.0; extra == "s3"
53
53
  Provides-Extra: snowflake
54
54
  Requires-Dist: snowflake-connector-python[pandas]<3.13,>=3.6; extra == "snowflake"
55
55
  Requires-Dist: soda-core-snowflake<3.4.0,>=3.3.20; extra == "snowflake"
@@ -63,16 +63,18 @@ Provides-Extra: dbml
63
63
  Requires-Dist: pydbml>=1.1.1; extra == "dbml"
64
64
  Provides-Extra: parquet
65
65
  Requires-Dist: pyarrow>=18.1.0; extra == "parquet"
66
- Provides-Extra: web
67
- Requires-Dist: fastapi==0.115.6; extra == "web"
68
- Requires-Dist: uvicorn==0.34.0; extra == "web"
66
+ Provides-Extra: api
67
+ Requires-Dist: fastapi==0.115.6; extra == "api"
68
+ Requires-Dist: uvicorn==0.34.0; extra == "api"
69
+ Provides-Extra: custom
70
+ Requires-Dist: Jinja2>=3.1.5; extra == "custom"
69
71
  Provides-Extra: all
70
- Requires-Dist: datacontract-cli[bigquery,csv,databricks,dbml,dbt,iceberg,kafka,parquet,postgres,s3,snowflake,sqlserver,trino,web]; extra == "all"
72
+ Requires-Dist: datacontract-cli[api,bigquery,csv,custom,databricks,dbml,dbt,iceberg,kafka,parquet,postgres,s3,snowflake,sqlserver,trino]; extra == "all"
71
73
  Provides-Extra: dev
72
74
  Requires-Dist: datacontract-cli[all]; extra == "dev"
73
75
  Requires-Dist: httpx==0.28.1; extra == "dev"
74
76
  Requires-Dist: kafka-python; extra == "dev"
75
- Requires-Dist: moto==5.0.26; extra == "dev"
77
+ Requires-Dist: moto==5.0.27; extra == "dev"
76
78
  Requires-Dist: pandas>=2.1.0; extra == "dev"
77
79
  Requires-Dist: pre-commit<4.1.0,>=3.7.1; extra == "dev"
78
80
  Requires-Dist: pytest; extra == "dev"
@@ -305,7 +307,7 @@ Commands
305
307
  - [diff](#diff)
306
308
  - [catalog](#catalog)
307
309
  - [publish](#publish)
308
- - [serve](#serve)
310
+ - [api](#api)
309
311
 
310
312
  ### init
311
313
  ```
@@ -881,7 +883,7 @@ models:
881
883
  │ vro-idl|sql|sql-query|html| │
882
884
  │ go|bigquery|dbml|spark|sqla │
883
885
  │ lchemy|data-caterer|dcs|mar │
884
- │ kdown|iceberg]
886
+ │ kdown|iceberg|custom]
885
887
  │ --output PATH Specify the file path where │
886
888
  │ the exported data will be │
887
889
  │ saved. If no path is │
@@ -904,6 +906,9 @@ models:
904
906
  │ --engine TEXT [engine] The engine used for │
905
907
  │ great expection run. │
906
908
  │ [default: None] │
909
+ │ --template PATH [custom] The file path of │
910
+ │ Jinja template. │
911
+ │ [default: None] │
907
912
  │ --help Show this message and exit. │
908
913
  ╰──────────────────────────────────────────────────────────────────────────────╯
909
914
  ╭─ RDF Options ────────────────────────────────────────────────────────────────╮
@@ -955,6 +960,7 @@ Available export options:
955
960
  | `dcs` | Export to Data Contract Specification in YAML format | ✅ |
956
961
  | `markdown` | Export to Markdown | ✅ |
957
962
  | `iceberg` | Export to an Iceberg JSON Schema Definition | partial |
963
+ | `custom` | Export to Custom format with Jinja | ✅ |
958
964
  | Missing something? | Please create an issue on GitHub | TBD |
959
965
 
960
966
 
@@ -1136,6 +1142,76 @@ to limit your contract export to a single model.
1136
1142
  }
1137
1143
  ```
1138
1144
 
1145
+ #### Custom
1146
+
1147
+ The export function converts the data contract specification into the custom format with Jinja. You can specify the path to a Jinja template with the `--template` argument, allowing you to output files in any format.
1148
+
1149
+ ```shell
1150
+ datacontract export --format custom --template template.txt datacontract.yaml
1151
+ ```
1152
+
1153
+ ##### Jinja variables
1154
+
1155
+ You can directly use the Data Contract Specification as template variables.
1156
+
1157
+ ```shell
1158
+ $ cat template.txt
1159
+ title: {{ data_contract.info.title }}
1160
+
1161
+ $ datacontract export --format custom --template template.txt datacontract.yaml
1162
+ title: Orders Latest
1163
+ ```
1164
+
1165
+ ##### Example Jinja Templates
1166
+
1167
+ ###### Customized dbt model
1168
+
1169
+ You can export the dbt models containing any logic.
1170
+
1171
+ Below is an example of a dbt staging layer that converts a field of `type: timestamp` to a `DATETIME` type with time zone conversion.
1172
+
1173
+ template.sql
1174
+
1175
+ {% raw %}
1176
+ ```sql
1177
+ {%- for model_name, model in data_contract.models.items() %}
1178
+ {#- Export only the first model #}
1179
+ {%- if loop.first -%}
1180
+ SELECT
1181
+ {%- for field_name, field in model.fields.items() %}
1182
+ {%- if field.type == "timestamp" %}
1183
+ DATETIME({{ field_name }}, "Asia/Tokyo") AS {{ field_name }},
1184
+ {%- else %}
1185
+ {{ field_name }} AS {{ field_name }},
1186
+ {%- endif %}
1187
+ {%- endfor %}
1188
+ FROM
1189
+ {{ "{{" }} ref('{{ model_name }}') {{ "}}" }}
1190
+ {%- endif %}
1191
+ {%- endfor %}
1192
+ ```
1193
+ {% endraw %}
1194
+
1195
+ command
1196
+
1197
+ ```shell
1198
+ datacontract export --format custom --template template.sql --output output.sql datacontract.yaml
1199
+ ```
1200
+
1201
+ output.sql
1202
+
1203
+ ```sql
1204
+ SELECT
1205
+ order_id AS order_id,
1206
+ DATETIME(order_timestamp, "Asia/Tokyo") AS order_timestamp,
1207
+ order_total AS order_total,
1208
+ customer_id AS customer_id,
1209
+ customer_email_address AS customer_email_address,
1210
+ DATETIME(processed_timestamp, "Asia/Tokyo") AS processed_timestamp,
1211
+ FROM
1212
+ {{ ref('orders') }}
1213
+ ```
1214
+
1139
1215
  ### import
1140
1216
  ```
1141
1217
 
@@ -1540,18 +1616,23 @@ datacontract catalog --files "*.odcs.yaml"
1540
1616
 
1541
1617
  ```
1542
1618
 
1543
- ### serve
1619
+ ### api
1544
1620
  ```
1545
-
1546
- Usage: datacontract serve [OPTIONS]
1547
-
1548
- Start the datacontract web server.
1549
-
1550
- ╭─ Options ────────────────────────────────────────────────────────────────────╮
1551
- --port INTEGER Bind socket to this port. [default: 4242] │
1552
- --host TEXT Bind socket to this host. [default: 127.0.0.1] │
1553
- │ --help Show this message and exit. │
1554
- ╰──────────────────────────────────────────────────────────────────────────────╯
1621
+
1622
+ Usage: datacontract api [OPTIONS]
1623
+
1624
+ Start the datacontract CLI as server application with REST API.
1625
+ The OpenAPI documentation as Swagger UI is available on http://localhost:4242. You can execute the commands directly from the Swagger UI.
1626
+ To protect the API, you can set the environment variable DATACONTRACT_CLI_API_KEY to a secret API key. To authenticate, requests must include the header 'x-api-key' with the
1627
+ correct API key. This is highly recommended, as data contract tests may be subject to SQL injections or leak sensitive information.
1628
+ To connect to servers (such as a Snowflake data source), set the credentials as environment variables as documented in https://cli.datacontract.com/#test
1629
+
1630
+ ╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
1631
+ │ --port INTEGER Bind socket to this port. [default: 4242] │
1632
+ │ --host TEXT Bind socket to this host. Hint: For running in docker, set it to 0.0.0.0 [default: 127.0.0.1] │
1633
+ │ --help Show this message and exit. │
1634
+ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
1635
+
1555
1636
 
1556
1637
  ```
1557
1638
 
@@ -1709,7 +1790,7 @@ class CustomExporter(Exporter):
1709
1790
 
1710
1791
 
1711
1792
  # Register the new custom class into factory
1712
- exporter_factory.register_exporter("custom", CustomExporter)
1793
+ exporter_factory.register_exporter("custom_exporter", CustomExporter)
1713
1794
 
1714
1795
 
1715
1796
  if __name__ == "__main__":
@@ -1719,7 +1800,7 @@ if __name__ == "__main__":
1719
1800
  )
1720
1801
  # Call export
1721
1802
  result = data_contract.export(
1722
- export_format="custom", model="orders", server="production", custom_arg="my_custom_arg"
1803
+ export_format="custom_exporter", model="orders", server="production", custom_arg="my_custom_arg"
1723
1804
  )
1724
1805
  print(result)
1725
1806
 
@@ -221,7 +221,7 @@ Commands
221
221
  - [diff](#diff)
222
222
  - [catalog](#catalog)
223
223
  - [publish](#publish)
224
- - [serve](#serve)
224
+ - [api](#api)
225
225
 
226
226
  ### init
227
227
  ```
@@ -797,7 +797,7 @@ models:
797
797
  │ vro-idl|sql|sql-query|html| │
798
798
  │ go|bigquery|dbml|spark|sqla │
799
799
  │ lchemy|data-caterer|dcs|mar │
800
- │ kdown|iceberg]
800
+ │ kdown|iceberg|custom]
801
801
  │ --output PATH Specify the file path where │
802
802
  │ the exported data will be │
803
803
  │ saved. If no path is │
@@ -820,6 +820,9 @@ models:
820
820
  │ --engine TEXT [engine] The engine used for │
821
821
  │ great expection run. │
822
822
  │ [default: None] │
823
+ │ --template PATH [custom] The file path of │
824
+ │ Jinja template. │
825
+ │ [default: None] │
823
826
  │ --help Show this message and exit. │
824
827
  ╰──────────────────────────────────────────────────────────────────────────────╯
825
828
  ╭─ RDF Options ────────────────────────────────────────────────────────────────╮
@@ -871,6 +874,7 @@ Available export options:
871
874
  | `dcs` | Export to Data Contract Specification in YAML format | ✅ |
872
875
  | `markdown` | Export to Markdown | ✅ |
873
876
  | `iceberg` | Export to an Iceberg JSON Schema Definition | partial |
877
+ | `custom` | Export to Custom format with Jinja | ✅ |
874
878
  | Missing something? | Please create an issue on GitHub | TBD |
875
879
 
876
880
 
@@ -1052,6 +1056,76 @@ to limit your contract export to a single model.
1052
1056
  }
1053
1057
  ```
1054
1058
 
1059
+ #### Custom
1060
+
1061
+ The export function converts the data contract specification into the custom format with Jinja. You can specify the path to a Jinja template with the `--template` argument, allowing you to output files in any format.
1062
+
1063
+ ```shell
1064
+ datacontract export --format custom --template template.txt datacontract.yaml
1065
+ ```
1066
+
1067
+ ##### Jinja variables
1068
+
1069
+ You can directly use the Data Contract Specification as template variables.
1070
+
1071
+ ```shell
1072
+ $ cat template.txt
1073
+ title: {{ data_contract.info.title }}
1074
+
1075
+ $ datacontract export --format custom --template template.txt datacontract.yaml
1076
+ title: Orders Latest
1077
+ ```
1078
+
1079
+ ##### Example Jinja Templates
1080
+
1081
+ ###### Customized dbt model
1082
+
1083
+ You can export the dbt models containing any logic.
1084
+
1085
+ Below is an example of a dbt staging layer that converts a field of `type: timestamp` to a `DATETIME` type with time zone conversion.
1086
+
1087
+ template.sql
1088
+
1089
+ {% raw %}
1090
+ ```sql
1091
+ {%- for model_name, model in data_contract.models.items() %}
1092
+ {#- Export only the first model #}
1093
+ {%- if loop.first -%}
1094
+ SELECT
1095
+ {%- for field_name, field in model.fields.items() %}
1096
+ {%- if field.type == "timestamp" %}
1097
+ DATETIME({{ field_name }}, "Asia/Tokyo") AS {{ field_name }},
1098
+ {%- else %}
1099
+ {{ field_name }} AS {{ field_name }},
1100
+ {%- endif %}
1101
+ {%- endfor %}
1102
+ FROM
1103
+ {{ "{{" }} ref('{{ model_name }}') {{ "}}" }}
1104
+ {%- endif %}
1105
+ {%- endfor %}
1106
+ ```
1107
+ {% endraw %}
1108
+
1109
+ command
1110
+
1111
+ ```shell
1112
+ datacontract export --format custom --template template.sql --output output.sql datacontract.yaml
1113
+ ```
1114
+
1115
+ output.sql
1116
+
1117
+ ```sql
1118
+ SELECT
1119
+ order_id AS order_id,
1120
+ DATETIME(order_timestamp, "Asia/Tokyo") AS order_timestamp,
1121
+ order_total AS order_total,
1122
+ customer_id AS customer_id,
1123
+ customer_email_address AS customer_email_address,
1124
+ DATETIME(processed_timestamp, "Asia/Tokyo") AS processed_timestamp,
1125
+ FROM
1126
+ {{ ref('orders') }}
1127
+ ```
1128
+
1055
1129
  ### import
1056
1130
  ```
1057
1131
 
@@ -1456,18 +1530,23 @@ datacontract catalog --files "*.odcs.yaml"
1456
1530
 
1457
1531
  ```
1458
1532
 
1459
- ### serve
1533
+ ### api
1460
1534
  ```
1461
-
1462
- Usage: datacontract serve [OPTIONS]
1463
-
1464
- Start the datacontract web server.
1465
-
1466
- ╭─ Options ────────────────────────────────────────────────────────────────────╮
1467
- --port INTEGER Bind socket to this port. [default: 4242] │
1468
- --host TEXT Bind socket to this host. [default: 127.0.0.1] │
1469
- │ --help Show this message and exit. │
1470
- ╰──────────────────────────────────────────────────────────────────────────────╯
1535
+
1536
+ Usage: datacontract api [OPTIONS]
1537
+
1538
+ Start the datacontract CLI as server application with REST API.
1539
+ The OpenAPI documentation as Swagger UI is available on http://localhost:4242. You can execute the commands directly from the Swagger UI.
1540
+ To protect the API, you can set the environment variable DATACONTRACT_CLI_API_KEY to a secret API key. To authenticate, requests must include the header 'x-api-key' with the
1541
+ correct API key. This is highly recommended, as data contract tests may be subject to SQL injections or leak sensitive information.
1542
+ To connect to servers (such as a Snowflake data source), set the credentials as environment variables as documented in https://cli.datacontract.com/#test
1543
+
1544
+ ╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
1545
+ │ --port INTEGER Bind socket to this port. [default: 4242] │
1546
+ │ --host TEXT Bind socket to this host. Hint: For running in docker, set it to 0.0.0.0 [default: 127.0.0.1] │
1547
+ │ --help Show this message and exit. │
1548
+ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
1549
+
1471
1550
 
1472
1551
  ```
1473
1552
 
@@ -1625,7 +1704,7 @@ class CustomExporter(Exporter):
1625
1704
 
1626
1705
 
1627
1706
  # Register the new custom class into factory
1628
- exporter_factory.register_exporter("custom", CustomExporter)
1707
+ exporter_factory.register_exporter("custom_exporter", CustomExporter)
1629
1708
 
1630
1709
 
1631
1710
  if __name__ == "__main__":
@@ -1635,7 +1714,7 @@ if __name__ == "__main__":
1635
1714
  )
1636
1715
  # Call export
1637
1716
  result = data_contract.export(
1638
- export_format="custom", model="orders", server="production", custom_arg="my_custom_arg"
1717
+ export_format="custom_exporter", model="orders", server="production", custom_arg="my_custom_arg"
1639
1718
  )
1640
1719
  print(result)
1641
1720
 
@@ -1,8 +1,11 @@
1
+ import logging
2
+ import os
1
3
  from typing import Annotated, Optional
2
4
 
3
5
  import typer
4
- from fastapi import Body, FastAPI, Query
6
+ from fastapi import Body, Depends, FastAPI, HTTPException, Query, status
5
7
  from fastapi.responses import PlainTextResponse
8
+ from fastapi.security.api_key import APIKeyHeader
6
9
 
7
10
  from datacontract.data_contract import DataContract, ExportFormat
8
11
  from datacontract.model.run import Run
@@ -55,8 +58,8 @@ models:
55
58
 
56
59
  app = FastAPI(
57
60
  docs_url="/",
58
- title="Data Contract API",
59
- summary="API to execute Data Contract CLI operations.",
61
+ title="Data Contract CLI API",
62
+ summary="You can use the API to test, export, and lint your data contracts.",
60
63
  license_info={
61
64
  "name": "MIT License",
62
65
  "identifier": "MIT",
@@ -87,6 +90,32 @@ app = FastAPI(
87
90
  ],
88
91
  )
89
92
 
93
+ api_key_header = APIKeyHeader(
94
+ name="x-api-key",
95
+ auto_error=False, # this makes authentication optional
96
+ )
97
+
98
+
99
+ def check_api_key(api_key_header: str | None):
100
+ correct_api_key = os.getenv("DATACONTRACT_CLI_API_KEY")
101
+ if correct_api_key is None or correct_api_key == "":
102
+ logging.info("Environment variable DATACONTRACT_CLI_API_KEY is not set. Skip API key check.")
103
+ return
104
+ if api_key_header is None or api_key_header == "":
105
+ logging.info("The API key is missing.")
106
+ raise HTTPException(
107
+ status_code=status.HTTP_401_UNAUTHORIZED,
108
+ detail="Missing API key. Use Header 'x-api-key' to provide the API key.",
109
+ )
110
+ if api_key_header != correct_api_key:
111
+ logging.info("The provided API key is not correct.")
112
+ raise HTTPException(
113
+ status_code=status.HTTP_403_FORBIDDEN,
114
+ detail="The provided API key is not correct.",
115
+ )
116
+ logging.info("Request authenticated with API key.")
117
+ pass
118
+
90
119
 
91
120
  @app.post(
92
121
  "/test",
@@ -98,6 +127,25 @@ app = FastAPI(
98
127
  Credentials must be provided via environment variables when running the web server.
99
128
  POST the data contract YAML as payload.
100
129
  """,
130
+ responses={
131
+ 401: {
132
+ "description": "Unauthorized (when an environment variable DATACONTRACT_CLI_API_KEY is configured).",
133
+ "content": {
134
+ "application/json": {
135
+ "examples": {
136
+ "api_key_missing": {
137
+ "summary": "API key Missing",
138
+ "value": {"detail": "Missing API key. Use Header 'x-api-key' to provide the API key."},
139
+ },
140
+ "api_key_wrong": {
141
+ "summary": "API key Wrong",
142
+ "value": {"detail": "The provided API key is not correct."},
143
+ },
144
+ }
145
+ }
146
+ },
147
+ },
148
+ },
101
149
  response_model_exclude_none=True,
102
150
  response_model_exclude_unset=True,
103
151
  )
@@ -110,6 +158,7 @@ async def test(
110
158
  examples=[DATA_CONTRACT_EXAMPLE_PAYLOAD],
111
159
  ),
112
160
  ],
161
+ api_key: Annotated[str | None, Depends(api_key_header)] = None,
113
162
  server: Annotated[
114
163
  str | None,
115
164
  Query(
@@ -118,6 +167,9 @@ async def test(
118
167
  ),
119
168
  ] = None,
120
169
  ) -> Run:
170
+ check_api_key(api_key)
171
+ logging.info("Testing data contract...")
172
+ logging.info(body)
121
173
  return DataContract(data_contract_str=body, server=server).test()
122
174
 
123
175
 
@@ -196,6 +196,11 @@ def export(
196
196
  Optional[str],
197
197
  typer.Option(help="[engine] The engine used for great expection run."),
198
198
  ] = None,
199
+ # TODO: this should be a subcommand
200
+ template: Annotated[
201
+ Optional[Path],
202
+ typer.Option(help="[custom] The file path of Jinja template."),
203
+ ] = None,
199
204
  ):
200
205
  """
201
206
  Convert data contract to a specific format. Saves to file specified by `output` option if present, otherwise prints to stdout.
@@ -208,6 +213,7 @@ def export(
208
213
  rdf_base=rdf_base,
209
214
  sql_server_type=sql_server_type,
210
215
  engine=engine,
216
+ template=template,
211
217
  )
212
218
  # Don't interpret console markup in output.
213
219
  if output is None:
@@ -344,7 +350,7 @@ def catalog(
344
350
  ] = None,
345
351
  ):
346
352
  """
347
- Create an html catalog of data contracts.
353
+ Create a html catalog of data contracts.
348
354
  """
349
355
  path = Path(output)
350
356
  path.mkdir(parents=True, exist_ok=True)
@@ -433,16 +439,32 @@ def diff(
433
439
 
434
440
 
435
441
  @app.command()
436
- def serve(
442
+ def api(
437
443
  port: Annotated[int, typer.Option(help="Bind socket to this port.")] = 4242,
438
- host: Annotated[str, typer.Option(help="Bind socket to this host.")] = "127.0.0.1",
444
+ host: Annotated[
445
+ str, typer.Option(help="Bind socket to this host. Hint: For running in docker, set it to 0.0.0.0")
446
+ ] = "127.0.0.1",
439
447
  ):
440
448
  """
441
- Start the datacontract web server.
449
+ Start the datacontract CLI as server application with REST API.
450
+
451
+ The OpenAPI documentation as Swagger UI is available on http://localhost:4242.
452
+ You can execute the commands directly from the Swagger UI.
453
+
454
+ To protect the API, you can set the environment variable DATACONTRACT_CLI_API_KEY to a secret API key.
455
+ To authenticate, requests must include the header 'x-api-key' with the correct API key.
456
+ This is highly recommended, as data contract tests may be subject to SQL injections or leak sensitive information.
457
+
458
+ To connect to servers (such as a Snowflake data source), set the credentials as environment variables as documented in
459
+ https://cli.datacontract.com/#test
442
460
  """
443
461
  import uvicorn
462
+ from uvicorn.config import LOGGING_CONFIG
463
+
464
+ log_config = LOGGING_CONFIG
465
+ log_config["root"] = {"level": "INFO"}
444
466
 
445
- uvicorn.run("datacontract.web:app", port=port, host=host, reload=True)
467
+ uvicorn.run(app="datacontract.api:app", port=port, host=host, reload=True, log_config=LOGGING_CONFIG)
446
468
 
447
469
 
448
470
  def _handle_result(run):
@@ -0,0 +1,40 @@
1
+ from pathlib import Path
2
+
3
+ from jinja2 import Environment, FileSystemLoader
4
+
5
+ from datacontract.export.exporter import Exporter
6
+ from datacontract.model.data_contract_specification import (
7
+ DataContractSpecification,
8
+ Model,
9
+ )
10
+
11
+
12
+ class CustomExporter(Exporter):
13
+ """Exporter implementation for converting data contracts to Markdown."""
14
+
15
+ def export(
16
+ self,
17
+ data_contract: DataContractSpecification,
18
+ model: Model,
19
+ server: str,
20
+ sql_server_type: str,
21
+ export_args: dict,
22
+ ) -> str:
23
+ """Exports a data contract to custom format with Jinja."""
24
+ template = export_args.get("template")
25
+ if template is None:
26
+ raise RuntimeError("Export to custom requires template argument.")
27
+
28
+ return to_custom(data_contract, template)
29
+
30
+
31
+ def to_custom(data_contract: DataContractSpecification, template_path: Path) -> str:
32
+ template = get_template(template_path)
33
+ rendered_sql = template.render(data_contract=data_contract)
34
+ return rendered_sql
35
+
36
+
37
+ def get_template(path: Path):
38
+ abosolute_path = Path(path).resolve()
39
+ env = Environment(loader=FileSystemLoader(str(abosolute_path.parent)))
40
+ return env.get_template(path.name)
@@ -45,6 +45,7 @@ class ExportFormat(str, Enum):
45
45
  dcs = "dcs"
46
46
  markdown = "markdown"
47
47
  iceberg = "iceberg"
48
+ custom = "custom"
48
49
 
49
50
  @classmethod
50
51
  def get_supported_formats(cls):
@@ -206,3 +206,7 @@ exporter_factory.register_lazy_exporter(
206
206
  exporter_factory.register_lazy_exporter(
207
207
  name=ExportFormat.iceberg, module_path="datacontract.export.iceberg_converter", class_name="IcebergExporter"
208
208
  )
209
+
210
+ exporter_factory.register_lazy_exporter(
211
+ name=ExportFormat.custom, module_path="datacontract.export.custom_converter", class_name="CustomExporter"
212
+ )
@@ -33,22 +33,22 @@ def _set_api_key(headers, url):
33
33
 
34
34
  if hostname == "datamesh-manager.com" or hostname.endswith(".datamesh-manager.com"):
35
35
  if datamesh_manager_api_key is None or datamesh_manager_api_key == "":
36
- print("Error: Data Mesh Manager API Key is not set. Set env variable DATAMESH_MANAGER_API_KEY.")
36
+ print("Error: Data Mesh Manager API key is not set. Set env variable DATAMESH_MANAGER_API_KEY.")
37
37
  raise DataContractException(
38
38
  type="lint",
39
39
  name=f"Reading data contract from {url}",
40
- reason="Error: Data Mesh Manager API Key is not set. Set env variable DATAMESH_MANAGER_API_KEY.",
40
+ reason="Error: Data Mesh Manager API key is not set. Set env variable DATAMESH_MANAGER_API_KEY.",
41
41
  engine="datacontract",
42
42
  result="error",
43
43
  )
44
44
  headers["x-api-key"] = datamesh_manager_api_key
45
45
  elif hostname == "datacontract-manager.com" or hostname.endswith(".datacontract-manager.com"):
46
46
  if datacontract_manager_api_key is None or datacontract_manager_api_key == "":
47
- print("Error: Data Contract Manager API Key is not set. Set env variable DATACONTRACT_MANAGER_API_KEY.")
47
+ print("Error: Data Contract Manager API key is not set. Set env variable DATACONTRACT_MANAGER_API_KEY.")
48
48
  raise DataContractException(
49
49
  type="lint",
50
50
  name=f"Reading data contract from {url}",
51
- reason="Error: Data Contract Manager API Key is not set. Set env variable DATACONTRACT_MANAGER_API_KEY.",
51
+ reason="Error: Data Contract Manager API key is not set. Set env variable DATACONTRACT_MANAGER_API_KEY.",
52
52
  engine="datacontract",
53
53
  result="error",
54
54
  )