acryl-datahub-cloud 0.3.12rc4__py3-none-any.whl → 0.3.12rc6__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 acryl-datahub-cloud might be problematic. Click here for more details.
- acryl_datahub_cloud/_codegen_config.json +1 -1
- acryl_datahub_cloud/datahub_forms_notifications/get_feature_flag.gql +7 -0
- acryl_datahub_cloud/sdk/__init__.py +11 -1
- acryl_datahub_cloud/sdk/assertion/__init__.py +0 -0
- acryl_datahub_cloud/sdk/{assertion.py → assertion/assertion_base.py} +565 -166
- acryl_datahub_cloud/sdk/assertion/smart_column_metric_assertion.py +224 -0
- acryl_datahub_cloud/sdk/assertion/types.py +20 -0
- acryl_datahub_cloud/sdk/assertion_input/assertion_input.py +46 -14
- acryl_datahub_cloud/sdk/assertion_input/freshness_assertion_input.py +1 -2
- acryl_datahub_cloud/sdk/assertion_input/smart_column_metric_assertion_input.py +12 -43
- acryl_datahub_cloud/sdk/assertion_input/sql_assertion_input.py +274 -0
- acryl_datahub_cloud/sdk/assertions_client.py +1202 -27
- acryl_datahub_cloud/sdk/entities/assertion.py +4 -0
- {acryl_datahub_cloud-0.3.12rc4.dist-info → acryl_datahub_cloud-0.3.12rc6.dist-info}/METADATA +44 -44
- {acryl_datahub_cloud-0.3.12rc4.dist-info → acryl_datahub_cloud-0.3.12rc6.dist-info}/RECORD +18 -13
- {acryl_datahub_cloud-0.3.12rc4.dist-info → acryl_datahub_cloud-0.3.12rc6.dist-info}/WHEEL +0 -0
- {acryl_datahub_cloud-0.3.12rc4.dist-info → acryl_datahub_cloud-0.3.12rc6.dist-info}/entry_points.txt +0 -0
- {acryl_datahub_cloud-0.3.12rc4.dist-info → acryl_datahub_cloud-0.3.12rc6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional, Union
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from acryl_datahub_cloud.sdk.assertion_input.assertion_input import (
|
|
8
|
+
DEFAULT_EVERY_SIX_HOURS_SCHEDULE,
|
|
9
|
+
RANGE_OPERATORS,
|
|
10
|
+
SINGLE_VALUE_NUMERIC_OPERATORS,
|
|
11
|
+
AssertionIncidentBehavior,
|
|
12
|
+
FieldSpecType,
|
|
13
|
+
_AssertionInput,
|
|
14
|
+
_try_parse_and_validate_schema_classes_enum,
|
|
15
|
+
)
|
|
16
|
+
from acryl_datahub_cloud.sdk.entities.assertion import (
|
|
17
|
+
AssertionInfoInputType,
|
|
18
|
+
TagsInputType,
|
|
19
|
+
)
|
|
20
|
+
from acryl_datahub_cloud.sdk.errors import SDKUsageError
|
|
21
|
+
from datahub.metadata import schema_classes as models
|
|
22
|
+
from datahub.metadata.urns import AssertionUrn, CorpUserUrn, DatasetUrn
|
|
23
|
+
from datahub.sdk.entity_client import EntityClient
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SqlAssertionType(Enum):
|
|
27
|
+
METRIC_CHANGE = models.SqlAssertionTypeClass.METRIC_CHANGE
|
|
28
|
+
METRIC = models.SqlAssertionTypeClass.METRIC
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SqlAssertionChangeType(Enum):
|
|
32
|
+
ABSOLUTE = models.AssertionValueChangeTypeClass.ABSOLUTE
|
|
33
|
+
PERCENTAGE = models.AssertionValueChangeTypeClass.PERCENTAGE
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SqlAssertionOperator(Enum):
|
|
37
|
+
EQUAL_TO = models.AssertionStdOperatorClass.EQUAL_TO
|
|
38
|
+
NOT_EQUAL_TO = models.AssertionStdOperatorClass.NOT_EQUAL_TO
|
|
39
|
+
GREATER_THAN = models.AssertionStdOperatorClass.GREATER_THAN
|
|
40
|
+
LESS_THAN = models.AssertionStdOperatorClass.LESS_THAN
|
|
41
|
+
GREATER_THAN_OR_EQUAL_TO = models.AssertionStdOperatorClass.GREATER_THAN_OR_EQUAL_TO
|
|
42
|
+
LESS_THAN_OR_EQUAL_TO = models.AssertionStdOperatorClass.LESS_THAN_OR_EQUAL_TO
|
|
43
|
+
BETWEEN = models.AssertionStdOperatorClass.BETWEEN
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class SqlAssertionCriteria(BaseModel):
|
|
47
|
+
type: Union[SqlAssertionType, str]
|
|
48
|
+
change_type: Optional[Union[SqlAssertionChangeType, str]]
|
|
49
|
+
operator: Union[SqlAssertionOperator, str]
|
|
50
|
+
# Either a single value or a range must be provided
|
|
51
|
+
parameters: Union[Union[float, int], tuple[Union[float, int], Union[float, int]]]
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def get_type(
|
|
55
|
+
cls, type: Union[SqlAssertionType, str]
|
|
56
|
+
) -> models.SqlAssertionTypeClass:
|
|
57
|
+
return _try_parse_and_validate_schema_classes_enum(
|
|
58
|
+
type if isinstance(type, str) else str(type.value),
|
|
59
|
+
models.SqlAssertionTypeClass,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def get_change_type(
|
|
64
|
+
cls, change_type: Optional[Union[SqlAssertionChangeType, str]]
|
|
65
|
+
) -> Optional[models.AssertionValueChangeTypeClass]:
|
|
66
|
+
if change_type is None:
|
|
67
|
+
return None
|
|
68
|
+
return _try_parse_and_validate_schema_classes_enum(
|
|
69
|
+
change_type if isinstance(change_type, str) else str(change_type.value),
|
|
70
|
+
models.AssertionValueChangeTypeClass,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def get_operator(
|
|
75
|
+
cls, operator: Union[SqlAssertionOperator, str]
|
|
76
|
+
) -> models.AssertionStdOperatorClass:
|
|
77
|
+
return _try_parse_and_validate_schema_classes_enum(
|
|
78
|
+
operator if isinstance(operator, str) else str(operator.value),
|
|
79
|
+
models.AssertionStdOperatorClass,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def get_parameters(
|
|
84
|
+
cls,
|
|
85
|
+
parameters: Union[
|
|
86
|
+
Union[float, int], tuple[Union[float, int], Union[float, int]]
|
|
87
|
+
],
|
|
88
|
+
) -> models.AssertionStdParametersClass:
|
|
89
|
+
if isinstance(parameters, (float, int)):
|
|
90
|
+
return models.AssertionStdParametersClass(
|
|
91
|
+
value=models.AssertionStdParameterClass(
|
|
92
|
+
type=models.AssertionStdParameterTypeClass.NUMBER,
|
|
93
|
+
value=str(parameters),
|
|
94
|
+
),
|
|
95
|
+
)
|
|
96
|
+
elif isinstance(parameters, tuple):
|
|
97
|
+
return models.AssertionStdParametersClass(
|
|
98
|
+
minValue=models.AssertionStdParameterClass(
|
|
99
|
+
type=models.AssertionStdParameterTypeClass.NUMBER,
|
|
100
|
+
value=str(min(parameters[0], parameters[1])),
|
|
101
|
+
),
|
|
102
|
+
maxValue=models.AssertionStdParameterClass(
|
|
103
|
+
type=models.AssertionStdParameterTypeClass.NUMBER,
|
|
104
|
+
value=str(max(parameters[0], parameters[1])),
|
|
105
|
+
),
|
|
106
|
+
)
|
|
107
|
+
else:
|
|
108
|
+
raise SDKUsageError(
|
|
109
|
+
"Either a single value or a range must be provided for the parameters of SqlAssertionCriteria"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def validate(criteria: "SqlAssertionCriteria") -> "SqlAssertionCriteria":
|
|
114
|
+
operator = SqlAssertionCriteria.get_operator(criteria.operator)
|
|
115
|
+
if operator in SINGLE_VALUE_NUMERIC_OPERATORS:
|
|
116
|
+
if not isinstance(criteria.parameters, float) and not isinstance(
|
|
117
|
+
criteria.parameters, int
|
|
118
|
+
):
|
|
119
|
+
raise SDKUsageError(
|
|
120
|
+
f"The parameter value of SqlAssertionCriteria must be a single value numeric for operator {str(operator)}"
|
|
121
|
+
)
|
|
122
|
+
elif operator in RANGE_OPERATORS:
|
|
123
|
+
if not isinstance(criteria.parameters, tuple):
|
|
124
|
+
raise SDKUsageError(
|
|
125
|
+
f"The parameter value of SqlAssertionCriteria must be a tuple range for operator {str(operator)}"
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
raise SDKUsageError(
|
|
129
|
+
f"Operator {str(operator)} is not supported for SqlAssertionCriteria"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
criteria.type == SqlAssertionType.METRIC_CHANGE
|
|
134
|
+
and criteria.change_type is None
|
|
135
|
+
):
|
|
136
|
+
raise SDKUsageError("Change type is required for metric change assertions")
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
criteria.type == SqlAssertionType.METRIC
|
|
140
|
+
and criteria.change_type is not None
|
|
141
|
+
):
|
|
142
|
+
raise SDKUsageError("Change type is not allowed for metric assertions")
|
|
143
|
+
|
|
144
|
+
return criteria
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class _SqlAssertionInput(_AssertionInput):
|
|
148
|
+
def _assertion_type(self) -> str:
|
|
149
|
+
"""Get the assertion type."""
|
|
150
|
+
return models.AssertionTypeClass.SQL
|
|
151
|
+
|
|
152
|
+
def __init__(
|
|
153
|
+
self,
|
|
154
|
+
*,
|
|
155
|
+
# Required fields
|
|
156
|
+
dataset_urn: Union[str, DatasetUrn],
|
|
157
|
+
entity_client: EntityClient, # Needed to get the schema field spec for the detection mechanism if needed
|
|
158
|
+
urn: Optional[Union[str, AssertionUrn]] = None,
|
|
159
|
+
criteria: SqlAssertionCriteria,
|
|
160
|
+
statement: str,
|
|
161
|
+
# Optional fields
|
|
162
|
+
display_name: Optional[str] = None,
|
|
163
|
+
enabled: bool = True,
|
|
164
|
+
schedule: Optional[Union[str, models.CronScheduleClass]] = None,
|
|
165
|
+
incident_behavior: Optional[
|
|
166
|
+
Union[AssertionIncidentBehavior, list[AssertionIncidentBehavior]]
|
|
167
|
+
] = None,
|
|
168
|
+
tags: Optional[TagsInputType] = None,
|
|
169
|
+
created_by: Union[str, CorpUserUrn],
|
|
170
|
+
created_at: datetime,
|
|
171
|
+
updated_by: Union[str, CorpUserUrn],
|
|
172
|
+
updated_at: datetime,
|
|
173
|
+
):
|
|
174
|
+
_AssertionInput.__init__(
|
|
175
|
+
self,
|
|
176
|
+
dataset_urn=dataset_urn,
|
|
177
|
+
entity_client=entity_client,
|
|
178
|
+
urn=urn,
|
|
179
|
+
display_name=display_name,
|
|
180
|
+
enabled=enabled,
|
|
181
|
+
schedule=schedule,
|
|
182
|
+
incident_behavior=incident_behavior,
|
|
183
|
+
tags=tags,
|
|
184
|
+
source_type=models.AssertionSourceTypeClass.NATIVE, # Native assertions are of type native, not inferred
|
|
185
|
+
created_by=created_by,
|
|
186
|
+
created_at=created_at,
|
|
187
|
+
updated_by=updated_by,
|
|
188
|
+
updated_at=updated_at,
|
|
189
|
+
)
|
|
190
|
+
self.criteria = criteria
|
|
191
|
+
self.statement = statement
|
|
192
|
+
|
|
193
|
+
def _create_monitor_info(
|
|
194
|
+
self,
|
|
195
|
+
assertion_urn: AssertionUrn,
|
|
196
|
+
status: models.MonitorStatusClass,
|
|
197
|
+
schedule: models.CronScheduleClass,
|
|
198
|
+
) -> models.MonitorInfoClass:
|
|
199
|
+
"""
|
|
200
|
+
Create a MonitorInfoClass with all the necessary components.
|
|
201
|
+
"""
|
|
202
|
+
return models.MonitorInfoClass(
|
|
203
|
+
type=models.MonitorTypeClass.ASSERTION,
|
|
204
|
+
status=status,
|
|
205
|
+
assertionMonitor=models.AssertionMonitorClass(
|
|
206
|
+
assertions=[
|
|
207
|
+
models.AssertionEvaluationSpecClass(
|
|
208
|
+
assertion=str(assertion_urn),
|
|
209
|
+
schedule=schedule,
|
|
210
|
+
parameters=self._get_assertion_evaluation_parameters(
|
|
211
|
+
"None",
|
|
212
|
+
None, # Not used for sql assertions
|
|
213
|
+
),
|
|
214
|
+
)
|
|
215
|
+
]
|
|
216
|
+
),
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def _create_assertion_info(
|
|
220
|
+
self,
|
|
221
|
+
filter: Optional[models.DatasetFilterClass], # Not used for sql assertions
|
|
222
|
+
) -> AssertionInfoInputType:
|
|
223
|
+
"""
|
|
224
|
+
Create a SqlAssertionInfoClass for a sql assertion.
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
A SqlAssertionInfoClass configured for sql.
|
|
228
|
+
"""
|
|
229
|
+
SqlAssertionCriteria.validate(self.criteria)
|
|
230
|
+
|
|
231
|
+
return models.SqlAssertionInfoClass(
|
|
232
|
+
type=SqlAssertionCriteria.get_type(self.criteria.type),
|
|
233
|
+
entity=str(self.dataset_urn),
|
|
234
|
+
statement=self.statement,
|
|
235
|
+
changeType=SqlAssertionCriteria.get_change_type(self.criteria.change_type),
|
|
236
|
+
operator=SqlAssertionCriteria.get_operator(self.criteria.operator),
|
|
237
|
+
parameters=SqlAssertionCriteria.get_parameters(self.criteria.parameters),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
def _get_assertion_evaluation_parameters(
|
|
241
|
+
self,
|
|
242
|
+
source_type: str, # Not used for sql assertions
|
|
243
|
+
field: Optional[FieldSpecType], # Not used for sql assertions
|
|
244
|
+
) -> models.AssertionEvaluationParametersClass:
|
|
245
|
+
return models.AssertionEvaluationParametersClass(
|
|
246
|
+
type=models.AssertionEvaluationParametersTypeClass.DATASET_SQL,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# Not used for sql assertions
|
|
250
|
+
def _convert_assertion_source_type_and_field(
|
|
251
|
+
self,
|
|
252
|
+
) -> tuple[str, Optional[FieldSpecType]]:
|
|
253
|
+
return "None", None
|
|
254
|
+
|
|
255
|
+
# Not used for sql assertions
|
|
256
|
+
def _create_filter_from_detection_mechanism(
|
|
257
|
+
self,
|
|
258
|
+
) -> Optional[models.DatasetFilterClass]:
|
|
259
|
+
return None
|
|
260
|
+
|
|
261
|
+
def _convert_schedule(self) -> models.CronScheduleClass:
|
|
262
|
+
"""Create a schedule for a sql assertion.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
A CronScheduleClass with appropriate schedule settings.
|
|
266
|
+
"""
|
|
267
|
+
print(f"self.schedule: {self.schedule}")
|
|
268
|
+
if self.schedule is None:
|
|
269
|
+
return DEFAULT_EVERY_SIX_HOURS_SCHEDULE
|
|
270
|
+
|
|
271
|
+
return models.CronScheduleClass(
|
|
272
|
+
cron=self.schedule.cron,
|
|
273
|
+
timezone=self.schedule.timezone,
|
|
274
|
+
)
|