acryl-datahub-cloud 0.3.12rc3__py3-none-any.whl → 0.3.12rc4__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/forms_notifications_source.py +37 -2
- acryl_datahub_cloud/metadata/schema.avsc +9 -0
- acryl_datahub_cloud/metadata/schemas/AssertionAnalyticsRunEvent.avsc +9 -0
- acryl_datahub_cloud/sdk/__init__.py +5 -1
- acryl_datahub_cloud/sdk/assertion.py +313 -162
- acryl_datahub_cloud/sdk/assertion_input/__init__.py +0 -0
- acryl_datahub_cloud/sdk/{assertion_input.py → assertion_input/assertion_input.py} +430 -147
- acryl_datahub_cloud/sdk/assertion_input/freshness_assertion_input.py +261 -0
- acryl_datahub_cloud/sdk/assertion_input/smart_column_metric_assertion_input.py +947 -0
- acryl_datahub_cloud/sdk/assertions_client.py +493 -7
- acryl_datahub_cloud/sdk/entities/assertion.py +4 -1
- {acryl_datahub_cloud-0.3.12rc3.dist-info → acryl_datahub_cloud-0.3.12rc4.dist-info}/METADATA +38 -38
- {acryl_datahub_cloud-0.3.12rc3.dist-info → acryl_datahub_cloud-0.3.12rc4.dist-info}/RECORD +17 -14
- {acryl_datahub_cloud-0.3.12rc3.dist-info → acryl_datahub_cloud-0.3.12rc4.dist-info}/WHEEL +0 -0
- {acryl_datahub_cloud-0.3.12rc3.dist-info → acryl_datahub_cloud-0.3.12rc4.dist-info}/entry_points.txt +0 -0
- {acryl_datahub_cloud-0.3.12rc3.dist-info → acryl_datahub_cloud-0.3.12rc4.dist-info}/top_level.txt +0 -0
|
@@ -14,7 +14,7 @@ from typing import Optional, Union
|
|
|
14
14
|
|
|
15
15
|
from typing_extensions import Self
|
|
16
16
|
|
|
17
|
-
from acryl_datahub_cloud.sdk.assertion_input import (
|
|
17
|
+
from acryl_datahub_cloud.sdk.assertion_input.assertion_input import (
|
|
18
18
|
ASSERTION_MONITOR_DEFAULT_TRAINING_LOOKBACK_WINDOW_DAYS,
|
|
19
19
|
DEFAULT_DETECTION_MECHANISM,
|
|
20
20
|
DEFAULT_SCHEDULE,
|
|
@@ -24,6 +24,7 @@ from acryl_datahub_cloud.sdk.assertion_input import (
|
|
|
24
24
|
ExclusionWindowTypes,
|
|
25
25
|
FixedRangeExclusionWindow,
|
|
26
26
|
InferenceSensitivity,
|
|
27
|
+
TimeWindowSizeInputTypes,
|
|
27
28
|
_DetectionMechanismTypes,
|
|
28
29
|
)
|
|
29
30
|
from acryl_datahub_cloud.sdk.entities.assertion import Assertion
|
|
@@ -85,21 +86,12 @@ class _HasSmartFunctionality:
|
|
|
85
86
|
Mixin class that provides smart functionality for assertions.
|
|
86
87
|
"""
|
|
87
88
|
|
|
88
|
-
_SUPPORTED_WITH_FILTER_ASSERTION_TYPES = (
|
|
89
|
-
models.FreshnessAssertionInfoClass,
|
|
90
|
-
models.VolumeAssertionInfoClass,
|
|
91
|
-
)
|
|
92
|
-
|
|
93
89
|
def __init__(
|
|
94
90
|
self,
|
|
95
91
|
*,
|
|
96
92
|
sensitivity: InferenceSensitivity = DEFAULT_SENSITIVITY,
|
|
97
93
|
exclusion_windows: list[ExclusionWindowTypes],
|
|
98
94
|
training_data_lookback_days: int = ASSERTION_MONITOR_DEFAULT_TRAINING_LOOKBACK_WINDOW_DAYS,
|
|
99
|
-
incident_behavior: list[AssertionIncidentBehavior],
|
|
100
|
-
detection_mechanism: Optional[
|
|
101
|
-
_DetectionMechanismTypes
|
|
102
|
-
] = DEFAULT_DETECTION_MECHANISM,
|
|
103
95
|
) -> None:
|
|
104
96
|
"""
|
|
105
97
|
Initialize the smart functionality mixin.
|
|
@@ -115,8 +107,6 @@ class _HasSmartFunctionality:
|
|
|
115
107
|
self._sensitivity = sensitivity
|
|
116
108
|
self._exclusion_windows = exclusion_windows
|
|
117
109
|
self._training_data_lookback_days = training_data_lookback_days
|
|
118
|
-
self._incident_behavior = incident_behavior
|
|
119
|
-
self._detection_mechanism = detection_mechanism
|
|
120
110
|
|
|
121
111
|
@property
|
|
122
112
|
def sensitivity(self) -> InferenceSensitivity:
|
|
@@ -130,14 +120,6 @@ class _HasSmartFunctionality:
|
|
|
130
120
|
def training_data_lookback_days(self) -> int:
|
|
131
121
|
return self._training_data_lookback_days
|
|
132
122
|
|
|
133
|
-
@property
|
|
134
|
-
def incident_behavior(self) -> list[AssertionIncidentBehavior]:
|
|
135
|
-
return self._incident_behavior
|
|
136
|
-
|
|
137
|
-
@property
|
|
138
|
-
def detection_mechanism(self) -> Optional[_DetectionMechanismTypes]:
|
|
139
|
-
return self._detection_mechanism
|
|
140
|
-
|
|
141
123
|
@staticmethod
|
|
142
124
|
def _get_sensitivity(monitor: Monitor) -> InferenceSensitivity:
|
|
143
125
|
# 1. Check if the monitor has a sensitivity field
|
|
@@ -186,6 +168,115 @@ class _HasSmartFunctionality:
|
|
|
186
168
|
assert isinstance(retrieved, int)
|
|
187
169
|
return retrieved
|
|
188
170
|
|
|
171
|
+
|
|
172
|
+
class _AssertionPublic(ABC):
|
|
173
|
+
"""
|
|
174
|
+
Abstract base class that represents a public facing assertion and contains the common properties of all assertions.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
_SUPPORTED_WITH_FILTER_ASSERTION_TYPES = (
|
|
178
|
+
models.FreshnessAssertionInfoClass,
|
|
179
|
+
models.VolumeAssertionInfoClass,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def __init__(
|
|
183
|
+
self,
|
|
184
|
+
*,
|
|
185
|
+
urn: AssertionUrn,
|
|
186
|
+
dataset_urn: DatasetUrn,
|
|
187
|
+
display_name: str,
|
|
188
|
+
mode: AssertionMode,
|
|
189
|
+
tags: list[TagUrn],
|
|
190
|
+
incident_behavior: list[AssertionIncidentBehavior],
|
|
191
|
+
detection_mechanism: Optional[
|
|
192
|
+
_DetectionMechanismTypes
|
|
193
|
+
] = DEFAULT_DETECTION_MECHANISM,
|
|
194
|
+
created_by: Optional[CorpUserUrn] = None,
|
|
195
|
+
created_at: Union[datetime, None] = None,
|
|
196
|
+
updated_by: Optional[CorpUserUrn] = None,
|
|
197
|
+
updated_at: Optional[datetime] = None,
|
|
198
|
+
):
|
|
199
|
+
"""
|
|
200
|
+
Initialize the public facing assertion class.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
urn: The urn of the assertion.
|
|
204
|
+
dataset_urn: The urn of the dataset that the assertion is for.
|
|
205
|
+
display_name: The display name of the assertion.
|
|
206
|
+
mode: The mode of the assertion (active, inactive).
|
|
207
|
+
tags: The tags of the assertion.
|
|
208
|
+
created_by: The urn of the user that created the assertion.
|
|
209
|
+
created_at: The timestamp of when the assertion was created.
|
|
210
|
+
updated_by: The urn of the user that updated the assertion.
|
|
211
|
+
updated_at: The timestamp of when the assertion was updated.
|
|
212
|
+
"""
|
|
213
|
+
self._urn = urn
|
|
214
|
+
self._dataset_urn = dataset_urn
|
|
215
|
+
self._display_name = display_name
|
|
216
|
+
self._mode = mode
|
|
217
|
+
self._incident_behavior = incident_behavior
|
|
218
|
+
self._detection_mechanism = detection_mechanism
|
|
219
|
+
self._created_by = created_by
|
|
220
|
+
self._created_at = created_at
|
|
221
|
+
self._updated_by = updated_by
|
|
222
|
+
self._updated_at = updated_at
|
|
223
|
+
self._tags = tags
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def urn(self) -> AssertionUrn:
|
|
227
|
+
return self._urn
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def dataset_urn(self) -> DatasetUrn:
|
|
231
|
+
return self._dataset_urn
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def display_name(self) -> str:
|
|
235
|
+
return self._display_name
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def mode(self) -> AssertionMode:
|
|
239
|
+
return self._mode
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def incident_behavior(self) -> list[AssertionIncidentBehavior]:
|
|
243
|
+
return self._incident_behavior
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def detection_mechanism(self) -> Optional[_DetectionMechanismTypes]:
|
|
247
|
+
return self._detection_mechanism
|
|
248
|
+
|
|
249
|
+
@property
|
|
250
|
+
def created_by(self) -> Optional[CorpUserUrn]:
|
|
251
|
+
return self._created_by
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
def created_at(self) -> Union[datetime, None]:
|
|
255
|
+
return self._created_at
|
|
256
|
+
|
|
257
|
+
@property
|
|
258
|
+
def updated_by(self) -> Optional[CorpUserUrn]:
|
|
259
|
+
return self._updated_by
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def updated_at(self) -> Union[datetime, None]:
|
|
263
|
+
return self._updated_at
|
|
264
|
+
|
|
265
|
+
@property
|
|
266
|
+
def tags(self) -> list[TagUrn]:
|
|
267
|
+
return self._tags
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def _get_incident_behavior(assertion: Assertion) -> list[AssertionIncidentBehavior]:
|
|
271
|
+
incident_behaviors = []
|
|
272
|
+
for action in assertion.on_failure + assertion.on_success:
|
|
273
|
+
if action.type == models.AssertionActionTypeClass.RAISE_INCIDENT:
|
|
274
|
+
incident_behaviors.append(AssertionIncidentBehavior.RAISE_ON_FAIL)
|
|
275
|
+
elif action.type == models.AssertionActionTypeClass.RESOLVE_INCIDENT:
|
|
276
|
+
incident_behaviors.append(AssertionIncidentBehavior.RESOLVE_ON_PASS)
|
|
277
|
+
|
|
278
|
+
return incident_behaviors
|
|
279
|
+
|
|
189
280
|
@staticmethod
|
|
190
281
|
def _get_detection_mechanism(
|
|
191
282
|
assertion: Assertion,
|
|
@@ -193,7 +284,7 @@ class _HasSmartFunctionality:
|
|
|
193
284
|
default: Optional[_DetectionMechanismTypes] = DEFAULT_DETECTION_MECHANISM,
|
|
194
285
|
) -> Optional[_DetectionMechanismTypes]:
|
|
195
286
|
"""Get the detection mechanism from the monitor and assertion."""
|
|
196
|
-
if not
|
|
287
|
+
if not _AssertionPublic._has_valid_monitor_info(monitor):
|
|
197
288
|
return default
|
|
198
289
|
|
|
199
290
|
# 1. Check if the assertion has a parameters field
|
|
@@ -206,7 +297,7 @@ class _HasSmartFunctionality:
|
|
|
206
297
|
)
|
|
207
298
|
return default
|
|
208
299
|
|
|
209
|
-
parameters =
|
|
300
|
+
parameters = _AssertionPublic._get_assertion_parameters(monitor, default)
|
|
210
301
|
if parameters is None:
|
|
211
302
|
return _warn_and_return_default_detection_mechanism("parameters", default)
|
|
212
303
|
|
|
@@ -218,11 +309,11 @@ class _HasSmartFunctionality:
|
|
|
218
309
|
if assertion.info is None:
|
|
219
310
|
return _warn_and_return_default_detection_mechanism("info", default)
|
|
220
311
|
if isinstance(assertion.info, models.VolumeAssertionInfoClass):
|
|
221
|
-
return
|
|
312
|
+
return _AssertionPublic._get_volume_detection_mechanism(
|
|
222
313
|
assertion, parameters, default
|
|
223
314
|
)
|
|
224
315
|
elif isinstance(assertion.info, models.FreshnessAssertionInfoClass):
|
|
225
|
-
return
|
|
316
|
+
return _AssertionPublic._get_freshness_detection_mechanism(
|
|
226
317
|
assertion, parameters, default
|
|
227
318
|
)
|
|
228
319
|
# TODO: Consider moving the detection mechanism logic to the assertion classes themselves e.g. _get_assertion_specific_detection_mechanism as an abstract method
|
|
@@ -236,53 +327,6 @@ class _HasSmartFunctionality:
|
|
|
236
327
|
f"AssertionEvaluationParametersType {parameters.type} not supported"
|
|
237
328
|
)
|
|
238
329
|
|
|
239
|
-
@staticmethod
|
|
240
|
-
def _has_valid_monitor_info(monitor: Monitor) -> bool:
|
|
241
|
-
"""Check if monitor has valid info and assertion monitor."""
|
|
242
|
-
|
|
243
|
-
def _warn_and_return_false(field_name: str) -> bool:
|
|
244
|
-
logger.warning(
|
|
245
|
-
f"Monitor {monitor.urn} does not have an `{field_name}` field, defaulting detection mechanism to {DEFAULT_DETECTION_MECHANISM}"
|
|
246
|
-
)
|
|
247
|
-
return False
|
|
248
|
-
|
|
249
|
-
if monitor.info is None:
|
|
250
|
-
return _warn_and_return_false("info")
|
|
251
|
-
if monitor.info.assertionMonitor is None:
|
|
252
|
-
return _warn_and_return_false("assertionMonitor")
|
|
253
|
-
if (
|
|
254
|
-
monitor.info.assertionMonitor.assertions is None
|
|
255
|
-
or len(monitor.info.assertionMonitor.assertions) == 0
|
|
256
|
-
):
|
|
257
|
-
return _warn_and_return_false("assertionMonitor.assertions")
|
|
258
|
-
|
|
259
|
-
return True
|
|
260
|
-
|
|
261
|
-
@staticmethod
|
|
262
|
-
def _get_assertion_parameters(
|
|
263
|
-
monitor: Monitor,
|
|
264
|
-
default: Optional[_DetectionMechanismTypes] = DEFAULT_DETECTION_MECHANISM,
|
|
265
|
-
) -> Optional[models.AssertionEvaluationParametersClass]:
|
|
266
|
-
"""Get the assertion parameters from the monitor."""
|
|
267
|
-
# We know these are not None from _has_valid_monitor_info check
|
|
268
|
-
assert (
|
|
269
|
-
monitor is not None
|
|
270
|
-
and monitor.info is not None
|
|
271
|
-
and monitor.info.assertionMonitor is not None
|
|
272
|
-
)
|
|
273
|
-
assertion_monitor = monitor.info.assertionMonitor
|
|
274
|
-
assert (
|
|
275
|
-
assertion_monitor is not None and assertion_monitor.assertions is not None
|
|
276
|
-
)
|
|
277
|
-
assertions = assertion_monitor.assertions
|
|
278
|
-
|
|
279
|
-
if assertions[0].parameters is None:
|
|
280
|
-
logger.warning(
|
|
281
|
-
f"Monitor {monitor.urn} does not have a assertionMonitor.assertions[0].parameters, defaulting detection mechanism to {default}"
|
|
282
|
-
)
|
|
283
|
-
return None
|
|
284
|
-
return assertions[0].parameters
|
|
285
|
-
|
|
286
330
|
@staticmethod
|
|
287
331
|
def _get_freshness_detection_mechanism(
|
|
288
332
|
assertion: Assertion,
|
|
@@ -302,7 +346,7 @@ class _HasSmartFunctionality:
|
|
|
302
346
|
elif source_type == models.DatasetFreshnessSourceTypeClass.AUDIT_LOG:
|
|
303
347
|
return DetectionMechanism.AUDIT_LOG
|
|
304
348
|
elif source_type == models.DatasetFreshnessSourceTypeClass.FIELD_VALUE:
|
|
305
|
-
return
|
|
349
|
+
return _AssertionPublic._get_field_value_detection_mechanism(
|
|
306
350
|
assertion, parameters
|
|
307
351
|
)
|
|
308
352
|
elif source_type == models.DatasetFreshnessSourceTypeClass.DATAHUB_OPERATION:
|
|
@@ -332,7 +376,7 @@ class _HasSmartFunctionality:
|
|
|
332
376
|
if source_type == models.DatasetVolumeSourceTypeClass.INFORMATION_SCHEMA:
|
|
333
377
|
return DetectionMechanism.INFORMATION_SCHEMA
|
|
334
378
|
elif source_type == models.DatasetVolumeSourceTypeClass.QUERY:
|
|
335
|
-
additional_filter =
|
|
379
|
+
additional_filter = _AssertionPublic._get_additional_filter(assertion)
|
|
336
380
|
return DetectionMechanism.QUERY(additional_filter=additional_filter)
|
|
337
381
|
elif source_type == models.DatasetVolumeSourceTypeClass.DATAHUB_DATASET_PROFILE:
|
|
338
382
|
return DetectionMechanism.DATASET_PROFILE
|
|
@@ -356,7 +400,7 @@ class _HasSmartFunctionality:
|
|
|
356
400
|
return DEFAULT_DETECTION_MECHANISM
|
|
357
401
|
|
|
358
402
|
column_name = field.path
|
|
359
|
-
additional_filter =
|
|
403
|
+
additional_filter = _AssertionPublic._get_additional_filter(assertion)
|
|
360
404
|
|
|
361
405
|
if field.kind == models.FreshnessFieldKindClass.LAST_MODIFIED:
|
|
362
406
|
return DetectionMechanism.LAST_MODIFIED_COLUMN(
|
|
@@ -380,7 +424,7 @@ class _HasSmartFunctionality:
|
|
|
380
424
|
if (
|
|
381
425
|
not isinstance(
|
|
382
426
|
assertion.info,
|
|
383
|
-
|
|
427
|
+
_AssertionPublic._SUPPORTED_WITH_FILTER_ASSERTION_TYPES,
|
|
384
428
|
)
|
|
385
429
|
or assertion.info.filter is None
|
|
386
430
|
):
|
|
@@ -394,95 +438,52 @@ class _HasSmartFunctionality:
|
|
|
394
438
|
)
|
|
395
439
|
return assertion.info.filter.sql
|
|
396
440
|
|
|
441
|
+
@staticmethod
|
|
442
|
+
def _has_valid_monitor_info(monitor: Monitor) -> bool:
|
|
443
|
+
"""Check if monitor has valid info and assertion monitor."""
|
|
397
444
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
def __init__(
|
|
404
|
-
self,
|
|
405
|
-
*,
|
|
406
|
-
urn: AssertionUrn,
|
|
407
|
-
dataset_urn: DatasetUrn,
|
|
408
|
-
display_name: str,
|
|
409
|
-
mode: AssertionMode,
|
|
410
|
-
tags: list[TagUrn],
|
|
411
|
-
created_by: Optional[CorpUserUrn] = None,
|
|
412
|
-
created_at: Union[datetime, None] = None,
|
|
413
|
-
updated_by: Optional[CorpUserUrn] = None,
|
|
414
|
-
updated_at: Optional[datetime] = None,
|
|
415
|
-
):
|
|
416
|
-
"""
|
|
417
|
-
Initialize the public facing assertion class.
|
|
418
|
-
|
|
419
|
-
Args:
|
|
420
|
-
urn: The urn of the assertion.
|
|
421
|
-
dataset_urn: The urn of the dataset that the assertion is for.
|
|
422
|
-
display_name: The display name of the assertion.
|
|
423
|
-
mode: The mode of the assertion (active, inactive).
|
|
424
|
-
tags: The tags of the assertion.
|
|
425
|
-
created_by: The urn of the user that created the assertion.
|
|
426
|
-
created_at: The timestamp of when the assertion was created.
|
|
427
|
-
updated_by: The urn of the user that updated the assertion.
|
|
428
|
-
updated_at: The timestamp of when the assertion was updated.
|
|
429
|
-
"""
|
|
430
|
-
self._urn = urn
|
|
431
|
-
self._dataset_urn = dataset_urn
|
|
432
|
-
self._display_name = display_name
|
|
433
|
-
self._mode = mode
|
|
434
|
-
self._created_by = created_by
|
|
435
|
-
self._created_at = created_at
|
|
436
|
-
self._updated_by = updated_by
|
|
437
|
-
self._updated_at = updated_at
|
|
438
|
-
self._tags = tags
|
|
439
|
-
|
|
440
|
-
@property
|
|
441
|
-
def urn(self) -> AssertionUrn:
|
|
442
|
-
return self._urn
|
|
443
|
-
|
|
444
|
-
@property
|
|
445
|
-
def dataset_urn(self) -> DatasetUrn:
|
|
446
|
-
return self._dataset_urn
|
|
447
|
-
|
|
448
|
-
@property
|
|
449
|
-
def display_name(self) -> str:
|
|
450
|
-
return self._display_name
|
|
451
|
-
|
|
452
|
-
@property
|
|
453
|
-
def mode(self) -> AssertionMode:
|
|
454
|
-
return self._mode
|
|
455
|
-
|
|
456
|
-
@property
|
|
457
|
-
def created_by(self) -> Optional[CorpUserUrn]:
|
|
458
|
-
return self._created_by
|
|
459
|
-
|
|
460
|
-
@property
|
|
461
|
-
def created_at(self) -> Union[datetime, None]:
|
|
462
|
-
return self._created_at
|
|
463
|
-
|
|
464
|
-
@property
|
|
465
|
-
def updated_by(self) -> Optional[CorpUserUrn]:
|
|
466
|
-
return self._updated_by
|
|
445
|
+
def _warn_and_return_false(field_name: str) -> bool:
|
|
446
|
+
logger.warning(
|
|
447
|
+
f"Monitor {monitor.urn} does not have an `{field_name}` field, defaulting detection mechanism to {DEFAULT_DETECTION_MECHANISM}"
|
|
448
|
+
)
|
|
449
|
+
return False
|
|
467
450
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
451
|
+
if monitor.info is None:
|
|
452
|
+
return _warn_and_return_false("info")
|
|
453
|
+
if monitor.info.assertionMonitor is None:
|
|
454
|
+
return _warn_and_return_false("assertionMonitor")
|
|
455
|
+
if (
|
|
456
|
+
monitor.info.assertionMonitor.assertions is None
|
|
457
|
+
or len(monitor.info.assertionMonitor.assertions) == 0
|
|
458
|
+
):
|
|
459
|
+
return _warn_and_return_false("assertionMonitor.assertions")
|
|
471
460
|
|
|
472
|
-
|
|
473
|
-
def tags(self) -> list[TagUrn]:
|
|
474
|
-
return self._tags
|
|
461
|
+
return True
|
|
475
462
|
|
|
476
463
|
@staticmethod
|
|
477
|
-
def
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
464
|
+
def _get_assertion_parameters(
|
|
465
|
+
monitor: Monitor,
|
|
466
|
+
default: Optional[_DetectionMechanismTypes] = DEFAULT_DETECTION_MECHANISM,
|
|
467
|
+
) -> Optional[models.AssertionEvaluationParametersClass]:
|
|
468
|
+
"""Get the assertion parameters from the monitor."""
|
|
469
|
+
# We know these are not None from _has_valid_monitor_info check
|
|
470
|
+
assert (
|
|
471
|
+
monitor is not None
|
|
472
|
+
and monitor.info is not None
|
|
473
|
+
and monitor.info.assertionMonitor is not None
|
|
474
|
+
)
|
|
475
|
+
assertion_monitor = monitor.info.assertionMonitor
|
|
476
|
+
assert (
|
|
477
|
+
assertion_monitor is not None and assertion_monitor.assertions is not None
|
|
478
|
+
)
|
|
479
|
+
assertions = assertion_monitor.assertions
|
|
484
480
|
|
|
485
|
-
|
|
481
|
+
if assertions[0].parameters is None:
|
|
482
|
+
logger.warning(
|
|
483
|
+
f"Monitor {monitor.urn} does not have a assertionMonitor.assertions[0].parameters, defaulting detection mechanism to {default}"
|
|
484
|
+
)
|
|
485
|
+
return None
|
|
486
|
+
return assertions[0].parameters
|
|
486
487
|
|
|
487
488
|
@staticmethod
|
|
488
489
|
def _get_created_by(assertion: Assertion) -> Optional[CorpUserUrn]:
|
|
@@ -619,8 +620,6 @@ class SmartFreshnessAssertion(_HasSchedule, _HasSmartFunctionality, _AssertionPu
|
|
|
619
620
|
sensitivity=sensitivity,
|
|
620
621
|
exclusion_windows=exclusion_windows,
|
|
621
622
|
training_data_lookback_days=training_data_lookback_days,
|
|
622
|
-
incident_behavior=incident_behavior,
|
|
623
|
-
detection_mechanism=detection_mechanism,
|
|
624
623
|
)
|
|
625
624
|
# Then initialize the parent class
|
|
626
625
|
_AssertionPublic.__init__(
|
|
@@ -629,6 +628,8 @@ class SmartFreshnessAssertion(_HasSchedule, _HasSmartFunctionality, _AssertionPu
|
|
|
629
628
|
dataset_urn=dataset_urn,
|
|
630
629
|
display_name=display_name,
|
|
631
630
|
mode=mode,
|
|
631
|
+
incident_behavior=incident_behavior,
|
|
632
|
+
detection_mechanism=detection_mechanism,
|
|
632
633
|
created_by=created_by,
|
|
633
634
|
created_at=created_at,
|
|
634
635
|
updated_by=updated_by,
|
|
@@ -717,8 +718,6 @@ class SmartVolumeAssertion(_HasSchedule, _HasSmartFunctionality, _AssertionPubli
|
|
|
717
718
|
sensitivity=sensitivity,
|
|
718
719
|
exclusion_windows=exclusion_windows,
|
|
719
720
|
training_data_lookback_days=training_data_lookback_days,
|
|
720
|
-
incident_behavior=incident_behavior,
|
|
721
|
-
detection_mechanism=detection_mechanism,
|
|
722
721
|
)
|
|
723
722
|
# Then initialize the parent class
|
|
724
723
|
_AssertionPublic.__init__(
|
|
@@ -727,6 +726,8 @@ class SmartVolumeAssertion(_HasSchedule, _HasSmartFunctionality, _AssertionPubli
|
|
|
727
726
|
dataset_urn=dataset_urn,
|
|
728
727
|
display_name=display_name,
|
|
729
728
|
mode=mode,
|
|
729
|
+
incident_behavior=incident_behavior,
|
|
730
|
+
detection_mechanism=detection_mechanism,
|
|
730
731
|
created_by=created_by,
|
|
731
732
|
created_at=created_at,
|
|
732
733
|
updated_by=updated_by,
|
|
@@ -760,8 +761,158 @@ class SmartVolumeAssertion(_HasSchedule, _HasSmartFunctionality, _AssertionPubli
|
|
|
760
761
|
)
|
|
761
762
|
|
|
762
763
|
|
|
764
|
+
class FreshnessAssertion(_HasSchedule, _AssertionPublic):
|
|
765
|
+
"""
|
|
766
|
+
A class that represents a freshness assertion.
|
|
767
|
+
"""
|
|
768
|
+
|
|
769
|
+
def __init__(
|
|
770
|
+
self,
|
|
771
|
+
*,
|
|
772
|
+
urn: AssertionUrn,
|
|
773
|
+
dataset_urn: DatasetUrn,
|
|
774
|
+
display_name: str,
|
|
775
|
+
mode: AssertionMode,
|
|
776
|
+
schedule: models.CronScheduleClass,
|
|
777
|
+
freshness_schedule_check_type: Union[
|
|
778
|
+
str, models.FreshnessAssertionScheduleTypeClass
|
|
779
|
+
],
|
|
780
|
+
lookback_window: Optional[TimeWindowSizeInputTypes],
|
|
781
|
+
tags: list[TagUrn],
|
|
782
|
+
incident_behavior: list[AssertionIncidentBehavior],
|
|
783
|
+
detection_mechanism: Optional[
|
|
784
|
+
_DetectionMechanismTypes
|
|
785
|
+
] = DEFAULT_DETECTION_MECHANISM,
|
|
786
|
+
created_by: Optional[CorpUserUrn] = None,
|
|
787
|
+
created_at: Union[datetime, None] = None,
|
|
788
|
+
updated_by: Optional[CorpUserUrn] = None,
|
|
789
|
+
updated_at: Optional[datetime] = None,
|
|
790
|
+
):
|
|
791
|
+
"""
|
|
792
|
+
Initialize a freshness assertion.
|
|
793
|
+
|
|
794
|
+
Note: Values can be accessed, but not set on the assertion object.
|
|
795
|
+
To update an assertion, use the `upsert_*` method.
|
|
796
|
+
Args:
|
|
797
|
+
urn: The urn of the assertion.
|
|
798
|
+
dataset_urn: The urn of the dataset that the assertion is for.
|
|
799
|
+
display_name: The display name of the assertion.
|
|
800
|
+
mode: The mode of the assertion (active, inactive).
|
|
801
|
+
schedule: The schedule of the assertion.
|
|
802
|
+
freshness_schedule_check_type: The type of freshness schedule check to be used for the assertion.
|
|
803
|
+
lookback_window: The lookback window to be used for the assertion.
|
|
804
|
+
tags: The tags applied to the assertion.
|
|
805
|
+
incident_behavior: Whether to raise or resolve an incident when the assertion fails / passes.
|
|
806
|
+
detection_mechanism: The detection mechanism of the assertion.
|
|
807
|
+
created_by: The urn of the user that created the assertion.
|
|
808
|
+
created_at: The timestamp of when the assertion was created.
|
|
809
|
+
updated_by: The urn of the user that updated the assertion.
|
|
810
|
+
updated_at: The timestamp of when the assertion was updated.
|
|
811
|
+
"""
|
|
812
|
+
_HasSchedule.__init__(self, schedule=schedule)
|
|
813
|
+
_AssertionPublic.__init__(
|
|
814
|
+
self,
|
|
815
|
+
urn=urn,
|
|
816
|
+
dataset_urn=dataset_urn,
|
|
817
|
+
display_name=display_name,
|
|
818
|
+
mode=mode,
|
|
819
|
+
incident_behavior=incident_behavior,
|
|
820
|
+
detection_mechanism=detection_mechanism,
|
|
821
|
+
created_by=created_by,
|
|
822
|
+
created_at=created_at,
|
|
823
|
+
updated_by=updated_by,
|
|
824
|
+
updated_at=updated_at,
|
|
825
|
+
tags=tags,
|
|
826
|
+
)
|
|
827
|
+
self._freshness_schedule_check_type = freshness_schedule_check_type
|
|
828
|
+
self._lookback_window = lookback_window
|
|
829
|
+
|
|
830
|
+
@property
|
|
831
|
+
def freshness_schedule_check_type(
|
|
832
|
+
self,
|
|
833
|
+
) -> Union[str, models.FreshnessAssertionScheduleTypeClass]:
|
|
834
|
+
return self._freshness_schedule_check_type
|
|
835
|
+
|
|
836
|
+
@property
|
|
837
|
+
def lookback_window(self) -> Optional[TimeWindowSizeInputTypes]:
|
|
838
|
+
return self._lookback_window
|
|
839
|
+
|
|
840
|
+
@staticmethod
|
|
841
|
+
def _get_freshness_schedule_check_type(
|
|
842
|
+
assertion: Assertion,
|
|
843
|
+
) -> Union[str, models.FreshnessAssertionScheduleTypeClass]:
|
|
844
|
+
if assertion.info is None:
|
|
845
|
+
raise SDKNotYetSupportedError(
|
|
846
|
+
f"Assertion {assertion.urn} does not have a freshness assertion info, which is not supported"
|
|
847
|
+
)
|
|
848
|
+
if isinstance(assertion.info, models.FreshnessAssertionInfoClass):
|
|
849
|
+
if assertion.info.schedule is None:
|
|
850
|
+
raise SDKNotYetSupportedError(
|
|
851
|
+
f"Traditional freshness assertion {assertion.urn} does not have a schedule, which is not supported"
|
|
852
|
+
)
|
|
853
|
+
return assertion.info.schedule.type
|
|
854
|
+
else:
|
|
855
|
+
raise SDKNotYetSupportedError(
|
|
856
|
+
f"Assertion {assertion.urn} is not a freshness assertion"
|
|
857
|
+
)
|
|
858
|
+
|
|
859
|
+
@staticmethod
|
|
860
|
+
def _get_lookback_window(
|
|
861
|
+
assertion: Assertion,
|
|
862
|
+
) -> Optional[models.FixedIntervalScheduleClass]:
|
|
863
|
+
if assertion.info is None:
|
|
864
|
+
raise SDKNotYetSupportedError(
|
|
865
|
+
f"Assertion {assertion.urn} does not have a freshness assertion info, which is not supported"
|
|
866
|
+
)
|
|
867
|
+
if isinstance(assertion.info, models.FreshnessAssertionInfoClass):
|
|
868
|
+
if assertion.info.schedule is None:
|
|
869
|
+
raise SDKNotYetSupportedError(
|
|
870
|
+
f"Traditional freshness assertion {assertion.urn} does not have a schedule, which is not supported"
|
|
871
|
+
)
|
|
872
|
+
return assertion.info.schedule.fixedInterval
|
|
873
|
+
else:
|
|
874
|
+
raise SDKNotYetSupportedError(
|
|
875
|
+
f"Assertion {assertion.urn} is not a freshness assertion"
|
|
876
|
+
)
|
|
877
|
+
|
|
878
|
+
@classmethod
|
|
879
|
+
def _from_entities(cls, assertion: Assertion, monitor: Monitor) -> Self:
|
|
880
|
+
"""
|
|
881
|
+
Create a freshness assertion from the assertion and monitor entities.
|
|
882
|
+
"""
|
|
883
|
+
return cls(
|
|
884
|
+
urn=assertion.urn,
|
|
885
|
+
dataset_urn=assertion.dataset,
|
|
886
|
+
display_name=assertion.description or "",
|
|
887
|
+
mode=cls._get_mode(monitor),
|
|
888
|
+
schedule=cls._get_schedule(monitor),
|
|
889
|
+
freshness_schedule_check_type=cls._get_freshness_schedule_check_type(
|
|
890
|
+
assertion
|
|
891
|
+
),
|
|
892
|
+
lookback_window=cls._get_lookback_window(assertion),
|
|
893
|
+
incident_behavior=cls._get_incident_behavior(assertion),
|
|
894
|
+
detection_mechanism=cls._get_detection_mechanism(assertion, monitor),
|
|
895
|
+
created_by=cls._get_created_by(assertion),
|
|
896
|
+
created_at=cls._get_created_at(assertion),
|
|
897
|
+
updated_by=cls._get_updated_by(assertion),
|
|
898
|
+
updated_at=cls._get_updated_at(assertion),
|
|
899
|
+
tags=cls._get_tags(assertion),
|
|
900
|
+
)
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
class SmartColumnMetricAssertion(_HasSmartFunctionality, _AssertionPublic):
|
|
904
|
+
"""
|
|
905
|
+
A class that represents a smart column metric assertion.
|
|
906
|
+
"""
|
|
907
|
+
|
|
908
|
+
def __init__(self) -> None:
|
|
909
|
+
raise NotImplementedError("SmartColumnMetricAssertion is not implemented yet")
|
|
910
|
+
|
|
911
|
+
|
|
763
912
|
AssertionTypes = Union[
|
|
764
913
|
SmartFreshnessAssertion,
|
|
765
914
|
SmartVolumeAssertion,
|
|
915
|
+
FreshnessAssertion,
|
|
916
|
+
SmartColumnMetricAssertion,
|
|
766
917
|
# TODO: Add other assertion types here as we add them.
|
|
767
918
|
]
|
|
File without changes
|