datacontract-cli 0.10.23__py3-none-any.whl → 0.10.37__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 (80) 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 +116 -10
  5. datacontract/data_contract.py +143 -65
  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 +22 -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/export/avro_converter.py +20 -3
  15. datacontract/export/bigquery_converter.py +1 -1
  16. datacontract/export/dbt_converter.py +36 -7
  17. datacontract/export/dqx_converter.py +126 -0
  18. datacontract/export/duckdb_type_converter.py +57 -0
  19. datacontract/export/excel_exporter.py +923 -0
  20. datacontract/export/exporter.py +3 -0
  21. datacontract/export/exporter_factory.py +17 -1
  22. datacontract/export/great_expectations_converter.py +55 -5
  23. datacontract/export/{html_export.py → html_exporter.py} +31 -20
  24. datacontract/export/markdown_converter.py +134 -5
  25. datacontract/export/mermaid_exporter.py +110 -0
  26. datacontract/export/odcs_v3_exporter.py +187 -145
  27. datacontract/export/protobuf_converter.py +163 -69
  28. datacontract/export/rdf_converter.py +2 -2
  29. datacontract/export/sodacl_converter.py +9 -1
  30. datacontract/export/spark_converter.py +31 -4
  31. datacontract/export/sql_converter.py +6 -2
  32. datacontract/export/sql_type_converter.py +20 -8
  33. datacontract/imports/avro_importer.py +63 -12
  34. datacontract/imports/csv_importer.py +111 -57
  35. datacontract/imports/excel_importer.py +1111 -0
  36. datacontract/imports/importer.py +16 -3
  37. datacontract/imports/importer_factory.py +17 -0
  38. datacontract/imports/json_importer.py +325 -0
  39. datacontract/imports/odcs_importer.py +2 -2
  40. datacontract/imports/odcs_v3_importer.py +351 -151
  41. datacontract/imports/protobuf_importer.py +264 -0
  42. datacontract/imports/spark_importer.py +117 -13
  43. datacontract/imports/sql_importer.py +32 -16
  44. datacontract/imports/unity_importer.py +84 -38
  45. datacontract/init/init_template.py +1 -1
  46. datacontract/integration/datamesh_manager.py +16 -2
  47. datacontract/lint/resolve.py +112 -23
  48. datacontract/lint/schema.py +24 -15
  49. datacontract/model/data_contract_specification/__init__.py +1 -0
  50. datacontract/model/odcs.py +13 -0
  51. datacontract/model/run.py +3 -0
  52. datacontract/output/junit_test_results.py +3 -3
  53. datacontract/schemas/datacontract-1.1.0.init.yaml +1 -1
  54. datacontract/schemas/datacontract-1.2.0.init.yaml +91 -0
  55. datacontract/schemas/datacontract-1.2.0.schema.json +2029 -0
  56. datacontract/schemas/datacontract-1.2.1.init.yaml +91 -0
  57. datacontract/schemas/datacontract-1.2.1.schema.json +2058 -0
  58. datacontract/schemas/odcs-3.0.2.schema.json +2382 -0
  59. datacontract/templates/datacontract.html +54 -3
  60. datacontract/templates/datacontract_odcs.html +685 -0
  61. datacontract/templates/index.html +5 -2
  62. datacontract/templates/partials/server.html +2 -0
  63. datacontract/templates/style/output.css +319 -145
  64. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/METADATA +656 -431
  65. datacontract_cli-0.10.37.dist-info/RECORD +119 -0
  66. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/WHEEL +1 -1
  67. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info/licenses}/LICENSE +1 -1
  68. datacontract/export/csv_type_converter.py +0 -36
  69. datacontract/lint/lint.py +0 -142
  70. datacontract/lint/linters/description_linter.py +0 -35
  71. datacontract/lint/linters/field_pattern_linter.py +0 -34
  72. datacontract/lint/linters/field_reference_linter.py +0 -48
  73. datacontract/lint/linters/notice_period_linter.py +0 -55
  74. datacontract/lint/linters/quality_schema_linter.py +0 -52
  75. datacontract/lint/linters/valid_constraints_linter.py +0 -100
  76. datacontract/model/data_contract_specification.py +0 -327
  77. datacontract_cli-0.10.23.dist-info/RECORD +0 -113
  78. /datacontract/{lint/linters → output}/__init__.py +0 -0
  79. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/entry_points.txt +0 -0
  80. {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,119 @@
1
+ datacontract/__init__.py,sha256=ThDdxDJsd7qNErLoh628nK5M7RzhJNYCmN-C6BAJFoo,405
2
+ datacontract/api.py,sha256=nFmrJOhC5AygY9YS1VXsbvKNtW92B8AF-lXdhuCvcPE,8578
3
+ datacontract/cli.py,sha256=ix1iwdo8bGfUW_tf1qiSoLhGBKCLcIgpVgn6diV9MB0,20742
4
+ datacontract/data_contract.py,sha256=24QE2ym5dfwTP6vJ0OmW37GNfGCCV6y4x4-J5Ouvfjk,13248
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=qc56ZNKyHIoSFgoXzBRioOhnhgsFSJ6L-nyBU7d0fW8,8902
19
+ datacontract/engines/soda/connections/athena.py,sha256=wjrJA9CHhl6FbSW0HulWcYlkT2_nY1s19Y2MFe4lbCU,3028
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/postgres.py,sha256=9GTF4Es3M5vb7ocSGqAxXmslvkS5CjsPQGIuo020CFc,626
25
+ datacontract/engines/soda/connections/snowflake.py,sha256=rfG2ysuqNM6TkvyqQKcGHFsTGJ6AROmud5VleUDRrb0,749
26
+ datacontract/engines/soda/connections/sqlserver.py,sha256=RzGLbCUdRyfmDcqtM_AB9WZ-Xk-XYX91nkXpVNpYbvc,1440
27
+ datacontract/engines/soda/connections/trino.py,sha256=JvKUP9aFg_n095oWE0-bGmfbETSWEOURGEZdQuG8txA,718
28
+ datacontract/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ datacontract/export/avro_converter.py,sha256=MnfeW2x-Eko9dK6_fpdQYWtEzLkFWXfKABAUSJqiDpo,5381
30
+ datacontract/export/avro_idl_converter.py,sha256=SGO7JfI9UGXLYFR5wMGNUH1qf6kt9lF6dUU9roVqnFo,9878
31
+ datacontract/export/bigquery_converter.py,sha256=9mm-XP3klu1C5J87L9EL5ZyMCJhLBwsixo3aAw9QmRI,4738
32
+ datacontract/export/custom_converter.py,sha256=xb8KbkRRgHmT4ewwC7XxtnKpe_ZMSJWBjYOaKjmO_KQ,1216
33
+ datacontract/export/data_caterer_converter.py,sha256=eSEuy3TbqUIG_lHYEBOydAgp_CJNoGArXrcJvh81wcw,5984
34
+ datacontract/export/dbml_converter.py,sha256=f_OZEFwRUyL-Kg2yn_G58I8iz1VfFrZh8Nbw3Wq0JDo,4777
35
+ datacontract/export/dbt_converter.py,sha256=58bub8n22dfL8w6bKdFe28BLF0e4PHbrxO_H3rZ9wfk,11840
36
+ datacontract/export/dcs_exporter.py,sha256=RALQ7bLAjak7EsoFFL2GFX2Oju7pnCDPCdRN_wo9wHM,210
37
+ datacontract/export/dqx_converter.py,sha256=5UevFPE8RdFIeu4CgeVnXMNDfWU7DhR34DW7O1aVIFs,4105
38
+ datacontract/export/duckdb_type_converter.py,sha256=hUAAbImhJUMJOXEG-UoOKQqYGrJM6UILpn2YjUuAUOw,2216
39
+ datacontract/export/excel_exporter.py,sha256=qDVcwO38aWPMTYyXo2qJd1HJLkmj_Izhi1hdVOQ8o_w,38424
40
+ datacontract/export/exporter.py,sha256=DfvMHDWmdqhJswLkQ5oMNojgYDblXDuRgFJRHuFSawM,3085
41
+ datacontract/export/exporter_factory.py,sha256=UvP3_U7xj-GEjaifi__Jri6eYKx9SFXtmSrnkSbWuP0,6318
42
+ datacontract/export/go_converter.py,sha256=Ttvbfu3YU-3GBwRD6nwCsFyZuc_hiIvJD-Jg2sT5WLw,3331
43
+ datacontract/export/great_expectations_converter.py,sha256=Wx0mESRy4xAf8y7HjESsGsQaaei8k9xOVu3RbC6BlQM,12257
44
+ datacontract/export/html_exporter.py,sha256=EyTMj25_Df3irZiYw1hxVZeLYWp6YSG6z3IuFUviP14,3066
45
+ datacontract/export/iceberg_converter.py,sha256=ArcQ_Y3z_W4_kGDU_8jPRx2-pHpP3Nhx1zYoETOL3c4,6804
46
+ datacontract/export/jsonschema_converter.py,sha256=2MT82MurcQQbrVDRj1kFsxnmFd9scNSfYI1upQSecl4,5631
47
+ datacontract/export/markdown_converter.py,sha256=J6QEGuopR9AUyEhux1GpjmJaQa1iihsbNMAmGRQ63BQ,10430
48
+ datacontract/export/mermaid_exporter.py,sha256=Hg2yc5DYDTEZ7etoIhB1LU6rob_sGlouDtkPxUtf6kQ,4008
49
+ datacontract/export/odcs_v3_exporter.py,sha256=b__AiPAnCUuFQE5DPHsvXBrMeEl1t_mJ1vzTx84TMlI,13931
50
+ datacontract/export/pandas_type_converter.py,sha256=464pQ3JQKFQa1TO0HBNcEoZvQye_yUbY6jQtiBaphSc,1117
51
+ datacontract/export/protobuf_converter.py,sha256=DHLl8BW26xqltBsd7Qhz0RhTl9YZQKCbkmjNpECgubg,7928
52
+ datacontract/export/pydantic_converter.py,sha256=1Lt9F8i6zyQYb44MyQtsXwCWWXYxZ47SmzArr_uPqsU,5579
53
+ datacontract/export/rdf_converter.py,sha256=zY2BZrRxM0J6C2cgf5zA8c7FxDRImFjZUrJ4ksmvSTw,6435
54
+ datacontract/export/sodacl_converter.py,sha256=75vQ2TnoLfjiDtWT2x8opumvotXVRs1YaIu1NLYz05M,1473
55
+ datacontract/export/spark_converter.py,sha256=aol9ygEq29mjrZNiaK3Vdm8kEZhCgFFphuFiFDX-pOE,7953
56
+ datacontract/export/sql_converter.py,sha256=vyLbDqzt_J3LRXpPv2W2HqUIyAtQx_S-jviBiSxh14A,5087
57
+ datacontract/export/sql_type_converter.py,sha256=eWHRHJNeg6oOT2uUPjmcVjEf6H_qXZvDhvSCk-_iBAM,13890
58
+ datacontract/export/sqlalchemy_converter.py,sha256=0DMncvA811lTtd5q4ZORREQ9YH1vQm1lJeqMWsFvloE,6463
59
+ datacontract/export/terraform_converter.py,sha256=ExFoEvErVk-gBnWJiqC38SxDUmUEydpACWc917l5RyM,2163
60
+ datacontract/imports/avro_importer.py,sha256=isfAnMq9bk-Yo5zSyTnqMegu7JIujn_sTGSTOYAc8-0,11847
61
+ datacontract/imports/bigquery_importer.py,sha256=7TcP9FDsIas5LwJZ-HrOPXZ-NuR056sxLfDDh3vjo8E,8419
62
+ datacontract/imports/csv_importer.py,sha256=mBsmyTvfB8q64Z3NYqv4zTDUOvoXG896hZvp3oLt5YM,5330
63
+ datacontract/imports/dbml_importer.py,sha256=o0IOgvXN34lU1FICDHm_QUTv0DKsgwbHPHUDxQhIapE,3872
64
+ datacontract/imports/dbt_importer.py,sha256=hQwqD9vbvwLLc6Yj3tQbar5ldI0pV-ynSiz7CZZ0JCc,8290
65
+ datacontract/imports/excel_importer.py,sha256=eBLc9VS9OYVFYFcHFHq9HYOStAPBDfVHwmgnBHjxOmc,46415
66
+ datacontract/imports/glue_importer.py,sha256=fiJPkvfwOCsaKKCGW19-JM5CCGXZ2mkNrVtUzp2iw6g,8370
67
+ datacontract/imports/iceberg_importer.py,sha256=vadGJVqQKgG-j8swUytZALFB8QjbGRqZPCcPcCy0vco,5923
68
+ datacontract/imports/importer.py,sha256=NRhR_9AWPWDNq2ac_DVUHGoJuvkVpwwaao8nDfJG_l0,1257
69
+ datacontract/imports/importer_factory.py,sha256=RS7uwkkT7rIKGeMKgPmZhE3GVC9IfZxZhm8XN0ooa3U,4124
70
+ datacontract/imports/json_importer.py,sha256=JeGbqAC_wAO0u8HeMA5H-KJBfs6gpp1oGIpxt6nxSZI,12641
71
+ datacontract/imports/jsonschema_importer.py,sha256=67H__XLugV4vguHrIqzW02dtx27zYTWnOms4D1ma3bk,4961
72
+ datacontract/imports/odcs_importer.py,sha256=ZP2u3kJsgULANTbbqkP3joOlU9cUneZOPy6Ak3oTMgs,2140
73
+ datacontract/imports/odcs_v3_importer.py,sha256=8mWFn4Ntf0jk0DKqmrp_DN7pKlSCO88Ol_UBWzHkY20,20467
74
+ datacontract/imports/parquet_importer.py,sha256=W_0_16mX4stwDUt4GM2L7dnGmTpAySab5k13-OlTCCc,3095
75
+ datacontract/imports/protobuf_importer.py,sha256=rlUIskv9PNi5rFQ4Hobt9zlnKpahGsb4dy5G5UJoVAw,10840
76
+ datacontract/imports/spark_importer.py,sha256=OxX9hJhi8e1o1pZGOKh5zWsK96SX13r0WV04kKDD61M,8964
77
+ datacontract/imports/sql_importer.py,sha256=AdbBe7RrOEDMwdDt4huF5XmOV2EDpOP-k_m8kFQRlJg,10130
78
+ datacontract/imports/unity_importer.py,sha256=ZoWVMPffYNAXxPa0E8d6gRBtx3l-KSx0fPqnQx81DX0,9067
79
+ datacontract/init/init_template.py,sha256=sLCxvXHqoeW-Qes9W8GSVPfDmmu7pfnVOm-puI1-wsQ,721
80
+ datacontract/integration/datamesh_manager.py,sha256=FT9eadzFz181lg54b49_c_x2caGJT7mR3drlZBSBJLo,3375
81
+ datacontract/lint/files.py,sha256=tg0vq_w4LQsEr_8A5qr4hUJmHeGalUpsXJXC1t-OGC0,471
82
+ datacontract/lint/resolve.py,sha256=TjCS0wX4OIkQsV1fXpgGwfnDRyBLrFwePyLsEVO8Qs0,15339
83
+ datacontract/lint/resources.py,sha256=nfeZmORh1aP7EKpMKCmfbS04Te8pQ0nz64vJVkHOq3c,647
84
+ datacontract/lint/schema.py,sha256=wijp3Ix7WNqA2gnIQ6_IxbjB6fe35nYvMNM16dtAEA4,2220
85
+ datacontract/lint/urls.py,sha256=giac0eAYa6hha8exleL3KsiPtiFlOq8l53axtAmCilw,2529
86
+ datacontract/model/exceptions.py,sha256=5BMuEH2qWuckNP4FTfpUEeEu6rjgGcLOD0GQugKRQ1U,1242
87
+ datacontract/model/odcs.py,sha256=Ku-n2xLC0_5EX7KxxLWrQ5ei5kugQiJy7AChKMmRWTc,782
88
+ datacontract/model/run.py,sha256=4UdEUaJl5RxEpN9S3swSu1vGJUVyNhOpRkdfbBZhh90,3146
89
+ datacontract/model/data_contract_specification/__init__.py,sha256=lO7ywraknlDwJNUaSd2B9FWFsWhE8v5S-kob_shW_lg,47
90
+ datacontract/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ datacontract/output/junit_test_results.py,sha256=ZjevRMTxNSiR0HMr3bEvqv4olozPw2zEutbuLloInww,4822
92
+ datacontract/output/output_format.py,sha256=_ZokDBo7-HXBs6czUv7kLLf9cYft_q5QaKzthsVnc58,212
93
+ datacontract/output/test_results_writer.py,sha256=PWNLs3R_LQMH4xp5WDxLkQgY3xvj8Eyzw1jnfgkQxlc,2713
94
+ datacontract/schemas/datacontract-1.1.0.init.yaml,sha256=ij_-ZEJP4A7ekeJfoqGpRbiCys7_YjkClNluVVo4C6E,1828
95
+ datacontract/schemas/datacontract-1.1.0.schema.json,sha256=3Bu2rxEjkF6dNLcqi1GF4KoXBnEIopaJ87Qb8S4zUvg,62872
96
+ datacontract/schemas/datacontract-1.2.0.init.yaml,sha256=ij_-ZEJP4A7ekeJfoqGpRbiCys7_YjkClNluVVo4C6E,1828
97
+ datacontract/schemas/datacontract-1.2.0.schema.json,sha256=sk7oL06cug9-WozCrLH8v8MuR3a8MaV1Ztkm1P-7UFk,64226
98
+ datacontract/schemas/datacontract-1.2.1.init.yaml,sha256=ij_-ZEJP4A7ekeJfoqGpRbiCys7_YjkClNluVVo4C6E,1828
99
+ datacontract/schemas/datacontract-1.2.1.schema.json,sha256=Ha6F8i2jaL3BKOV5kjWgaxzykAiaSLqjIq-OEOojnx4,65233
100
+ datacontract/schemas/odcs-3.0.1.schema.json,sha256=bRZsSXA0fV0EmV_8f1K68PlXu1m4K7JcuHpLnY3ESwQ,72933
101
+ datacontract/schemas/odcs-3.0.2.schema.json,sha256=_J13Tqc9E7RzpSho645meE86AxeU0dIt2U12-MnAfHk,69968
102
+ datacontract/templates/datacontract.html,sha256=dksPEnY3c66jaaVS5r5vWfG6LzyXPjA4nO_yLUirJWg,17394
103
+ datacontract/templates/datacontract_odcs.html,sha256=u4bpcgQVqwGmR0QjijJqecOClV2ZhpDvnNMAMzj4Ezc,32659
104
+ datacontract/templates/index.html,sha256=EY2LYSTFCwMMcezsDbYsJwM5A7As7oOEiqTBpK_MXe8,12683
105
+ datacontract/templates/partials/datacontract_information.html,sha256=7ZBxgEgi2XndKBypeOpe03oCSRPOujC6NVlN7zexGNM,6221
106
+ datacontract/templates/partials/datacontract_servicelevels.html,sha256=ed3QgB11B0Qq2h_NwaroGZ4pQMBPEhfeQaoS-qEipqY,11401
107
+ datacontract/templates/partials/datacontract_terms.html,sha256=1cnJcOTpxwot2BCuZmkLF_SPfiVloLs3c8mj9WfE4sc,1865
108
+ datacontract/templates/partials/definition.html,sha256=gZEmNvwNGGxA_Fnzx_0L6tXlAMk_EAPWr5ziRIThb_o,1005
109
+ datacontract/templates/partials/example.html,sha256=F1dWbHDIXQScgfs4OVgqM1lR4uV4xX5j6suasXHNM88,1204
110
+ datacontract/templates/partials/model_field.html,sha256=2YBF95ypNCPFYuYKoeilRnDG-H_FuW4JK1znkCaYCac,7625
111
+ datacontract/templates/partials/quality.html,sha256=ynEDWRn8I90Uje-xhGYgFcfwOgKI1R-CDki-EvTsauQ,1785
112
+ datacontract/templates/partials/server.html,sha256=dHFJtonMjhiUHtT69RUgTpkoRwmNdTRzkCdH0LtGg_4,6279
113
+ datacontract/templates/style/output.css,sha256=ioIo1f96VW7LHhDifj6QI8QbRChJl-LlQ59EwM8MEmA,28692
114
+ datacontract_cli-0.10.37.dist-info/licenses/LICENSE,sha256=0hcS8X51AL0UvEsx1ZM6WQcxiy9d0j5iOfzdPYM6ONU,2205
115
+ datacontract_cli-0.10.37.dist-info/METADATA,sha256=xG1Rilzh_eBYa-gBTG4b9AreKjV5-lcZ41sVqkHtHoc,115131
116
+ datacontract_cli-0.10.37.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
117
+ datacontract_cli-0.10.37.dist-info/entry_points.txt,sha256=D3Eqy4q_Z6bHauGd4ppIyQglwbrm1AJnLau4Ppbw9Is,54
118
+ datacontract_cli-0.10.37.dist-info/top_level.txt,sha256=VIRjd8EIUrBYWjEXJJjtdUgc0UAJdPZjmLiOR8BRBYM,13
119
+ datacontract_cli-0.10.37.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"
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
@@ -1,100 +0,0 @@
1
- from datacontract.model.data_contract_specification import DataContractSpecification, Field
2
-
3
- from ..lint import Linter, LinterResult
4
-
5
-
6
- class ValidFieldConstraintsLinter(Linter):
7
- """Check validity of field constraints.
8
-
9
- More precisely, check that only numeric constraints are specified on
10
- fields of numeric type and string constraints on fields of string type.
11
- Additionally, the linter checks that defined constraints make sense.
12
- Minimum values should not be greater than maximum values, exclusive and
13
- non-exclusive minimum and maximum should not be combined and string
14
- pattern and format should not be combined.
15
-
16
- """
17
-
18
- valid_types_for_constraint = {
19
- "pattern": set(["string", "text", "varchar"]),
20
- "format": set(["string", "text", "varchar"]),
21
- "minLength": set(["string", "text", "varchar"]),
22
- "maxLength": set(["string", "text", "varchar"]),
23
- "minimum": set(["int", "integer", "number", "decimal", "numeric", "long", "bigint", "float", "double"]),
24
- "exclusiveMinimum": set(
25
- ["int", "integer", "number", "decimal", "numeric", "long", "bigint", "float", "double"]
26
- ),
27
- "maximum": set(["int", "integer", "number", "decimal", "numeric", "long", "bigint", "float", "double"]),
28
- "exclusiveMaximum": set(
29
- ["int", "integer", "number", "decimal", "numeric", "long", "bigint", "float", "double"]
30
- ),
31
- }
32
-
33
- def check_minimum_maximum(self, field: Field, field_name: str, model_name: str) -> LinterResult:
34
- (min, max, xmin, xmax) = (field.minimum, field.maximum, field.exclusiveMinimum, field.exclusiveMaximum)
35
- match (
36
- "minimum" in field.model_fields_set,
37
- "maximum" in field.model_fields_set,
38
- "exclusiveMinimum" in field.model_fields_set,
39
- "exclusiveMaximum" in field.model_fields_set,
40
- ):
41
- case (True, True, _, _) if min > max:
42
- return LinterResult.erroneous(
43
- f"Minimum {min} is greater than maximum {max} on " f"field '{field_name}' in model '{model_name}'."
44
- )
45
- case (_, _, True, True) if xmin >= xmax:
46
- return LinterResult.erroneous(
47
- f"Exclusive minimum {xmin} is greater than exclusive"
48
- f" maximum {xmax} on field '{field_name}' in model '{model_name}'."
49
- )
50
- case (True, True, True, True):
51
- return LinterResult.erroneous(
52
- f"Both exclusive and non-exclusive minimum and maximum are "
53
- f"defined on field '{field_name}' in model '{model_name}'."
54
- )
55
- case (True, _, True, _):
56
- return LinterResult.erroneous(
57
- f"Both exclusive and non-exclusive minimum are "
58
- f"defined on field '{field_name}' in model '{model_name}'."
59
- )
60
- case (_, True, _, True):
61
- return LinterResult.erroneous(
62
- f"Both exclusive and non-exclusive maximum are "
63
- f"defined on field '{field_name}' in model '{model_name}'."
64
- )
65
- return LinterResult()
66
-
67
- def check_string_constraints(self, field: Field, field_name: str, model_name: str) -> LinterResult:
68
- result = LinterResult()
69
- if field.minLength and field.maxLength and field.minLength > field.maxLength:
70
- result = result.with_error(
71
- f"Minimum length is greater that maximum length on" f" field '{field_name}' in model '{model_name}'."
72
- )
73
- if field.pattern and field.format:
74
- result = result.with_error(
75
- f"Both a pattern and a format are defined for field" f" '{field_name}' in model '{model_name}'."
76
- )
77
- return result
78
-
79
- @property
80
- def name(self):
81
- return "Fields use valid constraints"
82
-
83
- @property
84
- def id(self):
85
- return "field-constraints"
86
-
87
- def lint_implementation(self, contract: DataContractSpecification) -> LinterResult:
88
- result = LinterResult()
89
- for model_name, model in contract.models.items():
90
- for field_name, field in model.fields.items():
91
- for _property, allowed_types in self.valid_types_for_constraint.items():
92
- if _property in field.model_fields_set and field.type not in allowed_types:
93
- result = result.with_error(
94
- f"Forbidden constraint '{_property}' defined on field "
95
- f"'{field_name}' in model '{model_name}'. Field type "
96
- f"is '{field.type}'."
97
- )
98
- result = result.combine(self.check_minimum_maximum(field, field_name, model_name))
99
- result = result.combine(self.check_string_constraints(field, field_name, model_name))
100
- return result