datacontract-cli 0.9.7__py3-none-any.whl → 0.9.9__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.

Potentially problematic release.


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

Files changed (62) hide show
  1. datacontract/breaking/breaking.py +48 -57
  2. datacontract/cli.py +100 -80
  3. datacontract/data_contract.py +178 -128
  4. datacontract/engines/datacontract/check_that_datacontract_contains_valid_servers_configuration.py +5 -1
  5. datacontract/engines/datacontract/check_that_datacontract_file_exists.py +9 -8
  6. datacontract/engines/datacontract/check_that_datacontract_str_is_valid.py +26 -22
  7. datacontract/engines/fastjsonschema/check_jsonschema.py +31 -25
  8. datacontract/engines/fastjsonschema/s3/s3_read_files.py +8 -6
  9. datacontract/engines/soda/check_soda_execute.py +58 -36
  10. datacontract/engines/soda/connections/bigquery.py +5 -3
  11. datacontract/engines/soda/connections/dask.py +0 -1
  12. datacontract/engines/soda/connections/databricks.py +2 -2
  13. datacontract/engines/soda/connections/duckdb.py +25 -8
  14. datacontract/engines/soda/connections/kafka.py +36 -17
  15. datacontract/engines/soda/connections/postgres.py +3 -3
  16. datacontract/engines/soda/connections/snowflake.py +4 -4
  17. datacontract/export/avro_converter.py +9 -11
  18. datacontract/export/avro_idl_converter.py +65 -42
  19. datacontract/export/csv_type_converter.py +36 -0
  20. datacontract/export/dbt_converter.py +43 -32
  21. datacontract/export/great_expectations_converter.py +141 -0
  22. datacontract/export/html_export.py +46 -0
  23. datacontract/export/jsonschema_converter.py +3 -1
  24. datacontract/export/odcs_converter.py +5 -7
  25. datacontract/export/protobuf_converter.py +12 -10
  26. datacontract/export/pydantic_converter.py +131 -0
  27. datacontract/export/rdf_converter.py +34 -11
  28. datacontract/export/sodacl_converter.py +118 -21
  29. datacontract/export/sql_converter.py +30 -8
  30. datacontract/export/sql_type_converter.py +44 -4
  31. datacontract/export/terraform_converter.py +4 -3
  32. datacontract/imports/avro_importer.py +65 -18
  33. datacontract/imports/sql_importer.py +0 -2
  34. datacontract/init/download_datacontract_file.py +2 -2
  35. datacontract/integration/publish_datamesh_manager.py +6 -12
  36. datacontract/integration/publish_opentelemetry.py +30 -16
  37. datacontract/lint/files.py +2 -2
  38. datacontract/lint/lint.py +26 -31
  39. datacontract/lint/linters/description_linter.py +12 -21
  40. datacontract/lint/linters/example_model_linter.py +28 -29
  41. datacontract/lint/linters/field_pattern_linter.py +8 -8
  42. datacontract/lint/linters/field_reference_linter.py +11 -10
  43. datacontract/lint/linters/notice_period_linter.py +18 -22
  44. datacontract/lint/linters/quality_schema_linter.py +16 -20
  45. datacontract/lint/linters/valid_constraints_linter.py +42 -37
  46. datacontract/lint/resolve.py +50 -14
  47. datacontract/lint/schema.py +2 -3
  48. datacontract/lint/urls.py +4 -5
  49. datacontract/model/breaking_change.py +2 -1
  50. datacontract/model/data_contract_specification.py +8 -7
  51. datacontract/model/exceptions.py +13 -2
  52. datacontract/model/run.py +3 -2
  53. datacontract/web.py +3 -7
  54. datacontract_cli-0.9.9.dist-info/METADATA +951 -0
  55. datacontract_cli-0.9.9.dist-info/RECORD +64 -0
  56. datacontract/lint/linters/primary_field_linter.py +0 -30
  57. datacontract_cli-0.9.7.dist-info/METADATA +0 -603
  58. datacontract_cli-0.9.7.dist-info/RECORD +0 -61
  59. {datacontract_cli-0.9.7.dist-info → datacontract_cli-0.9.9.dist-info}/LICENSE +0 -0
  60. {datacontract_cli-0.9.7.dist-info → datacontract_cli-0.9.9.dist-info}/WHEEL +0 -0
  61. {datacontract_cli-0.9.7.dist-info → datacontract_cli-0.9.9.dist-info}/entry_points.txt +0 -0
  62. {datacontract_cli-0.9.7.dist-info → datacontract_cli-0.9.9.dist-info}/top_level.txt +0 -0
@@ -4,62 +4,53 @@ import tempfile
4
4
  import typing
5
5
 
6
6
  import yaml
7
+ from pyspark.sql import SparkSession
7
8
 
8
- from datacontract.breaking.breaking import models_breaking_changes, quality_breaking_changes
9
- from datacontract.engines.datacontract.check_that_datacontract_contains_valid_servers_configuration import \
10
- check_that_datacontract_contains_valid_server_configuration
9
+ from datacontract.breaking.breaking import models_breaking_changes, \
10
+ quality_breaking_changes
11
+ from datacontract.engines.datacontract.check_that_datacontract_contains_valid_servers_configuration import (
12
+ check_that_datacontract_contains_valid_server_configuration,
13
+ )
11
14
  from datacontract.engines.fastjsonschema.check_jsonschema import \
12
15
  check_jsonschema
13
16
  from datacontract.engines.soda.check_soda_execute import check_soda_execute
14
- from datacontract.export.avro_converter import to_avro_schema, to_avro_schema_json
17
+ from datacontract.export.avro_converter import to_avro_schema_json
15
18
  from datacontract.export.avro_idl_converter import to_avro_idl
16
19
  from datacontract.export.dbt_converter import to_dbt_models_yaml, \
17
20
  to_dbt_sources_yaml, to_dbt_staging_sql
18
- from datacontract.export.jsonschema_converter import to_jsonschema, to_jsonschema_json
21
+ from datacontract.export.great_expectations_converter import \
22
+ to_great_expectations
23
+ from datacontract.export.html_export import to_html
24
+ from datacontract.export.jsonschema_converter import to_jsonschema_json
19
25
  from datacontract.export.odcs_converter import to_odcs_yaml
20
26
  from datacontract.export.protobuf_converter import to_protobuf
27
+ from datacontract.export.pydantic_converter import to_pydantic_model_str
21
28
  from datacontract.export.rdf_converter import to_rdf_n3
22
29
  from datacontract.export.sodacl_converter import to_sodacl_yaml
23
- from datacontract.imports.avro_importer import import_avro
24
30
  from datacontract.export.sql_converter import to_sql_ddl, to_sql_query
25
31
  from datacontract.export.terraform_converter import to_terraform
32
+ from datacontract.imports.avro_importer import import_avro
26
33
  from datacontract.imports.sql_importer import import_sql
27
34
  from datacontract.integration.publish_datamesh_manager import \
28
35
  publish_datamesh_manager
29
36
  from datacontract.integration.publish_opentelemetry import publish_opentelemetry
30
37
  from datacontract.lint import resolve
31
-
32
- from datacontract.model.breaking_change import BreakingChanges, BreakingChange, Severity
33
38
  from datacontract.lint.linters.description_linter import DescriptionLinter
34
39
  from datacontract.lint.linters.example_model_linter import ExampleModelLinter
35
- from datacontract.lint.linters.valid_constraints_linter import ValidFieldConstraintsLinter
36
40
  from datacontract.lint.linters.field_pattern_linter import FieldPatternLinter
37
- from datacontract.lint.linters.field_reference_linter import FieldReferenceLinter
41
+ from datacontract.lint.linters.field_reference_linter import \
42
+ FieldReferenceLinter
38
43
  from datacontract.lint.linters.notice_period_linter import NoticePeriodLinter
39
- from datacontract.lint.linters.primary_field_linter import PrimaryFieldUniqueRequired
40
- from datacontract.lint.linters.quality_schema_linter import QualityUsesSchemaLinter
44
+ from datacontract.lint.linters.quality_schema_linter import \
45
+ QualityUsesSchemaLinter
46
+ from datacontract.lint.linters.valid_constraints_linter import \
47
+ ValidFieldConstraintsLinter
48
+ from datacontract.model.breaking_change import BreakingChanges, BreakingChange, \
49
+ Severity
41
50
  from datacontract.model.data_contract_specification import \
42
51
  DataContractSpecification, Server
43
52
  from datacontract.model.exceptions import DataContractException
44
- from datacontract.model.run import \
45
- Run, Check
46
-
47
-
48
- def _determine_sql_server_type(data_contract, sql_server_type):
49
- if sql_server_type == "auto":
50
- if data_contract.servers is None or len(data_contract.servers) == 0:
51
- raise RuntimeError(f"Export with server_type='auto' requires servers in the data contract.")
52
-
53
- server_types = set([server.type for server in data_contract.servers.values()])
54
- if "snowflake" in server_types:
55
- return "snowflake"
56
- elif "postgres" in server_types:
57
- return "postgres"
58
- else:
59
- # default to snowflake dialect
60
- return "snowflake"
61
- else:
62
- return sql_server_type
53
+ from datacontract.model.run import Run, Check
63
54
 
64
55
 
65
56
  class DataContract:
@@ -73,7 +64,7 @@ class DataContract:
73
64
  examples: bool = False,
74
65
  publish_url: str = None,
75
66
  publish_to_opentelemetry: bool = False,
76
- spark: str = None,
67
+ spark: SparkSession = None,
77
68
  inline_definitions: bool = False,
78
69
  ):
79
70
  self._data_contract_file = data_contract_file
@@ -92,9 +83,8 @@ class DataContract:
92
83
  FieldPatternLinter(),
93
84
  FieldReferenceLinter(),
94
85
  NoticePeriodLinter(),
95
- PrimaryFieldUniqueRequired(),
96
86
  ValidFieldConstraintsLinter(),
97
- DescriptionLinter()
87
+ DescriptionLinter(),
98
88
  }
99
89
 
100
90
  @classmethod
@@ -104,60 +94,59 @@ class DataContract:
104
94
  def lint(self, enabled_linters: typing.Union[str, set[str]] = "all") -> Run:
105
95
  """Lint the data contract by deserializing the contract and checking the schema, as well as calling the configured linters.
106
96
 
107
- enabled_linters can be either "all" or "none", or a set of linter IDs. The "schema" linter is always enabled, even with enabled_linters="none".
108
- """
97
+ enabled_linters can be either "all" or "none", or a set of linter IDs. The "schema" linter is always enabled, even with enabled_linters="none".
98
+ """
109
99
  run = Run.create_run()
110
100
  try:
111
101
  run.log_info("Linting data contract")
112
- data_contract = resolve.resolve_data_contract(self._data_contract_file, self._data_contract_str,
113
- self._data_contract, self._schema_location,
114
- inline_definitions=True)
115
- run.checks.append(Check(
116
- type="lint",
117
- result="passed",
118
- name="Data contract is syntactically valid",
119
- engine="datacontract"
120
- ))
102
+ data_contract = resolve.resolve_data_contract(
103
+ self._data_contract_file,
104
+ self._data_contract_str,
105
+ self._data_contract,
106
+ self._schema_location,
107
+ inline_definitions=True,
108
+ )
109
+ run.checks.append(
110
+ Check(type="lint", result="passed", name="Data contract is syntactically valid", engine="datacontract")
111
+ )
121
112
  if enabled_linters == "none":
122
113
  linters_to_check = set()
123
114
  elif enabled_linters == "all":
124
115
  linters_to_check = self.all_linters
125
116
  elif isinstance(enabled_linters, set):
126
- linters_to_check = {linter for linter in self.all_linters
127
- if linter.id in enabled_linters}
117
+ linters_to_check = {linter for linter in self.all_linters if linter.id in enabled_linters}
128
118
  else:
129
119
  raise RuntimeError(f"Unknown argument enabled_linters={enabled_linters} for lint()")
130
120
  for linter in linters_to_check:
131
121
  try:
132
122
  run.checks.extend(linter.lint(data_contract))
133
123
  except Exception as e:
134
- run.checks.append(Check(
135
- type="general",
136
- result="error",
137
- name=f"Linter '{linter.name}'",
138
- reason=str(e),
139
- engine="datacontract",
140
- ))
124
+ run.checks.append(
125
+ Check(
126
+ type="general",
127
+ result="error",
128
+ name=f"Linter '{linter.name}'",
129
+ reason=str(e),
130
+ engine="datacontract",
131
+ )
132
+ )
141
133
  run.dataContractId = data_contract.id
142
134
  run.dataContractVersion = data_contract.info.version
143
135
  except DataContractException as e:
144
- run.checks.append(Check(
145
- type=e.type,
146
- result=e.result,
147
- name=e.name,
148
- reason=e.reason,
149
- engine=e.engine,
150
- details=""
151
- ))
136
+ run.checks.append(
137
+ Check(type=e.type, result=e.result, name=e.name, reason=e.reason, engine=e.engine, details="")
138
+ )
152
139
  run.log_error(str(e))
153
140
  except Exception as e:
154
- run.checks.append(Check(
155
- type="general",
156
- result="error",
157
- name="Check Data Contract",
158
- reason=str(e),
159
- engine="datacontract",
160
- ))
141
+ run.checks.append(
142
+ Check(
143
+ type="general",
144
+ result="error",
145
+ name="Check Data Contract",
146
+ reason=str(e),
147
+ engine="datacontract",
148
+ )
149
+ )
161
150
  run.log_error(str(e))
162
151
  run.finish()
163
152
  return run
@@ -165,9 +154,10 @@ class DataContract:
165
154
  def test(self) -> Run:
166
155
  run = Run.create_run()
167
156
  try:
168
- run.log_info(f"Testing data contract")
169
- data_contract = resolve.resolve_data_contract(self._data_contract_file, self._data_contract_str,
170
- self._data_contract, self._schema_location)
157
+ run.log_info("Testing data contract")
158
+ data_contract = resolve.resolve_data_contract(
159
+ self._data_contract_file, self._data_contract_str, self._data_contract, self._schema_location
160
+ )
171
161
 
172
162
  if data_contract.models is None or len(data_contract.models) == 0:
173
163
  raise DataContractException(
@@ -213,23 +203,20 @@ class DataContract:
213
203
  check_soda_execute(run, data_contract, server, self._spark, tmp_dir)
214
204
 
215
205
  except DataContractException as e:
216
- run.checks.append(Check(
217
- type=e.type,
218
- result=e.result,
219
- name=e.name,
220
- reason=e.reason,
221
- engine=e.engine,
222
- details=""
223
- ))
206
+ run.checks.append(
207
+ Check(type=e.type, result=e.result, name=e.name, reason=e.reason, engine=e.engine, details="")
208
+ )
224
209
  run.log_error(str(e))
225
210
  except Exception as e:
226
- run.checks.append(Check(
227
- type="general",
228
- result="error",
229
- name="Test Data Contract",
230
- reason=str(e),
231
- engine="datacontract",
232
- ))
211
+ run.checks.append(
212
+ Check(
213
+ type="general",
214
+ result="error",
215
+ name="Test Data Contract",
216
+ reason=str(e),
217
+ engine="datacontract",
218
+ )
219
+ )
233
220
  logging.exception("Exception occurred")
234
221
  run.log_error(str(e))
235
222
 
@@ -238,45 +225,44 @@ class DataContract:
238
225
  if self._publish_url is not None:
239
226
  try:
240
227
  publish_datamesh_manager(run, self._publish_url)
241
- except:
242
- logging.error("Failed to publish to datamesh manager")
228
+ except Exception:
229
+ run.log_error("Failed to publish to datamesh manager")
243
230
  if self._publish_to_opentelemetry:
244
231
  try:
245
232
  publish_opentelemetry(run)
246
- except:
247
- logging.error("Failed to publish to opentelemetry")
233
+ except Exception:
234
+ run.log_error("Failed to publish to opentelemetry")
248
235
 
249
236
  return run
250
237
 
251
- def breaking(self, other: 'DataContract') -> BreakingChanges:
252
- return self.changelog(
253
- other,
254
- include_severities=[Severity.ERROR, Severity.WARNING]
255
- )
238
+ def breaking(self, other: "DataContract") -> BreakingChanges:
239
+ return self.changelog(other, include_severities=[Severity.ERROR, Severity.WARNING])
256
240
 
257
241
  def changelog(
258
- self,
259
- other: 'DataContract',
260
- include_severities: [Severity] = (Severity.ERROR, Severity.WARNING, Severity.INFO)
242
+ self, other: "DataContract", include_severities: [Severity] = (Severity.ERROR, Severity.WARNING, Severity.INFO)
261
243
  ) -> BreakingChanges:
262
244
  old = self.get_data_contract_specification()
263
245
  new = other.get_data_contract_specification()
264
246
 
265
247
  breaking_changes = list[BreakingChange]()
266
248
 
267
- breaking_changes.extend(quality_breaking_changes(
268
- old_quality=old.quality,
269
- new_quality=new.quality,
270
- new_path=other._data_contract_file,
271
- include_severities=include_severities,
272
- ))
249
+ breaking_changes.extend(
250
+ quality_breaking_changes(
251
+ old_quality=old.quality,
252
+ new_quality=new.quality,
253
+ new_path=other._data_contract_file,
254
+ include_severities=include_severities,
255
+ )
256
+ )
273
257
 
274
- breaking_changes.extend(models_breaking_changes(
275
- old_models=old.models,
276
- new_models=new.models,
277
- new_path=other._data_contract_file,
278
- include_severities=include_severities,
279
- ))
258
+ breaking_changes.extend(
259
+ models_breaking_changes(
260
+ old_models=old.models,
261
+ new_models=new.models,
262
+ new_path=other._data_contract_file,
263
+ include_severities=include_severities,
264
+ )
265
+ )
280
266
 
281
267
  return BreakingChanges(breaking_changes=breaking_changes)
282
268
 
@@ -290,17 +276,20 @@ class DataContract:
290
276
  )
291
277
 
292
278
  def export(self, export_format, model: str = "all", rdf_base: str = None, sql_server_type: str = "auto") -> str:
293
- data_contract = resolve.resolve_data_contract(self._data_contract_file, self._data_contract_str,
294
- self._data_contract, inline_definitions=True)
279
+ data_contract = resolve.resolve_data_contract(
280
+ self._data_contract_file, self._data_contract_str, self._data_contract, inline_definitions=True
281
+ )
295
282
  if export_format == "jsonschema":
296
283
  if data_contract.models is None:
297
- raise RuntimeError( f"Export to {export_format} requires models in the data contract.")
284
+ raise RuntimeError(f"Export to {export_format} requires models in the data contract.")
298
285
 
299
286
  model_names = list(data_contract.models.keys())
300
287
 
301
288
  if model == "all":
302
289
  if len(data_contract.models.items()) != 1:
303
- raise RuntimeError( f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}")
290
+ raise RuntimeError(
291
+ f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}"
292
+ )
304
293
 
305
294
  model_name, model_value = next(iter(data_contract.models.items()))
306
295
  return to_jsonschema_json(model_name, model_value)
@@ -308,7 +297,9 @@ class DataContract:
308
297
  model_name = model
309
298
  model_value = data_contract.models.get(model_name)
310
299
  if model_value is None:
311
- raise RuntimeError( f"Model {model_name} not found in the data contract. Available models: {model_names}")
300
+ raise RuntimeError(
301
+ f"Model {model_name} not found in the data contract. Available models: {model_names}"
302
+ )
312
303
 
313
304
  return to_jsonschema_json(model_name, model_value)
314
305
  if export_format == "sodacl":
@@ -325,7 +316,9 @@ class DataContract:
325
316
 
326
317
  if model == "all":
327
318
  if len(data_contract.models.items()) != 1:
328
- raise RuntimeError(f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}")
319
+ raise RuntimeError(
320
+ f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}"
321
+ )
329
322
 
330
323
  model_name, model_value = next(iter(data_contract.models.items()))
331
324
  return to_dbt_staging_sql(data_contract, model_name, model_value)
@@ -333,7 +326,9 @@ class DataContract:
333
326
  model_name = model
334
327
  model_value = data_contract.models.get(model_name)
335
328
  if model_value is None:
336
- raise RuntimeError(f"Model {model_name} not found in the data contract. Available models: {model_names}")
329
+ raise RuntimeError(
330
+ f"Model {model_name} not found in the data contract. Available models: {model_names}"
331
+ )
337
332
 
338
333
  return to_dbt_staging_sql(data_contract, model_name, model_value)
339
334
  if export_format == "odcs":
@@ -350,7 +345,9 @@ class DataContract:
350
345
 
351
346
  if model == "all":
352
347
  if len(data_contract.models.items()) != 1:
353
- raise RuntimeError(f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}")
348
+ raise RuntimeError(
349
+ f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}"
350
+ )
354
351
 
355
352
  model_name, model_value = next(iter(data_contract.models.items()))
356
353
  return to_avro_schema_json(model_name, model_value)
@@ -358,7 +355,9 @@ class DataContract:
358
355
  model_name = model
359
356
  model_value = data_contract.models.get(model_name)
360
357
  if model_value is None:
361
- raise RuntimeError(f"Model {model_name} not found in the data contract. Available models: {model_names}")
358
+ raise RuntimeError(
359
+ f"Model {model_name} not found in the data contract. Available models: {model_names}"
360
+ )
362
361
 
363
362
  return to_avro_schema_json(model_name, model_value)
364
363
  if export_format == "avro-idl":
@@ -366,19 +365,21 @@ class DataContract:
366
365
  if export_format == "terraform":
367
366
  return to_terraform(data_contract)
368
367
  if export_format == "sql":
369
- server_type = _determine_sql_server_type(data_contract, sql_server_type)
368
+ server_type = self._determine_sql_server_type(data_contract, sql_server_type)
370
369
  return to_sql_ddl(data_contract, server_type=server_type)
371
370
  if export_format == "sql-query":
372
371
  if data_contract.models is None:
373
372
  raise RuntimeError(f"Export to {export_format} requires models in the data contract.")
374
373
 
375
- server_type = _determine_sql_server_type(data_contract, sql_server_type)
374
+ server_type = self._determine_sql_server_type(data_contract, sql_server_type)
376
375
 
377
376
  model_names = list(data_contract.models.keys())
378
377
 
379
378
  if model == "all":
380
379
  if len(data_contract.models.items()) != 1:
381
- raise RuntimeError(f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}")
380
+ raise RuntimeError(
381
+ f"Export to {export_format} is model specific. Specify the model via --model $MODEL_NAME. Available models: {model_names}"
382
+ )
382
383
 
383
384
  model_name, model_value = next(iter(data_contract.models.items()))
384
385
  return to_sql_query(data_contract, model_name, model_value, server_type)
@@ -386,13 +387,62 @@ class DataContract:
386
387
  model_name = model
387
388
  model_value = data_contract.models.get(model_name)
388
389
  if model_value is None:
389
- raise RuntimeError(f"Model {model_name} not found in the data contract. Available models: {model_names}")
390
+ raise RuntimeError(
391
+ f"Model {model_name} not found in the data contract. Available models: {model_names}"
392
+ )
390
393
 
391
394
  return to_sql_query(data_contract, model_name, model_value, server_type)
395
+
396
+ if export_format == "great-expectations":
397
+ if data_contract.models is None:
398
+ raise RuntimeError(f"Export to {export_format} requires models in the data contract.")
399
+
400
+ model_names = list(data_contract.models.keys())
401
+
402
+ if model == "all":
403
+ if len(data_contract.models.items()) != 1:
404
+ raise RuntimeError(
405
+ f"Export to {export_format} is model specific. Specify the model via --model "
406
+ f"$MODEL_NAME. Available models: {model_names}"
407
+ )
408
+
409
+ model_name, model_value = next(iter(data_contract.models.items()))
410
+ return to_great_expectations(data_contract, model_name)
411
+ else:
412
+ model_name = model
413
+ model_value = data_contract.models.get(model_name)
414
+ if model_value is None:
415
+ raise RuntimeError(
416
+ f"Model {model_name} not found in the data contract. " f"Available models: {model_names}"
417
+ )
418
+
419
+ return to_great_expectations(data_contract, model_name)
420
+ if export_format == "pydantic-model":
421
+ return to_pydantic_model_str(data_contract)
422
+ if export_format == "html":
423
+ return to_html(data_contract)
392
424
  else:
393
425
  print(f"Export format {export_format} not supported.")
394
426
  return ""
395
427
 
428
+ def _determine_sql_server_type(self, data_contract: DataContractSpecification, sql_server_type: str):
429
+ if sql_server_type == "auto":
430
+ if data_contract.servers is None or len(data_contract.servers) == 0:
431
+ raise RuntimeError("Export with server_type='auto' requires servers in the data contract.")
432
+
433
+ server_types = set([server.type for server in data_contract.servers.values()])
434
+ if "snowflake" in server_types:
435
+ return "snowflake"
436
+ elif "postgres" in server_types:
437
+ return "postgres"
438
+ elif "databricks" in server_types:
439
+ return "databricks"
440
+ else:
441
+ # default to snowflake dialect
442
+ return "snowflake"
443
+ else:
444
+ return sql_server_type
445
+
396
446
  def _get_examples_server(self, data_contract, run, tmp_dir):
397
447
  run.log_info(f"Copying examples to files in temporary directory {tmp_dir}")
398
448
  format = "json"
@@ -402,13 +452,13 @@ class DataContract:
402
452
  run.log_info(f"Creating example file {p}")
403
453
  with open(p, "w") as f:
404
454
  content = ""
405
- if format == "json" and type(example.data) is list:
455
+ if format == "json" and isinstance(example.data, list):
406
456
  content = json.dumps(example.data)
407
- elif format == "json" and type(example.data) is str:
457
+ elif format == "json" and isinstance(example.data, str):
408
458
  content = example.data
409
- elif format == "yaml" and type(example.data) is list:
459
+ elif format == "yaml" and isinstance(example.data, list):
410
460
  content = yaml.dump(example.data, allow_unicode=True)
411
- elif format == "yaml" and type(example.data) is str:
461
+ elif format == "yaml" and isinstance(example.data, str):
412
462
  content = example.data
413
463
  elif format == "csv":
414
464
  content = example.data
@@ -3,7 +3,9 @@ from datacontract.model.exceptions import DataContractException
3
3
  from datacontract.model.run import Run
4
4
 
5
5
 
6
- def check_that_datacontract_contains_valid_server_configuration(run: Run, data_contract: DataContractSpecification, server_name: str):
6
+ def check_that_datacontract_contains_valid_server_configuration(
7
+ run: Run, data_contract: DataContractSpecification, server_name: str
8
+ ):
7
9
  if data_contract.servers is None:
8
10
  raise DataContractException(
9
11
  type="lint",
@@ -28,4 +30,6 @@ def check_that_datacontract_contains_valid_server_configuration(run: Run, data_c
28
30
  reason=f"Cannot find server '{server_name}' in the data contract servers configuration. Skip executing tests.",
29
31
  engine="datacontract",
30
32
  )
33
+
34
+
31
35
  # TODO check for server.type, if all required fields are present
@@ -9,12 +9,13 @@ def check_that_datacontract_file_exists(run: Run, file_path: str):
9
9
  if file_path.startswith("http://") or file_path.startswith("https://"):
10
10
  return
11
11
  if not os.path.exists(file_path):
12
- run.checks.append(Check(
13
- type="lint",
14
- name="Check that data contract file exists",
15
- result="failed",
16
- reason=f"The file '{file_path}' does not exist.",
17
- engine="datacontract-cli",
18
- ))
12
+ run.checks.append(
13
+ Check(
14
+ type="lint",
15
+ name="Check that data contract file exists",
16
+ result="failed",
17
+ reason=f"The file '{file_path}' does not exist.",
18
+ engine="datacontract-cli",
19
+ )
20
+ )
19
21
  raise Exception(f"The file '{file_path}' does not exist.")
20
-
@@ -14,31 +14,35 @@ def check_that_datacontract_str_is_valid(run: Run, data_contract_str: str):
14
14
  try:
15
15
  fastjsonschema.validate(schema, data_contract_yaml)
16
16
  logging.debug("YAML data is valid.")
17
- run.checks.append(Check(
18
- type="lint",
19
- result="passed",
20
- name="Check that data contract YAML is valid",
21
- engine="datacontract",
22
- ))
17
+ run.checks.append(
18
+ Check(
19
+ type="lint",
20
+ result="passed",
21
+ name="Check that data contract YAML is valid",
22
+ engine="datacontract",
23
+ )
24
+ )
23
25
  except JsonSchemaValueException as e:
24
26
  logging.warning("YAML data is invalid.")
25
27
  logging.warning(f"Validation error: {e.message}")
26
- run.checks.append(Check(
27
- type="lint",
28
- result="failed",
29
- name="Check that data contract YAML is valid",
30
- reason=e.message,
31
- engine="datacontract",
32
- ))
28
+ run.checks.append(
29
+ Check(
30
+ type="lint",
31
+ result="failed",
32
+ name="Check that data contract YAML is valid",
33
+ reason=e.message,
34
+ engine="datacontract",
35
+ )
36
+ )
33
37
  except Exception as e:
34
38
  logging.warning("YAML data is invalid.")
35
39
  logging.warning(f"Validation error: {str(e)}")
36
- run.checks.append(Check(
37
- type="lint",
38
- result="failed",
39
- name="Check that data contract YAML is valid",
40
- reason=str(e),
41
- engine="datacontract",
42
- ))
43
-
44
-
40
+ run.checks.append(
41
+ Check(
42
+ type="lint",
43
+ result="failed",
44
+ name="Check that data contract YAML is valid",
45
+ reason=str(e),
46
+ engine="datacontract",
47
+ )
48
+ )