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.
- datacontract/__init__.py +13 -0
- datacontract/api.py +12 -5
- datacontract/catalog/catalog.py +5 -3
- datacontract/cli.py +116 -10
- datacontract/data_contract.py +143 -65
- datacontract/engines/data_contract_checks.py +366 -60
- datacontract/engines/data_contract_test.py +50 -4
- datacontract/engines/fastjsonschema/check_jsonschema.py +37 -19
- datacontract/engines/fastjsonschema/s3/s3_read_files.py +3 -2
- datacontract/engines/soda/check_soda_execute.py +22 -3
- datacontract/engines/soda/connections/athena.py +79 -0
- datacontract/engines/soda/connections/duckdb_connection.py +65 -6
- datacontract/engines/soda/connections/kafka.py +4 -2
- datacontract/export/avro_converter.py +20 -3
- datacontract/export/bigquery_converter.py +1 -1
- datacontract/export/dbt_converter.py +36 -7
- datacontract/export/dqx_converter.py +126 -0
- datacontract/export/duckdb_type_converter.py +57 -0
- datacontract/export/excel_exporter.py +923 -0
- datacontract/export/exporter.py +3 -0
- datacontract/export/exporter_factory.py +17 -1
- datacontract/export/great_expectations_converter.py +55 -5
- datacontract/export/{html_export.py → html_exporter.py} +31 -20
- datacontract/export/markdown_converter.py +134 -5
- datacontract/export/mermaid_exporter.py +110 -0
- datacontract/export/odcs_v3_exporter.py +187 -145
- datacontract/export/protobuf_converter.py +163 -69
- datacontract/export/rdf_converter.py +2 -2
- datacontract/export/sodacl_converter.py +9 -1
- datacontract/export/spark_converter.py +31 -4
- datacontract/export/sql_converter.py +6 -2
- datacontract/export/sql_type_converter.py +20 -8
- datacontract/imports/avro_importer.py +63 -12
- datacontract/imports/csv_importer.py +111 -57
- datacontract/imports/excel_importer.py +1111 -0
- datacontract/imports/importer.py +16 -3
- datacontract/imports/importer_factory.py +17 -0
- datacontract/imports/json_importer.py +325 -0
- datacontract/imports/odcs_importer.py +2 -2
- datacontract/imports/odcs_v3_importer.py +351 -151
- datacontract/imports/protobuf_importer.py +264 -0
- datacontract/imports/spark_importer.py +117 -13
- datacontract/imports/sql_importer.py +32 -16
- datacontract/imports/unity_importer.py +84 -38
- datacontract/init/init_template.py +1 -1
- datacontract/integration/datamesh_manager.py +16 -2
- datacontract/lint/resolve.py +112 -23
- datacontract/lint/schema.py +24 -15
- datacontract/model/data_contract_specification/__init__.py +1 -0
- datacontract/model/odcs.py +13 -0
- datacontract/model/run.py +3 -0
- datacontract/output/junit_test_results.py +3 -3
- datacontract/schemas/datacontract-1.1.0.init.yaml +1 -1
- datacontract/schemas/datacontract-1.2.0.init.yaml +91 -0
- datacontract/schemas/datacontract-1.2.0.schema.json +2029 -0
- datacontract/schemas/datacontract-1.2.1.init.yaml +91 -0
- datacontract/schemas/datacontract-1.2.1.schema.json +2058 -0
- datacontract/schemas/odcs-3.0.2.schema.json +2382 -0
- datacontract/templates/datacontract.html +54 -3
- datacontract/templates/datacontract_odcs.html +685 -0
- datacontract/templates/index.html +5 -2
- datacontract/templates/partials/server.html +2 -0
- datacontract/templates/style/output.css +319 -145
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/METADATA +656 -431
- datacontract_cli-0.10.37.dist-info/RECORD +119 -0
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/WHEEL +1 -1
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info/licenses}/LICENSE +1 -1
- datacontract/export/csv_type_converter.py +0 -36
- datacontract/lint/lint.py +0 -142
- datacontract/lint/linters/description_linter.py +0 -35
- datacontract/lint/linters/field_pattern_linter.py +0 -34
- datacontract/lint/linters/field_reference_linter.py +0 -48
- datacontract/lint/linters/notice_period_linter.py +0 -55
- datacontract/lint/linters/quality_schema_linter.py +0 -52
- datacontract/lint/linters/valid_constraints_linter.py +0 -100
- datacontract/model/data_contract_specification.py +0 -327
- datacontract_cli-0.10.23.dist-info/RECORD +0 -113
- /datacontract/{lint/linters → output}/__init__.py +0 -0
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/entry_points.txt +0 -0
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
from typing import Dict
|
|
2
|
-
|
|
3
|
-
import
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
3
|
+
from open_data_contract_standard.model import (
|
|
4
|
+
CustomProperty,
|
|
5
|
+
DataQuality,
|
|
6
|
+
Description,
|
|
7
|
+
OpenDataContractStandard,
|
|
8
|
+
Role,
|
|
9
|
+
SchemaObject,
|
|
10
|
+
SchemaProperty,
|
|
11
|
+
Server,
|
|
12
|
+
ServiceLevelAgreementProperty,
|
|
13
|
+
Support,
|
|
14
|
+
)
|
|
4
15
|
|
|
5
16
|
from datacontract.export.exporter import Exporter
|
|
6
17
|
from datacontract.model.data_contract_specification import DataContractSpecification, Field, Model
|
|
@@ -12,154 +23,146 @@ class OdcsV3Exporter(Exporter):
|
|
|
12
23
|
|
|
13
24
|
|
|
14
25
|
def to_odcs_v3_yaml(data_contract_spec: DataContractSpecification) -> str:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"name": data_contract_spec.info.title,
|
|
20
|
-
"version": data_contract_spec.info.version,
|
|
21
|
-
"domain": data_contract_spec.info.owner,
|
|
22
|
-
"status": to_status(data_contract_spec.info.status),
|
|
23
|
-
}
|
|
26
|
+
result = to_odcs_v3(data_contract_spec)
|
|
27
|
+
|
|
28
|
+
return result.to_yaml()
|
|
29
|
+
|
|
24
30
|
|
|
31
|
+
def to_odcs_v3(data_contract_spec: DataContractSpecification) -> OpenDataContractStandard:
|
|
32
|
+
result = OpenDataContractStandard(
|
|
33
|
+
apiVersion="v3.0.1",
|
|
34
|
+
kind="DataContract",
|
|
35
|
+
id=data_contract_spec.id,
|
|
36
|
+
name=data_contract_spec.info.title,
|
|
37
|
+
version=data_contract_spec.info.version,
|
|
38
|
+
status=to_status(data_contract_spec.info.status),
|
|
39
|
+
)
|
|
25
40
|
if data_contract_spec.terms is not None:
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
result.description = Description(
|
|
42
|
+
purpose=data_contract_spec.terms.description.strip()
|
|
28
43
|
if data_contract_spec.terms.description is not None
|
|
29
44
|
else None,
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
usage=data_contract_spec.terms.usage.strip() if data_contract_spec.terms.usage is not None else None,
|
|
46
|
+
limitations=data_contract_spec.terms.limitations.strip()
|
|
32
47
|
if data_contract_spec.terms.limitations is not None
|
|
33
48
|
else None,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
odcs["schema"] = []
|
|
49
|
+
)
|
|
50
|
+
result.schema_ = []
|
|
37
51
|
for model_key, model_value in data_contract_spec.models.items():
|
|
38
52
|
odcs_schema = to_odcs_schema(model_key, model_value)
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
result.schema_.append(odcs_schema)
|
|
41
54
|
if data_contract_spec.servicelevels is not None:
|
|
42
55
|
slas = []
|
|
43
56
|
if data_contract_spec.servicelevels.availability is not None:
|
|
44
57
|
slas.append(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
58
|
+
ServiceLevelAgreementProperty(
|
|
59
|
+
property="generalAvailability", value=data_contract_spec.servicelevels.availability.description
|
|
60
|
+
)
|
|
49
61
|
)
|
|
50
62
|
if data_contract_spec.servicelevels.retention is not None:
|
|
51
|
-
slas.append(
|
|
63
|
+
slas.append(
|
|
64
|
+
ServiceLevelAgreementProperty(
|
|
65
|
+
property="retention", value=data_contract_spec.servicelevels.retention.period
|
|
66
|
+
)
|
|
67
|
+
)
|
|
52
68
|
|
|
53
69
|
if len(slas) > 0:
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
result.slaProperties = slas
|
|
56
71
|
if data_contract_spec.info.contact is not None:
|
|
57
72
|
support = []
|
|
58
73
|
if data_contract_spec.info.contact.email is not None:
|
|
59
|
-
support.append(
|
|
60
|
-
{
|
|
61
|
-
"channel": "email",
|
|
62
|
-
"url": "mailto:" + data_contract_spec.info.contact.email,
|
|
63
|
-
}
|
|
64
|
-
)
|
|
74
|
+
support.append(Support(channel="email", url="mailto:" + data_contract_spec.info.contact.email))
|
|
65
75
|
if data_contract_spec.info.contact.url is not None:
|
|
66
|
-
support.append(
|
|
67
|
-
{
|
|
68
|
-
"channel": "other",
|
|
69
|
-
"url": data_contract_spec.info.contact.url,
|
|
70
|
-
}
|
|
71
|
-
)
|
|
76
|
+
support.append(Support(channel="other", url=data_contract_spec.info.contact.url))
|
|
72
77
|
if len(support) > 0:
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
result.support = support
|
|
75
79
|
if data_contract_spec.servers is not None and len(data_contract_spec.servers) > 0:
|
|
76
80
|
servers = []
|
|
77
81
|
|
|
78
82
|
for server_key, server_value in data_contract_spec.servers.items():
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
server_dict["type"] = server_value.type
|
|
83
|
+
server = Server(server=server_key, type=server_value.type or "")
|
|
84
|
+
|
|
85
|
+
# Set all the attributes that are not None
|
|
83
86
|
if server_value.environment is not None:
|
|
84
|
-
|
|
87
|
+
server.environment = server_value.environment
|
|
85
88
|
if server_value.account is not None:
|
|
86
|
-
|
|
89
|
+
server.account = server_value.account
|
|
87
90
|
if server_value.database is not None:
|
|
88
|
-
|
|
91
|
+
server.database = server_value.database
|
|
89
92
|
if server_value.schema_ is not None:
|
|
90
|
-
|
|
93
|
+
server.schema_ = server_value.schema_
|
|
91
94
|
if server_value.format is not None:
|
|
92
|
-
|
|
95
|
+
server.format = server_value.format
|
|
93
96
|
if server_value.project is not None:
|
|
94
|
-
|
|
97
|
+
server.project = server_value.project
|
|
95
98
|
if server_value.dataset is not None:
|
|
96
|
-
|
|
99
|
+
server.dataset = server_value.dataset
|
|
97
100
|
if server_value.path is not None:
|
|
98
|
-
|
|
101
|
+
server.path = server_value.path
|
|
99
102
|
if server_value.delimiter is not None:
|
|
100
|
-
|
|
103
|
+
server.delimiter = server_value.delimiter
|
|
101
104
|
if server_value.endpointUrl is not None:
|
|
102
|
-
|
|
105
|
+
server.endpointUrl = server_value.endpointUrl
|
|
103
106
|
if server_value.location is not None:
|
|
104
|
-
|
|
107
|
+
server.location = server_value.location
|
|
105
108
|
if server_value.host is not None:
|
|
106
|
-
|
|
109
|
+
server.host = server_value.host
|
|
107
110
|
if server_value.port is not None:
|
|
108
|
-
|
|
111
|
+
server.port = server_value.port
|
|
109
112
|
if server_value.catalog is not None:
|
|
110
|
-
|
|
113
|
+
server.catalog = server_value.catalog
|
|
111
114
|
if server_value.topic is not None:
|
|
112
|
-
|
|
115
|
+
server.topic = server_value.topic
|
|
113
116
|
if server_value.http_path is not None:
|
|
114
|
-
|
|
117
|
+
server.http_path = server_value.http_path
|
|
115
118
|
if server_value.token is not None:
|
|
116
|
-
|
|
119
|
+
server.token = server_value.token
|
|
117
120
|
if server_value.driver is not None:
|
|
118
|
-
|
|
121
|
+
server.driver = server_value.driver
|
|
122
|
+
|
|
119
123
|
if server_value.roles is not None:
|
|
120
|
-
|
|
121
|
-
{"name": role.name, "description": role.description} for role in server_value.roles
|
|
122
|
-
]
|
|
123
|
-
servers.append(server_dict)
|
|
124
|
+
server.roles = [Role(role=role.name, description=role.description) for role in server_value.roles]
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
odcs["servers"] = servers
|
|
126
|
+
servers.append(server)
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
if len(servers) > 0:
|
|
129
|
+
result.servers = servers
|
|
130
|
+
custom_properties = []
|
|
131
|
+
if data_contract_spec.info.owner is not None:
|
|
132
|
+
custom_properties.append(CustomProperty(property="owner", value=data_contract_spec.info.owner))
|
|
129
133
|
if data_contract_spec.info.model_extra is not None:
|
|
130
134
|
for key, value in data_contract_spec.info.model_extra.items():
|
|
131
|
-
|
|
132
|
-
if len(
|
|
133
|
-
|
|
135
|
+
custom_properties.append(CustomProperty(property=key, value=value))
|
|
136
|
+
if len(custom_properties) > 0:
|
|
137
|
+
result.customProperties = custom_properties
|
|
138
|
+
return result
|
|
134
139
|
|
|
135
|
-
return yaml.dump(odcs, indent=2, sort_keys=False, allow_unicode=True)
|
|
136
140
|
|
|
141
|
+
def to_odcs_schema(model_key, model_value: Model) -> SchemaObject:
|
|
142
|
+
schema_obj = SchemaObject(
|
|
143
|
+
name=model_key, physicalName=model_key, logicalType="object", physicalType=model_value.type
|
|
144
|
+
)
|
|
137
145
|
|
|
138
|
-
def to_odcs_schema(model_key, model_value: Model) -> dict:
|
|
139
|
-
odcs_table = {
|
|
140
|
-
"name": model_key,
|
|
141
|
-
"physicalName": model_key,
|
|
142
|
-
"logicalType": "object",
|
|
143
|
-
"physicalType": model_value.type,
|
|
144
|
-
}
|
|
145
146
|
if model_value.description is not None:
|
|
146
|
-
|
|
147
|
+
schema_obj.description = model_value.description
|
|
148
|
+
|
|
147
149
|
properties = to_properties(model_value.fields)
|
|
148
150
|
if properties:
|
|
149
|
-
|
|
151
|
+
schema_obj.properties = properties
|
|
150
152
|
|
|
151
153
|
model_quality = to_odcs_quality_list(model_value.quality)
|
|
152
154
|
if len(model_quality) > 0:
|
|
153
|
-
|
|
155
|
+
schema_obj.quality = model_quality
|
|
154
156
|
|
|
155
|
-
|
|
157
|
+
custom_properties = []
|
|
156
158
|
if model_value.model_extra is not None:
|
|
157
159
|
for key, value in model_value.model_extra.items():
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
custom_properties.append(CustomProperty(property=key, value=value))
|
|
161
|
+
|
|
162
|
+
if len(custom_properties) > 0:
|
|
163
|
+
schema_obj.customProperties = custom_properties
|
|
161
164
|
|
|
162
|
-
return
|
|
165
|
+
return schema_obj
|
|
163
166
|
|
|
164
167
|
|
|
165
168
|
def to_properties(fields: Dict[str, Field]) -> list:
|
|
@@ -197,82 +200,119 @@ def to_logical_type(type: str) -> str | None:
|
|
|
197
200
|
return "array"
|
|
198
201
|
if type.lower() in ["array"]:
|
|
199
202
|
return "array"
|
|
203
|
+
if type.lower() in ["variant"]:
|
|
204
|
+
return "variant"
|
|
200
205
|
if type.lower() in ["null"]:
|
|
201
206
|
return None
|
|
202
207
|
return None
|
|
203
208
|
|
|
204
209
|
|
|
205
|
-
def to_physical_type(
|
|
206
|
-
|
|
207
|
-
|
|
210
|
+
def to_physical_type(config: Dict[str, Any]) -> str | None:
|
|
211
|
+
if config is None:
|
|
212
|
+
return None
|
|
213
|
+
if "postgresType" in config:
|
|
214
|
+
return config["postgresType"]
|
|
215
|
+
elif "bigqueryType" in config:
|
|
216
|
+
return config["bigqueryType"]
|
|
217
|
+
elif "snowflakeType" in config:
|
|
218
|
+
return config["snowflakeType"]
|
|
219
|
+
elif "redshiftType" in config:
|
|
220
|
+
return config["redshiftType"]
|
|
221
|
+
elif "sqlserverType" in config:
|
|
222
|
+
return config["sqlserverType"]
|
|
223
|
+
elif "databricksType" in config:
|
|
224
|
+
return config["databricksType"]
|
|
225
|
+
elif "physicalType" in config:
|
|
226
|
+
return config["physicalType"]
|
|
227
|
+
return None
|
|
208
228
|
|
|
209
229
|
|
|
210
|
-
def to_property(field_name: str, field: Field) ->
|
|
211
|
-
property =
|
|
230
|
+
def to_property(field_name: str, field: Field) -> SchemaProperty:
|
|
231
|
+
property = SchemaProperty(name=field_name)
|
|
232
|
+
|
|
233
|
+
if field.fields:
|
|
234
|
+
properties = []
|
|
235
|
+
for field_name_, field_ in field.fields.items():
|
|
236
|
+
property_ = to_property(field_name_, field_)
|
|
237
|
+
properties.append(property_)
|
|
238
|
+
property.properties = properties
|
|
239
|
+
|
|
240
|
+
if field.items:
|
|
241
|
+
items = to_property(field_name, field.items)
|
|
242
|
+
items.name = None # Clear the name for items
|
|
243
|
+
property.items = items
|
|
244
|
+
|
|
212
245
|
if field.title is not None:
|
|
213
|
-
property
|
|
246
|
+
property.businessName = field.title
|
|
247
|
+
|
|
214
248
|
if field.type is not None:
|
|
215
|
-
property
|
|
216
|
-
property
|
|
249
|
+
property.logicalType = to_logical_type(field.type)
|
|
250
|
+
property.physicalType = to_physical_type(field.config) or field.type
|
|
251
|
+
|
|
217
252
|
if field.description is not None:
|
|
218
|
-
property
|
|
253
|
+
property.description = field.description
|
|
254
|
+
|
|
219
255
|
if field.required is not None:
|
|
220
|
-
property
|
|
256
|
+
property.required = field.required
|
|
257
|
+
|
|
221
258
|
if field.unique is not None:
|
|
222
|
-
property
|
|
259
|
+
property.unique = field.unique
|
|
260
|
+
|
|
223
261
|
if field.classification is not None:
|
|
224
|
-
property
|
|
262
|
+
property.classification = field.classification
|
|
263
|
+
|
|
225
264
|
if field.examples is not None:
|
|
226
|
-
property
|
|
265
|
+
property.examples = field.examples.copy()
|
|
266
|
+
|
|
227
267
|
if field.example is not None:
|
|
228
|
-
property
|
|
268
|
+
property.examples = [field.example]
|
|
269
|
+
|
|
229
270
|
if field.primaryKey is not None and field.primaryKey:
|
|
230
|
-
property
|
|
231
|
-
property
|
|
271
|
+
property.primaryKey = field.primaryKey
|
|
272
|
+
property.primaryKeyPosition = 1
|
|
273
|
+
|
|
232
274
|
if field.primary is not None and field.primary:
|
|
233
|
-
property
|
|
234
|
-
property
|
|
275
|
+
property.primaryKey = field.primary
|
|
276
|
+
property.primaryKeyPosition = 1
|
|
235
277
|
|
|
236
|
-
|
|
278
|
+
custom_properties = []
|
|
237
279
|
if field.model_extra is not None:
|
|
238
280
|
for key, value in field.model_extra.items():
|
|
239
|
-
|
|
281
|
+
custom_properties.append(CustomProperty(property=key, value=value))
|
|
282
|
+
|
|
240
283
|
if field.pii is not None:
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
284
|
+
custom_properties.append(CustomProperty(property="pii", value=field.pii))
|
|
285
|
+
|
|
286
|
+
if len(custom_properties) > 0:
|
|
287
|
+
property.customProperties = custom_properties
|
|
244
288
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
property["tags"].extend(field.tags)
|
|
248
|
-
if not property["tags"]:
|
|
249
|
-
del property["tags"]
|
|
289
|
+
if field.tags is not None and len(field.tags) > 0:
|
|
290
|
+
property.tags = field.tags
|
|
250
291
|
|
|
251
|
-
|
|
292
|
+
logical_type_options = {}
|
|
252
293
|
if field.minLength is not None:
|
|
253
|
-
|
|
294
|
+
logical_type_options["minLength"] = field.minLength
|
|
254
295
|
if field.maxLength is not None:
|
|
255
|
-
|
|
296
|
+
logical_type_options["maxLength"] = field.maxLength
|
|
256
297
|
if field.pattern is not None:
|
|
257
|
-
|
|
298
|
+
logical_type_options["pattern"] = field.pattern
|
|
258
299
|
if field.minimum is not None:
|
|
259
|
-
|
|
300
|
+
logical_type_options["minimum"] = field.minimum
|
|
260
301
|
if field.maximum is not None:
|
|
261
|
-
|
|
302
|
+
logical_type_options["maximum"] = field.maximum
|
|
262
303
|
if field.exclusiveMinimum is not None:
|
|
263
|
-
|
|
304
|
+
logical_type_options["exclusiveMinimum"] = field.exclusiveMinimum
|
|
264
305
|
if field.exclusiveMaximum is not None:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
306
|
+
logical_type_options["exclusiveMaximum"] = field.exclusiveMaximum
|
|
307
|
+
|
|
308
|
+
if logical_type_options:
|
|
309
|
+
property.logicalTypeOptions = logical_type_options
|
|
268
310
|
|
|
269
311
|
if field.quality is not None:
|
|
270
312
|
quality_list = field.quality
|
|
271
313
|
quality_property = to_odcs_quality_list(quality_list)
|
|
272
314
|
if len(quality_property) > 0:
|
|
273
|
-
property
|
|
274
|
-
|
|
275
|
-
# todo enum
|
|
315
|
+
property.quality = quality_property
|
|
276
316
|
|
|
277
317
|
return property
|
|
278
318
|
|
|
@@ -285,33 +325,35 @@ def to_odcs_quality_list(quality_list):
|
|
|
285
325
|
|
|
286
326
|
|
|
287
327
|
def to_odcs_quality(quality):
|
|
288
|
-
|
|
328
|
+
quality_obj = DataQuality(type=quality.type)
|
|
329
|
+
|
|
289
330
|
if quality.description is not None:
|
|
290
|
-
|
|
331
|
+
quality_obj.description = quality.description
|
|
291
332
|
if quality.query is not None:
|
|
292
|
-
|
|
333
|
+
quality_obj.query = quality.query
|
|
293
334
|
# dialect is not supported in v3.0.0
|
|
294
335
|
if quality.mustBe is not None:
|
|
295
|
-
|
|
336
|
+
quality_obj.mustBe = quality.mustBe
|
|
296
337
|
if quality.mustNotBe is not None:
|
|
297
|
-
|
|
338
|
+
quality_obj.mustNotBe = quality.mustNotBe
|
|
298
339
|
if quality.mustBeGreaterThan is not None:
|
|
299
|
-
|
|
340
|
+
quality_obj.mustBeGreaterThan = quality.mustBeGreaterThan
|
|
300
341
|
if quality.mustBeGreaterThanOrEqualTo is not None:
|
|
301
|
-
|
|
342
|
+
quality_obj.mustBeGreaterOrEqualTo = quality.mustBeGreaterThanOrEqualTo
|
|
302
343
|
if quality.mustBeLessThan is not None:
|
|
303
|
-
|
|
344
|
+
quality_obj.mustBeLessThan = quality.mustBeLessThan
|
|
304
345
|
if quality.mustBeLessThanOrEqualTo is not None:
|
|
305
|
-
|
|
346
|
+
quality_obj.mustBeLessOrEqualTo = quality.mustBeLessThanOrEqualTo
|
|
306
347
|
if quality.mustBeBetween is not None:
|
|
307
|
-
|
|
348
|
+
quality_obj.mustBeBetween = quality.mustBeBetween
|
|
308
349
|
if quality.mustNotBeBetween is not None:
|
|
309
|
-
|
|
350
|
+
quality_obj.mustNotBeBetween = quality.mustNotBeBetween
|
|
310
351
|
if quality.engine is not None:
|
|
311
|
-
|
|
352
|
+
quality_obj.engine = quality.engine
|
|
312
353
|
if quality.implementation is not None:
|
|
313
|
-
|
|
314
|
-
|
|
354
|
+
quality_obj.implementation = quality.implementation
|
|
355
|
+
|
|
356
|
+
return quality_obj
|
|
315
357
|
|
|
316
358
|
|
|
317
359
|
def to_status(status):
|