datacontract-cli 0.10.23__py3-none-any.whl → 0.10.40__py3-none-any.whl

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 (84) hide show
  1. datacontract/__init__.py +13 -0
  2. datacontract/api.py +12 -5
  3. datacontract/catalog/catalog.py +5 -3
  4. datacontract/cli.py +119 -13
  5. datacontract/data_contract.py +145 -67
  6. datacontract/engines/data_contract_checks.py +366 -60
  7. datacontract/engines/data_contract_test.py +50 -4
  8. datacontract/engines/fastjsonschema/check_jsonschema.py +37 -19
  9. datacontract/engines/fastjsonschema/s3/s3_read_files.py +3 -2
  10. datacontract/engines/soda/check_soda_execute.py +27 -3
  11. datacontract/engines/soda/connections/athena.py +79 -0
  12. datacontract/engines/soda/connections/duckdb_connection.py +65 -6
  13. datacontract/engines/soda/connections/kafka.py +4 -2
  14. datacontract/engines/soda/connections/oracle.py +50 -0
  15. datacontract/export/avro_converter.py +20 -3
  16. datacontract/export/bigquery_converter.py +1 -1
  17. datacontract/export/dbt_converter.py +36 -7
  18. datacontract/export/dqx_converter.py +126 -0
  19. datacontract/export/duckdb_type_converter.py +57 -0
  20. datacontract/export/excel_exporter.py +923 -0
  21. datacontract/export/exporter.py +3 -0
  22. datacontract/export/exporter_factory.py +17 -1
  23. datacontract/export/great_expectations_converter.py +55 -5
  24. datacontract/export/{html_export.py → html_exporter.py} +31 -20
  25. datacontract/export/markdown_converter.py +134 -5
  26. datacontract/export/mermaid_exporter.py +110 -0
  27. datacontract/export/odcs_v3_exporter.py +193 -149
  28. datacontract/export/protobuf_converter.py +163 -69
  29. datacontract/export/rdf_converter.py +2 -2
  30. datacontract/export/sodacl_converter.py +9 -1
  31. datacontract/export/spark_converter.py +31 -4
  32. datacontract/export/sql_converter.py +6 -2
  33. datacontract/export/sql_type_converter.py +124 -8
  34. datacontract/imports/avro_importer.py +63 -12
  35. datacontract/imports/csv_importer.py +111 -57
  36. datacontract/imports/excel_importer.py +1112 -0
  37. datacontract/imports/importer.py +16 -3
  38. datacontract/imports/importer_factory.py +17 -0
  39. datacontract/imports/json_importer.py +325 -0
  40. datacontract/imports/odcs_importer.py +2 -2
  41. datacontract/imports/odcs_v3_importer.py +367 -151
  42. datacontract/imports/protobuf_importer.py +264 -0
  43. datacontract/imports/spark_importer.py +117 -13
  44. datacontract/imports/sql_importer.py +32 -16
  45. datacontract/imports/unity_importer.py +84 -38
  46. datacontract/init/init_template.py +1 -1
  47. datacontract/integration/entropy_data.py +126 -0
  48. datacontract/lint/resolve.py +112 -23
  49. datacontract/lint/schema.py +24 -15
  50. datacontract/lint/urls.py +17 -3
  51. datacontract/model/data_contract_specification/__init__.py +1 -0
  52. datacontract/model/odcs.py +13 -0
  53. datacontract/model/run.py +3 -0
  54. datacontract/output/junit_test_results.py +3 -3
  55. datacontract/schemas/datacontract-1.1.0.init.yaml +1 -1
  56. datacontract/schemas/datacontract-1.2.0.init.yaml +91 -0
  57. datacontract/schemas/datacontract-1.2.0.schema.json +2029 -0
  58. datacontract/schemas/datacontract-1.2.1.init.yaml +91 -0
  59. datacontract/schemas/datacontract-1.2.1.schema.json +2058 -0
  60. datacontract/schemas/odcs-3.0.2.schema.json +2382 -0
  61. datacontract/schemas/odcs-3.1.0.schema.json +2809 -0
  62. datacontract/templates/datacontract.html +54 -3
  63. datacontract/templates/datacontract_odcs.html +685 -0
  64. datacontract/templates/index.html +5 -2
  65. datacontract/templates/partials/server.html +2 -0
  66. datacontract/templates/style/output.css +319 -145
  67. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.40.dist-info}/METADATA +711 -433
  68. datacontract_cli-0.10.40.dist-info/RECORD +121 -0
  69. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.40.dist-info}/WHEEL +1 -1
  70. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.40.dist-info/licenses}/LICENSE +1 -1
  71. datacontract/export/csv_type_converter.py +0 -36
  72. datacontract/integration/datamesh_manager.py +0 -72
  73. datacontract/lint/lint.py +0 -142
  74. datacontract/lint/linters/description_linter.py +0 -35
  75. datacontract/lint/linters/field_pattern_linter.py +0 -34
  76. datacontract/lint/linters/field_reference_linter.py +0 -48
  77. datacontract/lint/linters/notice_period_linter.py +0 -55
  78. datacontract/lint/linters/quality_schema_linter.py +0 -52
  79. datacontract/lint/linters/valid_constraints_linter.py +0 -100
  80. datacontract/model/data_contract_specification.py +0 -327
  81. datacontract_cli-0.10.23.dist-info/RECORD +0 -113
  82. /datacontract/{lint/linters → output}/__init__.py +0 -0
  83. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.40.dist-info}/entry_points.txt +0 -0
  84. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.40.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,121 @@
1
+ datacontract/__init__.py,sha256=ThDdxDJsd7qNErLoh628nK5M7RzhJNYCmN-C6BAJFoo,405
2
+ datacontract/api.py,sha256=nFmrJOhC5AygY9YS1VXsbvKNtW92B8AF-lXdhuCvcPE,8578
3
+ datacontract/cli.py,sha256=SeIfc_VOzqsqsO87JkllxQZTgmUyYdQO8CWWRnKAy_o,20730
4
+ datacontract/data_contract.py,sha256=fU_dwjncNcyoyzvQVTk53ZJsUnY2m8biRKXIzUyKyqM,13236
5
+ datacontract/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ datacontract/breaking/breaking.py,sha256=DnqgxUjD-EAZcg5RBizOP9a2WxsFTaQBik0AB_m3K00,20431
7
+ datacontract/breaking/breaking_change.py,sha256=BIDEUo1U2CQLVT2-I5PyFttxAj6zQPI1UUkEoOOQXMY,2249
8
+ datacontract/breaking/breaking_rules.py,sha256=M9IdzVJSA7oOr1fvLQl0y9MoBKeItPz42Db2U2cjH2Y,4063
9
+ datacontract/catalog/catalog.py,sha256=U5TpDyT9kcF086DoDSS3bWBE4Q8uj6HVuCSFaxN5kMw,2830
10
+ datacontract/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ datacontract/engines/data_contract_checks.py,sha256=LNI0OZPrzrf7sn6lPgTL4uAHSqMH2VBrmaBo8etuSE0,37453
12
+ datacontract/engines/data_contract_test.py,sha256=8qg0SkwtTmayfzNL2U_0xgx5Hi_DUePaMt2q_JiCqX8,4543
13
+ datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py,sha256=zrDn-_EJJ5kv0kZWAA-toeEPuBd3YQ0-U7Jb8euNUS8,1558
14
+ datacontract/engines/datacontract/check_that_datacontract_file_exists.py,sha256=Vw-7U0GmQT2127tybxggZfpRFiZVgoIh6ndkTGM0FP4,665
15
+ datacontract/engines/fastjsonschema/check_jsonschema.py,sha256=EKPkFM8iGyiWsHw8peErhQvbt9gu_zJ2S-NDQnupfeM,10921
16
+ datacontract/engines/fastjsonschema/s3/s3_read_files.py,sha256=0sTDWvuu0AzSgn7fKWJxGaTmPww00TFYyDK-X0s5T3c,1193
17
+ datacontract/engines/soda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ datacontract/engines/soda/check_soda_execute.py,sha256=jOFeylYtixxsX9xk14vPRM7d6jI8ZH3uuCFR6bnTSwg,9241
19
+ datacontract/engines/soda/connections/athena.py,sha256=x-DCEN8LCoy-8nGhEv7ty22s6mQpr-W8HtWQveXgdgA,3024
20
+ datacontract/engines/soda/connections/bigquery.py,sha256=C-8kxmzpYe88bJp80ObHFLMh4rpnIjnUQ7XOj0Ke7lk,903
21
+ datacontract/engines/soda/connections/databricks.py,sha256=cMRasuO0MrSKVgHPB-9uFTGTZPFg6z9Kpk3tJ0SdR0s,943
22
+ datacontract/engines/soda/connections/duckdb_connection.py,sha256=wGiB6EKr-OZosEFvT2gkutFgAzAxFMKicfpjbIJUZwQ,9332
23
+ datacontract/engines/soda/connections/kafka.py,sha256=lnj_-3-CnJ6stetGqm6HOzN1Qatlw7xoCQU2zKBIXxU,8725
24
+ datacontract/engines/soda/connections/oracle.py,sha256=4uEBce67MbOZR8kQqmcsN0bgl1xibd_CfS5JEPiCqm0,1750
25
+ datacontract/engines/soda/connections/postgres.py,sha256=9GTF4Es3M5vb7ocSGqAxXmslvkS5CjsPQGIuo020CFc,626
26
+ datacontract/engines/soda/connections/snowflake.py,sha256=rfG2ysuqNM6TkvyqQKcGHFsTGJ6AROmud5VleUDRrb0,749
27
+ datacontract/engines/soda/connections/sqlserver.py,sha256=RzGLbCUdRyfmDcqtM_AB9WZ-Xk-XYX91nkXpVNpYbvc,1440
28
+ datacontract/engines/soda/connections/trino.py,sha256=JvKUP9aFg_n095oWE0-bGmfbETSWEOURGEZdQuG8txA,718
29
+ datacontract/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ datacontract/export/avro_converter.py,sha256=MnfeW2x-Eko9dK6_fpdQYWtEzLkFWXfKABAUSJqiDpo,5381
31
+ datacontract/export/avro_idl_converter.py,sha256=SGO7JfI9UGXLYFR5wMGNUH1qf6kt9lF6dUU9roVqnFo,9878
32
+ datacontract/export/bigquery_converter.py,sha256=9mm-XP3klu1C5J87L9EL5ZyMCJhLBwsixo3aAw9QmRI,4738
33
+ datacontract/export/custom_converter.py,sha256=xb8KbkRRgHmT4ewwC7XxtnKpe_ZMSJWBjYOaKjmO_KQ,1216
34
+ datacontract/export/data_caterer_converter.py,sha256=eSEuy3TbqUIG_lHYEBOydAgp_CJNoGArXrcJvh81wcw,5984
35
+ datacontract/export/dbml_converter.py,sha256=f_OZEFwRUyL-Kg2yn_G58I8iz1VfFrZh8Nbw3Wq0JDo,4777
36
+ datacontract/export/dbt_converter.py,sha256=58bub8n22dfL8w6bKdFe28BLF0e4PHbrxO_H3rZ9wfk,11840
37
+ datacontract/export/dcs_exporter.py,sha256=RALQ7bLAjak7EsoFFL2GFX2Oju7pnCDPCdRN_wo9wHM,210
38
+ datacontract/export/dqx_converter.py,sha256=5UevFPE8RdFIeu4CgeVnXMNDfWU7DhR34DW7O1aVIFs,4105
39
+ datacontract/export/duckdb_type_converter.py,sha256=hUAAbImhJUMJOXEG-UoOKQqYGrJM6UILpn2YjUuAUOw,2216
40
+ datacontract/export/excel_exporter.py,sha256=qDVcwO38aWPMTYyXo2qJd1HJLkmj_Izhi1hdVOQ8o_w,38424
41
+ datacontract/export/exporter.py,sha256=DfvMHDWmdqhJswLkQ5oMNojgYDblXDuRgFJRHuFSawM,3085
42
+ datacontract/export/exporter_factory.py,sha256=UvP3_U7xj-GEjaifi__Jri6eYKx9SFXtmSrnkSbWuP0,6318
43
+ datacontract/export/go_converter.py,sha256=Ttvbfu3YU-3GBwRD6nwCsFyZuc_hiIvJD-Jg2sT5WLw,3331
44
+ datacontract/export/great_expectations_converter.py,sha256=Wx0mESRy4xAf8y7HjESsGsQaaei8k9xOVu3RbC6BlQM,12257
45
+ datacontract/export/html_exporter.py,sha256=EyTMj25_Df3irZiYw1hxVZeLYWp6YSG6z3IuFUviP14,3066
46
+ datacontract/export/iceberg_converter.py,sha256=ArcQ_Y3z_W4_kGDU_8jPRx2-pHpP3Nhx1zYoETOL3c4,6804
47
+ datacontract/export/jsonschema_converter.py,sha256=2MT82MurcQQbrVDRj1kFsxnmFd9scNSfYI1upQSecl4,5631
48
+ datacontract/export/markdown_converter.py,sha256=J6QEGuopR9AUyEhux1GpjmJaQa1iihsbNMAmGRQ63BQ,10430
49
+ datacontract/export/mermaid_exporter.py,sha256=Hg2yc5DYDTEZ7etoIhB1LU6rob_sGlouDtkPxUtf6kQ,4008
50
+ datacontract/export/odcs_v3_exporter.py,sha256=BctUnBG9E9seo-pvgBCXB6wkokmjpF7JUJmr1YXqqOo,14055
51
+ datacontract/export/pandas_type_converter.py,sha256=464pQ3JQKFQa1TO0HBNcEoZvQye_yUbY6jQtiBaphSc,1117
52
+ datacontract/export/protobuf_converter.py,sha256=DHLl8BW26xqltBsd7Qhz0RhTl9YZQKCbkmjNpECgubg,7928
53
+ datacontract/export/pydantic_converter.py,sha256=1Lt9F8i6zyQYb44MyQtsXwCWWXYxZ47SmzArr_uPqsU,5579
54
+ datacontract/export/rdf_converter.py,sha256=zY2BZrRxM0J6C2cgf5zA8c7FxDRImFjZUrJ4ksmvSTw,6435
55
+ datacontract/export/sodacl_converter.py,sha256=75vQ2TnoLfjiDtWT2x8opumvotXVRs1YaIu1NLYz05M,1473
56
+ datacontract/export/spark_converter.py,sha256=aol9ygEq29mjrZNiaK3Vdm8kEZhCgFFphuFiFDX-pOE,7953
57
+ datacontract/export/sql_converter.py,sha256=vyLbDqzt_J3LRXpPv2W2HqUIyAtQx_S-jviBiSxh14A,5087
58
+ datacontract/export/sql_type_converter.py,sha256=TOuuSn8uvTECPp3htSbYRC1Iwn-P7HW5gS8Ex24WF-4,17117
59
+ datacontract/export/sqlalchemy_converter.py,sha256=0DMncvA811lTtd5q4ZORREQ9YH1vQm1lJeqMWsFvloE,6463
60
+ datacontract/export/terraform_converter.py,sha256=ExFoEvErVk-gBnWJiqC38SxDUmUEydpACWc917l5RyM,2163
61
+ datacontract/imports/avro_importer.py,sha256=isfAnMq9bk-Yo5zSyTnqMegu7JIujn_sTGSTOYAc8-0,11847
62
+ datacontract/imports/bigquery_importer.py,sha256=7TcP9FDsIas5LwJZ-HrOPXZ-NuR056sxLfDDh3vjo8E,8419
63
+ datacontract/imports/csv_importer.py,sha256=mBsmyTvfB8q64Z3NYqv4zTDUOvoXG896hZvp3oLt5YM,5330
64
+ datacontract/imports/dbml_importer.py,sha256=o0IOgvXN34lU1FICDHm_QUTv0DKsgwbHPHUDxQhIapE,3872
65
+ datacontract/imports/dbt_importer.py,sha256=hQwqD9vbvwLLc6Yj3tQbar5ldI0pV-ynSiz7CZZ0JCc,8290
66
+ datacontract/imports/excel_importer.py,sha256=dFPgbtaG8KMcYe1pcRiXN4kWepbb8J-ji3q1_Or7SMg,46437
67
+ datacontract/imports/glue_importer.py,sha256=fiJPkvfwOCsaKKCGW19-JM5CCGXZ2mkNrVtUzp2iw6g,8370
68
+ datacontract/imports/iceberg_importer.py,sha256=vadGJVqQKgG-j8swUytZALFB8QjbGRqZPCcPcCy0vco,5923
69
+ datacontract/imports/importer.py,sha256=NRhR_9AWPWDNq2ac_DVUHGoJuvkVpwwaao8nDfJG_l0,1257
70
+ datacontract/imports/importer_factory.py,sha256=RS7uwkkT7rIKGeMKgPmZhE3GVC9IfZxZhm8XN0ooa3U,4124
71
+ datacontract/imports/json_importer.py,sha256=JeGbqAC_wAO0u8HeMA5H-KJBfs6gpp1oGIpxt6nxSZI,12641
72
+ datacontract/imports/jsonschema_importer.py,sha256=67H__XLugV4vguHrIqzW02dtx27zYTWnOms4D1ma3bk,4961
73
+ datacontract/imports/odcs_importer.py,sha256=ZP2u3kJsgULANTbbqkP3joOlU9cUneZOPy6Ak3oTMgs,2140
74
+ datacontract/imports/odcs_v3_importer.py,sha256=VbcMfijDKbKgeVCHq2g3FgE1lYMPrclf5-HWNszlKFc,21144
75
+ datacontract/imports/parquet_importer.py,sha256=W_0_16mX4stwDUt4GM2L7dnGmTpAySab5k13-OlTCCc,3095
76
+ datacontract/imports/protobuf_importer.py,sha256=rlUIskv9PNi5rFQ4Hobt9zlnKpahGsb4dy5G5UJoVAw,10840
77
+ datacontract/imports/spark_importer.py,sha256=OxX9hJhi8e1o1pZGOKh5zWsK96SX13r0WV04kKDD61M,8964
78
+ datacontract/imports/sql_importer.py,sha256=AdbBe7RrOEDMwdDt4huF5XmOV2EDpOP-k_m8kFQRlJg,10130
79
+ datacontract/imports/unity_importer.py,sha256=ZoWVMPffYNAXxPa0E8d6gRBtx3l-KSx0fPqnQx81DX0,9067
80
+ datacontract/init/init_template.py,sha256=sLCxvXHqoeW-Qes9W8GSVPfDmmu7pfnVOm-puI1-wsQ,721
81
+ datacontract/integration/entropy_data.py,sha256=tJVGbixateg_k55iEuI0_LlpKKDN-Ts84JaTRQ2epOc,4284
82
+ datacontract/lint/files.py,sha256=tg0vq_w4LQsEr_8A5qr4hUJmHeGalUpsXJXC1t-OGC0,471
83
+ datacontract/lint/resolve.py,sha256=rqO-hX7zOjWO32LkkZsT8FhiUXX_yFTvS1MVuvlH0Qc,15339
84
+ datacontract/lint/resources.py,sha256=nfeZmORh1aP7EKpMKCmfbS04Te8pQ0nz64vJVkHOq3c,647
85
+ datacontract/lint/schema.py,sha256=wijp3Ix7WNqA2gnIQ6_IxbjB6fe35nYvMNM16dtAEA4,2220
86
+ datacontract/lint/urls.py,sha256=MkGirWUeUycCf3MKtV25eYuPQlLqBPFNWJiMgL65b74,3338
87
+ datacontract/model/exceptions.py,sha256=5BMuEH2qWuckNP4FTfpUEeEu6rjgGcLOD0GQugKRQ1U,1242
88
+ datacontract/model/odcs.py,sha256=Ku-n2xLC0_5EX7KxxLWrQ5ei5kugQiJy7AChKMmRWTc,782
89
+ datacontract/model/run.py,sha256=4UdEUaJl5RxEpN9S3swSu1vGJUVyNhOpRkdfbBZhh90,3146
90
+ datacontract/model/data_contract_specification/__init__.py,sha256=lO7ywraknlDwJNUaSd2B9FWFsWhE8v5S-kob_shW_lg,47
91
+ datacontract/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
+ datacontract/output/junit_test_results.py,sha256=ZjevRMTxNSiR0HMr3bEvqv4olozPw2zEutbuLloInww,4822
93
+ datacontract/output/output_format.py,sha256=_ZokDBo7-HXBs6czUv7kLLf9cYft_q5QaKzthsVnc58,212
94
+ datacontract/output/test_results_writer.py,sha256=PWNLs3R_LQMH4xp5WDxLkQgY3xvj8Eyzw1jnfgkQxlc,2713
95
+ datacontract/schemas/datacontract-1.1.0.init.yaml,sha256=ij_-ZEJP4A7ekeJfoqGpRbiCys7_YjkClNluVVo4C6E,1828
96
+ datacontract/schemas/datacontract-1.1.0.schema.json,sha256=3Bu2rxEjkF6dNLcqi1GF4KoXBnEIopaJ87Qb8S4zUvg,62872
97
+ datacontract/schemas/datacontract-1.2.0.init.yaml,sha256=ij_-ZEJP4A7ekeJfoqGpRbiCys7_YjkClNluVVo4C6E,1828
98
+ datacontract/schemas/datacontract-1.2.0.schema.json,sha256=sk7oL06cug9-WozCrLH8v8MuR3a8MaV1Ztkm1P-7UFk,64226
99
+ datacontract/schemas/datacontract-1.2.1.init.yaml,sha256=ij_-ZEJP4A7ekeJfoqGpRbiCys7_YjkClNluVVo4C6E,1828
100
+ datacontract/schemas/datacontract-1.2.1.schema.json,sha256=Ha6F8i2jaL3BKOV5kjWgaxzykAiaSLqjIq-OEOojnx4,65233
101
+ datacontract/schemas/odcs-3.0.1.schema.json,sha256=bRZsSXA0fV0EmV_8f1K68PlXu1m4K7JcuHpLnY3ESwQ,72933
102
+ datacontract/schemas/odcs-3.0.2.schema.json,sha256=_J13Tqc9E7RzpSho645meE86AxeU0dIt2U12-MnAfHk,69968
103
+ datacontract/schemas/odcs-3.1.0.schema.json,sha256=2impzli4wGeGVxsWNSRCfJc6hRtPaRzxKR89eq3HSYU,89358
104
+ datacontract/templates/datacontract.html,sha256=dksPEnY3c66jaaVS5r5vWfG6LzyXPjA4nO_yLUirJWg,17394
105
+ datacontract/templates/datacontract_odcs.html,sha256=9Lyat37E3bzHTucdVJeZnTfEdX5vKlHSciCPscKrqtQ,32713
106
+ datacontract/templates/index.html,sha256=EY2LYSTFCwMMcezsDbYsJwM5A7As7oOEiqTBpK_MXe8,12683
107
+ datacontract/templates/partials/datacontract_information.html,sha256=7ZBxgEgi2XndKBypeOpe03oCSRPOujC6NVlN7zexGNM,6221
108
+ datacontract/templates/partials/datacontract_servicelevels.html,sha256=ed3QgB11B0Qq2h_NwaroGZ4pQMBPEhfeQaoS-qEipqY,11401
109
+ datacontract/templates/partials/datacontract_terms.html,sha256=1cnJcOTpxwot2BCuZmkLF_SPfiVloLs3c8mj9WfE4sc,1865
110
+ datacontract/templates/partials/definition.html,sha256=gZEmNvwNGGxA_Fnzx_0L6tXlAMk_EAPWr5ziRIThb_o,1005
111
+ datacontract/templates/partials/example.html,sha256=F1dWbHDIXQScgfs4OVgqM1lR4uV4xX5j6suasXHNM88,1204
112
+ datacontract/templates/partials/model_field.html,sha256=2YBF95ypNCPFYuYKoeilRnDG-H_FuW4JK1znkCaYCac,7625
113
+ datacontract/templates/partials/quality.html,sha256=ynEDWRn8I90Uje-xhGYgFcfwOgKI1R-CDki-EvTsauQ,1785
114
+ datacontract/templates/partials/server.html,sha256=dHFJtonMjhiUHtT69RUgTpkoRwmNdTRzkCdH0LtGg_4,6279
115
+ datacontract/templates/style/output.css,sha256=ioIo1f96VW7LHhDifj6QI8QbRChJl-LlQ59EwM8MEmA,28692
116
+ datacontract_cli-0.10.40.dist-info/licenses/LICENSE,sha256=0hcS8X51AL0UvEsx1ZM6WQcxiy9d0j5iOfzdPYM6ONU,2205
117
+ datacontract_cli-0.10.40.dist-info/METADATA,sha256=sCIdW2fPGpyEPndnsHQm6f8z2VxSdEfOQqkSBEWfsUE,117363
118
+ datacontract_cli-0.10.40.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
119
+ datacontract_cli-0.10.40.dist-info/entry_points.txt,sha256=D3Eqy4q_Z6bHauGd4ppIyQglwbrm1AJnLau4Ppbw9Is,54
120
+ datacontract_cli-0.10.40.dist-info/top_level.txt,sha256=VIRjd8EIUrBYWjEXJJjtdUgc0UAJdPZjmLiOR8BRBYM,13
121
+ datacontract_cli-0.10.40.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 innoQ Deutschland GmbH
3
+ Copyright (c) 2025 Entropy Data GmbH
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,36 +0,0 @@
1
- # https://duckdb.org/docs/data/csv/overview.html
2
- # ['SQLNULL', 'BOOLEAN', 'BIGINT', 'DOUBLE', 'TIME', 'DATE', 'TIMESTAMP', 'VARCHAR']
3
- def convert_to_duckdb_csv_type(field) -> None | str:
4
- type = field.type
5
- if type is None:
6
- return "VARCHAR"
7
- if type.lower() in ["string", "varchar", "text"]:
8
- return "VARCHAR"
9
- if type.lower() in ["timestamp", "timestamp_tz"]:
10
- return "TIMESTAMP"
11
- if type.lower() in ["timestamp_ntz"]:
12
- return "TIMESTAMP"
13
- if type.lower() in ["date"]:
14
- return "DATE"
15
- if type.lower() in ["time"]:
16
- return "TIME"
17
- if type.lower() in ["number", "decimal", "numeric"]:
18
- # precision and scale not supported by data contract
19
- return "VARCHAR"
20
- if type.lower() in ["float", "double"]:
21
- return "DOUBLE"
22
- if type.lower() in ["integer", "int", "long", "bigint"]:
23
- return "BIGINT"
24
- if type.lower() in ["boolean"]:
25
- return "BOOLEAN"
26
- if type.lower() in ["object", "record", "struct"]:
27
- # not supported in CSV
28
- return "VARCHAR"
29
- if type.lower() in ["bytes"]:
30
- # not supported in CSV
31
- return "VARCHAR"
32
- if type.lower() in ["array"]:
33
- return "VARCHAR"
34
- if type.lower() in ["null"]:
35
- return "SQLNULL"
36
- return "VARCHAR"
@@ -1,72 +0,0 @@
1
- import os
2
-
3
- import requests
4
-
5
- from datacontract.model.run import Run
6
-
7
-
8
- def publish_test_results_to_datamesh_manager(run: Run, publish_url: str, ssl_verification: bool):
9
- try:
10
- if publish_url is None:
11
- # this url supports Data Mesh Manager and Data Contract Manager
12
- url = "https://api.datamesh-manager.com/api/test-results"
13
- else:
14
- url = publish_url
15
-
16
- api_key = os.getenv("DATAMESH_MANAGER_API_KEY")
17
- if api_key is None:
18
- api_key = os.getenv("DATACONTRACT_MANAGER_API_KEY")
19
- if api_key is None:
20
- raise Exception(
21
- "Cannot publish run results, as DATAMESH_MANAGER_API_KEY nor DATACONTRACT_MANAGER_API_KEY are not set"
22
- )
23
-
24
- if run.dataContractId is None:
25
- raise Exception("Cannot publish run results for unknown data contract ID")
26
-
27
- headers = {"Content-Type": "application/json", "x-api-key": api_key}
28
- request_body = run.model_dump_json()
29
- # print("Request Body:", request_body)
30
- response = requests.post(
31
- url,
32
- data=request_body,
33
- headers=headers,
34
- verify=ssl_verification,
35
- )
36
- # print("Status Code:", response.status_code)
37
- # print("Response Body:", response.text)
38
- if response.status_code != 200:
39
- run.log_error(f"Error publishing test results to Data Mesh Manager: {response.text}")
40
- return
41
- run.log_info(f"Published test results to {url}")
42
- except Exception as e:
43
- run.log_error(f"Failed publishing test results. Error: {str(e)}")
44
-
45
-
46
- def publish_data_contract_to_datamesh_manager(data_contract_dict: dict, ssl_verification: bool):
47
- try:
48
- api_key = os.getenv("DATAMESH_MANAGER_API_KEY")
49
- host = "https://api.datamesh-manager.com"
50
- if os.getenv("DATAMESH_MANAGER_HOST") is not None:
51
- host = os.getenv("DATAMESH_MANAGER_HOST")
52
- if api_key is None:
53
- api_key = os.getenv("DATACONTRACT_MANAGER_API_KEY")
54
- if api_key is None:
55
- raise Exception(
56
- "Cannot publish data contract, as neither DATAMESH_MANAGER_API_KEY nor DATACONTRACT_MANAGER_API_KEY is set"
57
- )
58
- headers = {"Content-Type": "application/json", "x-api-key": api_key}
59
- id = data_contract_dict["id"]
60
- url = f"{host}/api/datacontracts/{id}"
61
- response = requests.put(
62
- url=url,
63
- json=data_contract_dict,
64
- headers=headers,
65
- verify=ssl_verification,
66
- )
67
- if response.status_code != 200:
68
- print(f"Error publishing data contract to Data Mesh Manager: {response.text}")
69
- exit(1)
70
- print(f"Published data contract to {url}")
71
- except Exception as e:
72
- print(f"Failed publishing data contract. Error: {str(e)}")
datacontract/lint/lint.py DELETED
@@ -1,142 +0,0 @@
1
- import abc
2
- from dataclasses import dataclass, field
3
- from enum import Enum
4
- from typing import Any, Sequence, cast
5
-
6
- from datacontract.model.run import Check
7
-
8
- from ..model.data_contract_specification import DataContractSpecification
9
-
10
- """This module contains linter definitions for linting a data contract.
11
-
12
- Lints are quality checks that can succeed, fail, or warn. They are
13
- distinct from checks such as "valid yaml" or "file not found", which
14
- will cause the processing of the data contract to stop. Lints can be
15
- ignored, and are high-level requirements on the format of a data
16
- contract."""
17
-
18
-
19
- class LintSeverity(Enum):
20
- """The severity of a lint message. Generally, lint messages should be
21
- emitted with a severity of ERROR. WARNING should be used when the linter
22
- cannot determine a lint result, for example, when an unsupported model
23
- type is used.
24
- """
25
-
26
- ERROR = 2
27
- WARNING = 1
28
-
29
-
30
- @dataclass
31
- class LinterMessage:
32
- """A single linter message with attached severity and optional "model" that
33
- caused the message.
34
-
35
- Attributes:
36
- outcome: The outcome of the linting, either ERROR or WARNING. Linting outcomes with level WARNING are discarded for now.
37
- message: A message describing the error or warning in more detail.
38
- model: The model that caused the lint to fail. Is optional.
39
-
40
- """
41
-
42
- outcome: LintSeverity
43
- message: str
44
- model: Any = None
45
-
46
- @classmethod
47
- def error(cls, message: str, model=None):
48
- return LinterMessage(LintSeverity.ERROR, message, model)
49
-
50
- @classmethod
51
- def warning(cls, message: str, model=None):
52
- return LinterMessage(LintSeverity.WARNING, message, model)
53
-
54
-
55
- @dataclass
56
- class LinterResult:
57
- """Result of linting a contract. Contains multiple LinterResults from
58
- the same linter or lint phase.
59
-
60
- Attributes:
61
- linter: The linter that produced these results
62
- results: A list of linting results. Multiple identical linting
63
- results can be present in the list. An empty list means that
64
- the linter ran without producing warnings or errors.
65
- """
66
-
67
- results: Sequence[LinterMessage] = field(default_factory=list)
68
-
69
- @classmethod
70
- def erroneous(cls, message, model=None):
71
- return cls([LinterMessage.error(message, model)])
72
-
73
- @classmethod
74
- def cautious(cls, message, model=None):
75
- return cls([LinterMessage.warning(message, model)])
76
-
77
- def with_warning(self, message, model=None):
78
- result = LinterMessage.warning(message, model)
79
- return LinterResult(cast(list[LinterMessage], self.results) + [result])
80
-
81
- def with_error(self, message, model=None):
82
- result = LinterMessage.error(message, model)
83
- return LinterResult(cast(list[LinterMessage], self.results) + [result])
84
-
85
- def has_errors(self) -> bool:
86
- return any(map(lambda result: result.outcome == LintSeverity.ERROR, self.results))
87
-
88
- def has_warnings(self) -> bool:
89
- return any(map(lambda result: result.outcome == LintSeverity.WARNING, self.results))
90
-
91
- def error_results(self) -> Sequence[LinterMessage]:
92
- return [result for result in self.results if result.outcome == LintSeverity.ERROR]
93
-
94
- def warning_results(self) -> Sequence[LinterMessage]:
95
- return [result for result in self.results if result.outcome == LintSeverity.WARNING]
96
-
97
- def no_errors_or_warnings(self) -> bool:
98
- return len(self.results) == 0
99
-
100
- def combine(self, other: "LinterResult") -> "LinterResult":
101
- return LinterResult(cast(list[Any], self.results) + cast(list[Any], other.results))
102
-
103
-
104
- class Linter(abc.ABC):
105
- @property
106
- @abc.abstractmethod
107
- def name(self) -> str:
108
- """Human-readable name of the linter."""
109
- pass
110
-
111
- @property
112
- @abc.abstractmethod
113
- def id(self) -> str:
114
- """A linter ID for configuration (i.e. enabling and disabling)."""
115
- pass
116
-
117
- @abc.abstractmethod
118
- def lint_implementation(self, contract: DataContractSpecification) -> LinterResult:
119
- pass
120
-
121
- def lint(self, contract: DataContractSpecification) -> list[Check]:
122
- """Call with a data contract to get a list of check results from the linter."""
123
- result = self.lint_implementation(contract)
124
- checks = []
125
- if not result.error_results():
126
- checks.append(Check(type="lint", name=f"Linter '{self.name}'", result="passed", engine="datacontract"))
127
- else:
128
- # All linter messages are treated as warnings. Severity is
129
- # currently ignored, but could be used in filtering in the future
130
- # Linter messages with level WARNING are currently ignored, but might
131
- # be logged or printed in the future.
132
- for lint_error in result.error_results():
133
- checks.append(
134
- Check(
135
- type="lint",
136
- name=f"Linter '{self.name}'",
137
- result="warning",
138
- engine="datacontract",
139
- reason=lint_error.message,
140
- )
141
- )
142
- return checks
@@ -1,35 +0,0 @@
1
- from datacontract.model.data_contract_specification import DataContractSpecification
2
-
3
- from ..lint import Linter, LinterResult
4
-
5
-
6
- class DescriptionLinter(Linter):
7
- """Check for a description on contracts, models, model fields, definitions and examples."""
8
-
9
- @property
10
- def name(self) -> str:
11
- return "Objects have descriptions"
12
-
13
- @property
14
- def id(self) -> str:
15
- return "description"
16
-
17
- def lint_implementation(self, contract: DataContractSpecification) -> LinterResult:
18
- result = LinterResult()
19
- if not contract.info or not contract.info.description:
20
- result = result.with_error("Contract has empty description.")
21
- for model_name, model in contract.models.items():
22
- if not model.description:
23
- result = result.with_error(f"Model '{model_name}' has empty description.")
24
- for field_name, field in model.fields.items():
25
- if not field.description:
26
- result = result.with_error(
27
- f"Field '{field_name}' in model '{model_name}'" f" has empty description."
28
- )
29
- for definition_name, definition in contract.definitions.items():
30
- if not definition.description:
31
- result = result.with_error(f"Definition '{definition_name}' has empty description.")
32
- for index, example in enumerate(contract.examples):
33
- if not example.description:
34
- result = result.with_error(f"Example {index + 1} has empty description.")
35
- return result
@@ -1,34 +0,0 @@
1
- import re
2
-
3
- from datacontract.model.data_contract_specification import DataContractSpecification
4
-
5
- from ..lint import Linter, LinterResult
6
-
7
-
8
- class FieldPatternLinter(Linter):
9
- """Checks that all patterns defined for fields are correct Python regex
10
- syntax.
11
-
12
- """
13
-
14
- @property
15
- def name(self):
16
- return "Field pattern is correct regex"
17
-
18
- @property
19
- def id(self) -> str:
20
- return "field-pattern"
21
-
22
- def lint_implementation(self, contract: DataContractSpecification) -> LinterResult:
23
- result = LinterResult()
24
- for model_name, model in contract.models.items():
25
- for field_name, field in model.fields.items():
26
- if field.pattern:
27
- try:
28
- re.compile(field.pattern)
29
- except re.error as e:
30
- result = result.with_error(
31
- f"Failed to compile pattern regex '{field.pattern}' for "
32
- f"field '{field_name}' in model '{model_name}': {e.msg}"
33
- )
34
- return result
@@ -1,48 +0,0 @@
1
- from datacontract.model.data_contract_specification import DataContractSpecification
2
-
3
- from ..lint import Linter, LinterResult
4
-
5
-
6
- class FieldReferenceLinter(Linter):
7
- """Checks that all references definitions in fields refer to existing
8
- fields.
9
-
10
- """
11
-
12
- @property
13
- def name(self):
14
- return "Field references existing field"
15
-
16
- @property
17
- def id(self) -> str:
18
- return "field-reference"
19
-
20
- def lint_implementation(self, contract: DataContractSpecification) -> LinterResult:
21
- result = LinterResult()
22
- for model_name, model in contract.models.items():
23
- for field_name, field in model.fields.items():
24
- if field.references:
25
- reference_hierarchy = field.references.split(".")
26
- if len(reference_hierarchy) != 2:
27
- result = result.with_error(
28
- f"Field '{field_name}' in model '{model_name}'"
29
- f" references must follow the model.field syntax and refer to a field in a model in this data contract."
30
- )
31
- continue
32
- ref_model = reference_hierarchy[0]
33
- ref_field = reference_hierarchy[1]
34
-
35
- if ref_model not in contract.models:
36
- result = result.with_error(
37
- f"Field '{field_name}' in model '{model_name}'"
38
- f" references non-existing model '{ref_model}'."
39
- )
40
- else:
41
- ref_model_obj = contract.models[ref_model]
42
- if ref_field not in ref_model_obj.fields:
43
- result = result.with_error(
44
- f"Field '{field_name}' in model '{model_name}'"
45
- f" references non-existing field '{ref_field}'"
46
- f" in model '{ref_model}'."
47
- )
48
- return result
@@ -1,55 +0,0 @@
1
- import re
2
-
3
- from datacontract.model.data_contract_specification import DataContractSpecification
4
-
5
- from ..lint import Linter, LinterResult
6
-
7
-
8
- class NoticePeriodLinter(Linter):
9
- @property
10
- def name(self) -> str:
11
- return "noticePeriod in ISO8601 format"
12
-
13
- @property
14
- def id(self) -> str:
15
- return "notice-period"
16
-
17
- # Regex matching the "simple" ISO8601 duration format
18
- simple = re.compile(
19
- r"""P # Introduces period
20
- (:?[0-9\.,]+Y)? # Number of years
21
- (:?[0-9\.,]+M)? # Number of months
22
- (:?[0-9\.,]+W)? # Number of weeks
23
- (:?[0-9\.,]+D)? # Number of days
24
- (:? # Time part (optional)
25
- T # Always starts with T
26
- (:?[0-9\.,]+H)? # Number of hours
27
- (:?[0-9\.,]+M)? # Number of minutes
28
- (:?[0-9\.,]+S)? # Number of seconds
29
- )?
30
- """,
31
- re.VERBOSE,
32
- )
33
- datetime_basic = re.compile(r"P\d{8}T\d{6}")
34
- datetime_extended = re.compile(r"P\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}")
35
-
36
- def lint_implementation(self, contract: DataContractSpecification) -> LinterResult:
37
- """Check whether the notice period is specified using ISO8601 duration syntax."""
38
- if not contract.terms:
39
- return LinterResult.cautious("No terms defined.")
40
- period = contract.terms.noticePeriod
41
- if not period:
42
- return LinterResult.cautious("No notice period defined.")
43
- if not period.startswith("P"):
44
- return LinterResult.erroneous(f"Notice period '{period}' is not a valid" "ISO8601 duration.")
45
- if period == "P":
46
- return LinterResult.erroneous(
47
- "Notice period 'P' is not a valid" "ISO8601 duration, requires at least one" "duration to be specified."
48
- )
49
- if (
50
- not self.simple.fullmatch(period)
51
- and not self.datetime_basic.fullmatch(period)
52
- and not self.datetime_extended.fullmatch(period)
53
- ):
54
- return LinterResult.erroneous(f"Notice period '{period}' is not a valid ISO8601 duration.")
55
- return LinterResult()
@@ -1,52 +0,0 @@
1
- import yaml
2
-
3
- from datacontract.model.data_contract_specification import DataContractSpecification, Model
4
-
5
- from ..lint import Linter, LinterResult
6
-
7
-
8
- class QualityUsesSchemaLinter(Linter):
9
- @property
10
- def name(self) -> str:
11
- return "Quality check(s) use model"
12
-
13
- @property
14
- def id(self) -> str:
15
- return "quality-schema"
16
-
17
- def lint_sodacl(self, check, models: dict[str, Model]) -> LinterResult:
18
- result = LinterResult()
19
- for sodacl_check in check.keys():
20
- table_name = sodacl_check[len("checks for ") :]
21
- if table_name not in models:
22
- result = result.with_error(f"Quality check on unknown model '{table_name}'")
23
- return result
24
-
25
- def lint_montecarlo(self, check, models: dict[str, Model]) -> LinterResult:
26
- return LinterResult().with_warning("Linting montecarlo checks is not currently implemented")
27
-
28
- def lint_great_expectations(self, check, models: dict[str, Model]) -> LinterResult:
29
- return LinterResult().with_warning("Linting great expectations checks is not currently implemented")
30
-
31
- def lint_implementation(self, contract: DataContractSpecification) -> LinterResult:
32
- result = LinterResult()
33
- models = contract.models
34
- check = contract.quality
35
- if not check:
36
- return LinterResult()
37
- if not check.specification:
38
- return LinterResult.cautious("Quality check without specification.")
39
- if isinstance(check.specification, str):
40
- check_specification = yaml.safe_load(check.specification)
41
- else:
42
- check_specification = check.specification
43
- match check.type:
44
- case "SodaCL":
45
- result = result.combine(self.lint_sodacl(check_specification, models))
46
- case "montecarlo":
47
- result = result.combine(self.lint_montecarlo(check_specification, models))
48
- case "great-expectations":
49
- result = result.combine(self.lint_great_expectations(check_specification, models))
50
- case _:
51
- result = result.with_warning("Can't lint quality check " f"with type '{check.type}'")
52
- return result