acryl-datahub-cloud 0.3.12rc5__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.

@@ -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
+ )