datacontract-cli 0.10.35__py3-none-any.whl → 0.10.36__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 (34) hide show
  1. datacontract/api.py +1 -1
  2. datacontract/cli.py +1 -1
  3. datacontract/data_contract.py +18 -51
  4. datacontract/engines/data_contract_checks.py +280 -19
  5. datacontract/export/dbt_converter.py +30 -4
  6. datacontract/export/dqx_converter.py +12 -7
  7. datacontract/export/excel_exporter.py +3 -3
  8. datacontract/export/markdown_converter.py +35 -16
  9. datacontract/export/rdf_converter.py +2 -2
  10. datacontract/export/sql_type_converter.py +6 -4
  11. datacontract/imports/odcs_v3_importer.py +71 -18
  12. datacontract/imports/unity_importer.py +16 -11
  13. datacontract/init/init_template.py +1 -1
  14. datacontract/lint/resolve.py +1 -1
  15. datacontract/lint/schema.py +1 -1
  16. datacontract/schemas/datacontract-1.1.0.init.yaml +1 -1
  17. datacontract/schemas/datacontract-1.2.0.init.yaml +1 -1
  18. datacontract/schemas/datacontract-1.2.1.init.yaml +91 -0
  19. datacontract/schemas/datacontract-1.2.1.schema.json +2058 -0
  20. datacontract/schemas/odcs-3.0.2.schema.json +2382 -0
  21. datacontract/templates/datacontract_odcs.html +60 -41
  22. {datacontract_cli-0.10.35.dist-info → datacontract_cli-0.10.36.dist-info}/METADATA +27 -24
  23. {datacontract_cli-0.10.35.dist-info → datacontract_cli-0.10.36.dist-info}/RECORD +27 -31
  24. datacontract/lint/lint.py +0 -142
  25. datacontract/lint/linters/__init__.py +0 -0
  26. datacontract/lint/linters/description_linter.py +0 -33
  27. datacontract/lint/linters/field_pattern_linter.py +0 -34
  28. datacontract/lint/linters/field_reference_linter.py +0 -47
  29. datacontract/lint/linters/notice_period_linter.py +0 -55
  30. datacontract/lint/linters/valid_constraints_linter.py +0 -100
  31. {datacontract_cli-0.10.35.dist-info → datacontract_cli-0.10.36.dist-info}/WHEEL +0 -0
  32. {datacontract_cli-0.10.35.dist-info → datacontract_cli-0.10.36.dist-info}/entry_points.txt +0 -0
  33. {datacontract_cli-0.10.35.dist-info → datacontract_cli-0.10.36.dist-info}/licenses/LICENSE +0 -0
  34. {datacontract_cli-0.10.35.dist-info → datacontract_cli-0.10.36.dist-info}/top_level.txt +0 -0
@@ -1,47 +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}' references non-existing model '{ref_model}'."
38
- )
39
- else:
40
- ref_model_obj = contract.models[ref_model]
41
- if ref_field not in ref_model_obj.fields:
42
- result = result.with_error(
43
- f"Field '{field_name}' in model '{model_name}'"
44
- f" references non-existing field '{ref_field}'"
45
- f" in model '{ref_model}'."
46
- )
47
- 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,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 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 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 '{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