truthound-dashboard 1.4.4__py3-none-any.whl → 1.5.1__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.
- truthound_dashboard/api/alerts.py +75 -86
- truthound_dashboard/api/anomaly.py +7 -13
- truthound_dashboard/api/cross_alerts.py +38 -52
- truthound_dashboard/api/drift.py +49 -59
- truthound_dashboard/api/drift_monitor.py +234 -79
- truthound_dashboard/api/enterprise_sampling.py +498 -0
- truthound_dashboard/api/history.py +57 -5
- truthound_dashboard/api/lineage.py +3 -48
- truthound_dashboard/api/maintenance.py +104 -49
- truthound_dashboard/api/mask.py +1 -2
- truthound_dashboard/api/middleware.py +2 -1
- truthound_dashboard/api/model_monitoring.py +435 -311
- truthound_dashboard/api/notifications.py +227 -191
- truthound_dashboard/api/notifications_advanced.py +21 -20
- truthound_dashboard/api/observability.py +586 -0
- truthound_dashboard/api/plugins.py +2 -433
- truthound_dashboard/api/profile.py +199 -37
- truthound_dashboard/api/quality_reporter.py +701 -0
- truthound_dashboard/api/reports.py +7 -16
- truthound_dashboard/api/router.py +66 -0
- truthound_dashboard/api/rule_suggestions.py +5 -5
- truthound_dashboard/api/scan.py +17 -19
- truthound_dashboard/api/schedules.py +85 -50
- truthound_dashboard/api/schema_evolution.py +6 -6
- truthound_dashboard/api/schema_watcher.py +667 -0
- truthound_dashboard/api/sources.py +98 -27
- truthound_dashboard/api/tiering.py +1323 -0
- truthound_dashboard/api/triggers.py +14 -11
- truthound_dashboard/api/validations.py +12 -11
- truthound_dashboard/api/versioning.py +1 -6
- truthound_dashboard/core/__init__.py +129 -3
- truthound_dashboard/core/actions/__init__.py +62 -0
- truthound_dashboard/core/actions/custom.py +426 -0
- truthound_dashboard/core/actions/notifications.py +910 -0
- truthound_dashboard/core/actions/storage.py +472 -0
- truthound_dashboard/core/actions/webhook.py +281 -0
- truthound_dashboard/core/anomaly.py +262 -67
- truthound_dashboard/core/anomaly_explainer.py +4 -3
- truthound_dashboard/core/backends/__init__.py +67 -0
- truthound_dashboard/core/backends/base.py +299 -0
- truthound_dashboard/core/backends/errors.py +191 -0
- truthound_dashboard/core/backends/factory.py +423 -0
- truthound_dashboard/core/backends/mock_backend.py +451 -0
- truthound_dashboard/core/backends/truthound_backend.py +718 -0
- truthound_dashboard/core/checkpoint/__init__.py +87 -0
- truthound_dashboard/core/checkpoint/adapters.py +814 -0
- truthound_dashboard/core/checkpoint/checkpoint.py +491 -0
- truthound_dashboard/core/checkpoint/runner.py +270 -0
- truthound_dashboard/core/connections.py +645 -23
- truthound_dashboard/core/converters/__init__.py +14 -0
- truthound_dashboard/core/converters/truthound.py +620 -0
- truthound_dashboard/core/cross_alerts.py +540 -320
- truthound_dashboard/core/datasource_factory.py +1672 -0
- truthound_dashboard/core/drift_monitor.py +216 -20
- truthound_dashboard/core/enterprise_sampling.py +1291 -0
- truthound_dashboard/core/interfaces/__init__.py +225 -0
- truthound_dashboard/core/interfaces/actions.py +652 -0
- truthound_dashboard/core/interfaces/base.py +247 -0
- truthound_dashboard/core/interfaces/checkpoint.py +676 -0
- truthound_dashboard/core/interfaces/protocols.py +664 -0
- truthound_dashboard/core/interfaces/reporters.py +650 -0
- truthound_dashboard/core/interfaces/routing.py +646 -0
- truthound_dashboard/core/interfaces/triggers.py +619 -0
- truthound_dashboard/core/lineage.py +407 -71
- truthound_dashboard/core/model_monitoring.py +431 -3
- truthound_dashboard/core/notifications/base.py +4 -0
- truthound_dashboard/core/notifications/channels.py +501 -1203
- truthound_dashboard/core/notifications/deduplication/__init__.py +81 -115
- truthound_dashboard/core/notifications/deduplication/service.py +131 -348
- truthound_dashboard/core/notifications/dispatcher.py +202 -11
- truthound_dashboard/core/notifications/escalation/__init__.py +119 -106
- truthound_dashboard/core/notifications/escalation/engine.py +168 -358
- truthound_dashboard/core/notifications/routing/__init__.py +88 -128
- truthound_dashboard/core/notifications/routing/engine.py +90 -317
- truthound_dashboard/core/notifications/stats_aggregator.py +246 -1
- truthound_dashboard/core/notifications/throttling/__init__.py +67 -50
- truthound_dashboard/core/notifications/throttling/builder.py +117 -255
- truthound_dashboard/core/notifications/truthound_adapter.py +842 -0
- truthound_dashboard/core/phase5/collaboration.py +1 -1
- truthound_dashboard/core/plugins/lifecycle/__init__.py +0 -13
- truthound_dashboard/core/quality_reporter.py +1359 -0
- truthound_dashboard/core/report_history.py +0 -6
- truthound_dashboard/core/reporters/__init__.py +175 -14
- truthound_dashboard/core/reporters/adapters.py +943 -0
- truthound_dashboard/core/reporters/base.py +0 -3
- truthound_dashboard/core/reporters/builtin/__init__.py +18 -0
- truthound_dashboard/core/reporters/builtin/csv_reporter.py +111 -0
- truthound_dashboard/core/reporters/builtin/html_reporter.py +270 -0
- truthound_dashboard/core/reporters/builtin/json_reporter.py +127 -0
- truthound_dashboard/core/reporters/compat.py +266 -0
- truthound_dashboard/core/reporters/csv_reporter.py +2 -35
- truthound_dashboard/core/reporters/factory.py +526 -0
- truthound_dashboard/core/reporters/interfaces.py +745 -0
- truthound_dashboard/core/reporters/registry.py +1 -10
- truthound_dashboard/core/scheduler.py +165 -0
- truthound_dashboard/core/schema_evolution.py +3 -3
- truthound_dashboard/core/schema_watcher.py +1528 -0
- truthound_dashboard/core/services.py +595 -76
- truthound_dashboard/core/store_manager.py +810 -0
- truthound_dashboard/core/streaming_anomaly.py +169 -4
- truthound_dashboard/core/tiering.py +1309 -0
- truthound_dashboard/core/triggers/evaluators.py +178 -8
- truthound_dashboard/core/truthound_adapter.py +2620 -197
- truthound_dashboard/core/unified_alerts.py +23 -20
- truthound_dashboard/db/__init__.py +8 -0
- truthound_dashboard/db/database.py +8 -2
- truthound_dashboard/db/models.py +944 -25
- truthound_dashboard/db/repository.py +2 -0
- truthound_dashboard/main.py +15 -0
- truthound_dashboard/schemas/__init__.py +177 -16
- truthound_dashboard/schemas/base.py +44 -23
- truthound_dashboard/schemas/collaboration.py +19 -6
- truthound_dashboard/schemas/cross_alerts.py +19 -3
- truthound_dashboard/schemas/drift.py +61 -55
- truthound_dashboard/schemas/drift_monitor.py +67 -23
- truthound_dashboard/schemas/enterprise_sampling.py +653 -0
- truthound_dashboard/schemas/lineage.py +0 -33
- truthound_dashboard/schemas/mask.py +10 -8
- truthound_dashboard/schemas/model_monitoring.py +89 -10
- truthound_dashboard/schemas/notifications_advanced.py +13 -0
- truthound_dashboard/schemas/observability.py +453 -0
- truthound_dashboard/schemas/plugins.py +0 -280
- truthound_dashboard/schemas/profile.py +154 -247
- truthound_dashboard/schemas/quality_reporter.py +403 -0
- truthound_dashboard/schemas/reports.py +2 -2
- truthound_dashboard/schemas/rule_suggestion.py +8 -1
- truthound_dashboard/schemas/scan.py +4 -24
- truthound_dashboard/schemas/schedule.py +11 -3
- truthound_dashboard/schemas/schema_watcher.py +727 -0
- truthound_dashboard/schemas/source.py +17 -2
- truthound_dashboard/schemas/tiering.py +822 -0
- truthound_dashboard/schemas/triggers.py +16 -0
- truthound_dashboard/schemas/unified_alerts.py +7 -0
- truthound_dashboard/schemas/validation.py +0 -13
- truthound_dashboard/schemas/validators/base.py +41 -21
- truthound_dashboard/schemas/validators/business_rule_validators.py +244 -0
- truthound_dashboard/schemas/validators/localization_validators.py +273 -0
- truthound_dashboard/schemas/validators/ml_feature_validators.py +308 -0
- truthound_dashboard/schemas/validators/profiling_validators.py +275 -0
- truthound_dashboard/schemas/validators/referential_validators.py +312 -0
- truthound_dashboard/schemas/validators/registry.py +93 -8
- truthound_dashboard/schemas/validators/timeseries_validators.py +389 -0
- truthound_dashboard/schemas/versioning.py +1 -6
- truthound_dashboard/static/index.html +2 -2
- truthound_dashboard-1.5.1.dist-info/METADATA +312 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/RECORD +149 -148
- truthound_dashboard/core/plugins/hooks/__init__.py +0 -63
- truthound_dashboard/core/plugins/hooks/decorators.py +0 -367
- truthound_dashboard/core/plugins/hooks/manager.py +0 -403
- truthound_dashboard/core/plugins/hooks/protocols.py +0 -265
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +0 -584
- truthound_dashboard/core/reporters/junit_reporter.py +0 -233
- truthound_dashboard/core/reporters/markdown_reporter.py +0 -207
- truthound_dashboard/core/reporters/pdf_reporter.py +0 -209
- truthound_dashboard/static/assets/_baseUniq-BcrSP13d.js +0 -1
- truthound_dashboard/static/assets/arc-DlYjKwIL.js +0 -1
- truthound_dashboard/static/assets/architectureDiagram-VXUJARFQ-Bb2drbQM.js +0 -36
- truthound_dashboard/static/assets/blockDiagram-VD42YOAC-BlsPG1CH.js +0 -122
- truthound_dashboard/static/assets/c4Diagram-YG6GDRKO-B9JdUoaC.js +0 -10
- truthound_dashboard/static/assets/channel-Q6mHF1Hd.js +0 -1
- truthound_dashboard/static/assets/chunk-4BX2VUAB-DmyoPVuJ.js +0 -1
- truthound_dashboard/static/assets/chunk-55IACEB6-Bcz6Siv8.js +0 -1
- truthound_dashboard/static/assets/chunk-B4BG7PRW-Br3G5Rum.js +0 -165
- truthound_dashboard/static/assets/chunk-DI55MBZ5-DuM9c23u.js +0 -220
- truthound_dashboard/static/assets/chunk-FMBD7UC4-DNU-5mvT.js +0 -15
- truthound_dashboard/static/assets/chunk-QN33PNHL-Im2yNcmS.js +0 -1
- truthound_dashboard/static/assets/chunk-QZHKN3VN-kZr8XFm1.js +0 -1
- truthound_dashboard/static/assets/chunk-TZMSLE5B-Q__360q_.js +0 -1
- truthound_dashboard/static/assets/classDiagram-2ON5EDUG-vtixxUyK.js +0 -1
- truthound_dashboard/static/assets/classDiagram-v2-WZHVMYZB-vtixxUyK.js +0 -1
- truthound_dashboard/static/assets/clone-BOt2LwD0.js +0 -1
- truthound_dashboard/static/assets/cose-bilkent-S5V4N54A-CBDw6iac.js +0 -1
- truthound_dashboard/static/assets/dagre-6UL2VRFP-XdKqmmY9.js +0 -4
- truthound_dashboard/static/assets/diagram-PSM6KHXK-DAZ8nx9V.js +0 -24
- truthound_dashboard/static/assets/diagram-QEK2KX5R-BRvDTbGD.js +0 -43
- truthound_dashboard/static/assets/diagram-S2PKOQOG-bQcczUkl.js +0 -24
- truthound_dashboard/static/assets/erDiagram-Q2GNP2WA-DPje7VMN.js +0 -60
- truthound_dashboard/static/assets/flowDiagram-NV44I4VS-B7BVtFVS.js +0 -162
- truthound_dashboard/static/assets/ganttDiagram-JELNMOA3-D6WKSS7U.js +0 -267
- truthound_dashboard/static/assets/gitGraphDiagram-NY62KEGX-D3vtVd3y.js +0 -65
- truthound_dashboard/static/assets/graph-BKgNKZVp.js +0 -1
- truthound_dashboard/static/assets/index-C6JSrkHo.css +0 -1
- truthound_dashboard/static/assets/index-DkU82VsU.js +0 -1800
- truthound_dashboard/static/assets/infoDiagram-WHAUD3N6-DnNCT429.js +0 -2
- truthound_dashboard/static/assets/journeyDiagram-XKPGCS4Q-DGiMozqS.js +0 -139
- truthound_dashboard/static/assets/kanban-definition-3W4ZIXB7-BV2gUgli.js +0 -89
- truthound_dashboard/static/assets/katex-Cu_Erd72.js +0 -261
- truthound_dashboard/static/assets/layout-DI2MfQ5G.js +0 -1
- truthound_dashboard/static/assets/min-DYdgXVcT.js +0 -1
- truthound_dashboard/static/assets/mindmap-definition-VGOIOE7T-C7x4ruxz.js +0 -68
- truthound_dashboard/static/assets/pieDiagram-ADFJNKIX-CAJaAB9f.js +0 -30
- truthound_dashboard/static/assets/quadrantDiagram-AYHSOK5B-DeqwDI46.js +0 -7
- truthound_dashboard/static/assets/requirementDiagram-UZGBJVZJ-e3XDpZIM.js +0 -64
- truthound_dashboard/static/assets/sankeyDiagram-TZEHDZUN-CNnAv5Ux.js +0 -10
- truthound_dashboard/static/assets/sequenceDiagram-WL72ISMW-Dsne-Of3.js +0 -145
- truthound_dashboard/static/assets/stateDiagram-FKZM4ZOC-Ee0sQXyb.js +0 -1
- truthound_dashboard/static/assets/stateDiagram-v2-4FDKWEC3-B26KqW_W.js +0 -1
- truthound_dashboard/static/assets/timeline-definition-IT6M3QCI-DZYi2yl3.js +0 -61
- truthound_dashboard/static/assets/treemap-KMMF4GRG-CY3f8In2.js +0 -128
- truthound_dashboard/static/assets/unmerged_dictionaries-Dd7xcPWG.js +0 -1
- truthound_dashboard/static/assets/xychartDiagram-PRI3JC2R-CS7fydZZ.js +0 -7
- truthound_dashboard-1.4.4.dist-info/METADATA +0 -507
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
"""Trigger evaluator implementations.
|
|
2
2
|
|
|
3
|
-
Provides concrete implementations for all trigger types
|
|
3
|
+
Provides concrete implementations for all trigger types using truthound.checkpoint.triggers
|
|
4
|
+
when available, with fallback to APScheduler-based implementation:
|
|
4
5
|
- CronTrigger: Cron expression based scheduling
|
|
5
6
|
- IntervalTrigger: Fixed time interval scheduling
|
|
6
|
-
- DataChangeTrigger: Profile-based change detection
|
|
7
|
+
- DataChangeTrigger: Profile-based change detection (FileWatchTrigger in truthound)
|
|
7
8
|
- CompositeTrigger: Combine multiple triggers
|
|
8
9
|
- EventTrigger: Respond to system events
|
|
9
10
|
- ManualTrigger: API-only execution
|
|
11
|
+
- WebhookTrigger: External webhook triggers
|
|
12
|
+
|
|
13
|
+
truthound.checkpoint.triggers provides:
|
|
14
|
+
- ScheduleTrigger: Time-based scheduling
|
|
15
|
+
- CronTrigger: Cron expression scheduling
|
|
16
|
+
- EventTrigger: Event-driven triggers
|
|
17
|
+
- FileWatchTrigger: File/data change monitoring
|
|
10
18
|
"""
|
|
11
19
|
|
|
12
20
|
from __future__ import annotations
|
|
@@ -27,11 +35,28 @@ from .base import (
|
|
|
27
35
|
|
|
28
36
|
logger = logging.getLogger(__name__)
|
|
29
37
|
|
|
38
|
+
# Try to import truthound triggers
|
|
39
|
+
_TRUTHOUND_TRIGGERS_AVAILABLE = False
|
|
40
|
+
try:
|
|
41
|
+
from truthound.checkpoint.triggers import (
|
|
42
|
+
ScheduleTrigger as TruthoundScheduleTrigger,
|
|
43
|
+
CronTrigger as TruthoundCronTrigger,
|
|
44
|
+
EventTrigger as TruthoundEventTrigger,
|
|
45
|
+
FileWatchTrigger as TruthoundFileWatchTrigger,
|
|
46
|
+
)
|
|
47
|
+
_TRUTHOUND_TRIGGERS_AVAILABLE = True
|
|
48
|
+
logger.info("truthound.checkpoint.triggers available")
|
|
49
|
+
except ImportError:
|
|
50
|
+
logger.debug("truthound.checkpoint.triggers not available, using APScheduler fallback")
|
|
51
|
+
|
|
30
52
|
|
|
31
53
|
@TriggerRegistry.register("cron")
|
|
32
54
|
class CronTrigger(BaseTrigger):
|
|
33
55
|
"""Cron expression based trigger.
|
|
34
56
|
|
|
57
|
+
Uses truthound.checkpoint.triggers.CronTrigger when available,
|
|
58
|
+
falls back to APScheduler's CronTrigger.
|
|
59
|
+
|
|
35
60
|
Uses standard cron format: minute hour day month weekday
|
|
36
61
|
|
|
37
62
|
Config:
|
|
@@ -39,13 +64,35 @@ class CronTrigger(BaseTrigger):
|
|
|
39
64
|
timezone: Optional timezone (default: UTC)
|
|
40
65
|
"""
|
|
41
66
|
|
|
67
|
+
def __init__(self, config: dict[str, Any]) -> None:
|
|
68
|
+
"""Initialize cron trigger."""
|
|
69
|
+
super().__init__(config)
|
|
70
|
+
self._truthound_trigger = None
|
|
71
|
+
self._init_truthound_trigger()
|
|
72
|
+
|
|
73
|
+
def _init_truthound_trigger(self) -> None:
|
|
74
|
+
"""Initialize truthound trigger if available."""
|
|
75
|
+
if _TRUTHOUND_TRIGGERS_AVAILABLE:
|
|
76
|
+
try:
|
|
77
|
+
expression = self.config.get("expression", "0 * * * *")
|
|
78
|
+
self._truthound_trigger = TruthoundCronTrigger(expression=expression)
|
|
79
|
+
logger.debug(f"Using truthound CronTrigger: {expression}")
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.warning(f"Failed to create truthound CronTrigger: {e}")
|
|
82
|
+
self._truthound_trigger = None
|
|
83
|
+
|
|
42
84
|
def _validate_config(self) -> None:
|
|
43
85
|
"""Validate cron configuration."""
|
|
44
86
|
expression = self.config.get("expression")
|
|
45
87
|
if not expression:
|
|
46
88
|
raise ValueError("Cron trigger requires 'expression' field")
|
|
47
89
|
|
|
48
|
-
# Validate
|
|
90
|
+
# Validate using truthound or APScheduler
|
|
91
|
+
if self._truthound_trigger is not None:
|
|
92
|
+
# truthound already validated in _init_truthound_trigger
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# Fallback validation with APScheduler
|
|
49
96
|
try:
|
|
50
97
|
APCronTrigger.from_crontab(expression)
|
|
51
98
|
except Exception as e:
|
|
@@ -54,10 +101,37 @@ class CronTrigger(BaseTrigger):
|
|
|
54
101
|
async def evaluate(self, context: TriggerContext) -> TriggerEvaluation:
|
|
55
102
|
"""Evaluate if cron trigger should fire.
|
|
56
103
|
|
|
57
|
-
|
|
58
|
-
since the last run.
|
|
104
|
+
Uses truthound trigger evaluation when available.
|
|
59
105
|
"""
|
|
60
106
|
expression = self.config.get("expression")
|
|
107
|
+
|
|
108
|
+
# Try truthound evaluation first
|
|
109
|
+
if self._truthound_trigger is not None:
|
|
110
|
+
try:
|
|
111
|
+
should_fire = self._truthound_trigger.should_fire(
|
|
112
|
+
current_time=context.current_time,
|
|
113
|
+
last_run_at=context.last_run_at,
|
|
114
|
+
)
|
|
115
|
+
next_fire = self._truthound_trigger.get_next_fire_time(context.current_time)
|
|
116
|
+
|
|
117
|
+
return TriggerEvaluation(
|
|
118
|
+
should_trigger=should_fire,
|
|
119
|
+
reason=(
|
|
120
|
+
f"Scheduled time reached (truthound)"
|
|
121
|
+
if should_fire
|
|
122
|
+
else f"Waiting for scheduled time ({next_fire.isoformat() if next_fire else 'unknown'})"
|
|
123
|
+
),
|
|
124
|
+
next_evaluation_at=next_fire if not should_fire else None,
|
|
125
|
+
details={
|
|
126
|
+
"expression": expression,
|
|
127
|
+
"next_fire_time": next_fire.isoformat() if next_fire else None,
|
|
128
|
+
"provider": "truthound",
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
except Exception as e:
|
|
132
|
+
logger.warning(f"truthound CronTrigger evaluation failed: {e}")
|
|
133
|
+
|
|
134
|
+
# Fallback to APScheduler
|
|
61
135
|
trigger = APCronTrigger.from_crontab(expression)
|
|
62
136
|
|
|
63
137
|
# Get next fire time from last run (or from epoch if never run)
|
|
@@ -83,6 +157,7 @@ class CronTrigger(BaseTrigger):
|
|
|
83
157
|
details={
|
|
84
158
|
"expression": expression,
|
|
85
159
|
"next_fire_time": next_fire.isoformat(),
|
|
160
|
+
"provider": "apscheduler",
|
|
86
161
|
},
|
|
87
162
|
)
|
|
88
163
|
|
|
@@ -90,6 +165,14 @@ class CronTrigger(BaseTrigger):
|
|
|
90
165
|
self, context: TriggerContext
|
|
91
166
|
) -> datetime | None:
|
|
92
167
|
"""Get next cron fire time."""
|
|
168
|
+
# Try truthound first
|
|
169
|
+
if self._truthound_trigger is not None:
|
|
170
|
+
try:
|
|
171
|
+
return self._truthound_trigger.get_next_fire_time(context.current_time)
|
|
172
|
+
except Exception:
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
# Fallback to APScheduler
|
|
93
176
|
expression = self.config.get("expression")
|
|
94
177
|
try:
|
|
95
178
|
trigger = APCronTrigger.from_crontab(expression)
|
|
@@ -189,6 +272,9 @@ class IntervalTrigger(BaseTrigger):
|
|
|
189
272
|
class DataChangeTrigger(BaseTrigger):
|
|
190
273
|
"""Data change detection trigger.
|
|
191
274
|
|
|
275
|
+
Uses truthound.checkpoint.triggers.FileWatchTrigger when available
|
|
276
|
+
for enhanced file/data monitoring with change detection.
|
|
277
|
+
|
|
192
278
|
Triggers when profile metrics change by more than a threshold.
|
|
193
279
|
|
|
194
280
|
Config:
|
|
@@ -199,6 +285,25 @@ class DataChangeTrigger(BaseTrigger):
|
|
|
199
285
|
|
|
200
286
|
DEFAULT_METRICS = ["row_count", "null_percentage", "distinct_count"]
|
|
201
287
|
|
|
288
|
+
def __init__(self, config: dict[str, Any]) -> None:
|
|
289
|
+
"""Initialize data change trigger."""
|
|
290
|
+
super().__init__(config)
|
|
291
|
+
self._truthound_trigger = None
|
|
292
|
+
self._init_truthound_trigger()
|
|
293
|
+
|
|
294
|
+
def _init_truthound_trigger(self) -> None:
|
|
295
|
+
"""Initialize truthound FileWatchTrigger if available."""
|
|
296
|
+
if _TRUTHOUND_TRIGGERS_AVAILABLE:
|
|
297
|
+
try:
|
|
298
|
+
self._truthound_trigger = TruthoundFileWatchTrigger(
|
|
299
|
+
change_threshold=self.config.get("change_threshold", 0.05),
|
|
300
|
+
metrics=self.config.get("metrics", self.DEFAULT_METRICS),
|
|
301
|
+
)
|
|
302
|
+
logger.debug("Using truthound FileWatchTrigger for data change detection")
|
|
303
|
+
except Exception as e:
|
|
304
|
+
logger.warning(f"Failed to create truthound FileWatchTrigger: {e}")
|
|
305
|
+
self._truthound_trigger = None
|
|
306
|
+
|
|
202
307
|
def _validate_config(self) -> None:
|
|
203
308
|
"""Validate data change configuration."""
|
|
204
309
|
threshold = self.config.get("change_threshold", 0.05)
|
|
@@ -208,12 +313,34 @@ class DataChangeTrigger(BaseTrigger):
|
|
|
208
313
|
async def evaluate(self, context: TriggerContext) -> TriggerEvaluation:
|
|
209
314
|
"""Evaluate if data has changed enough to trigger.
|
|
210
315
|
|
|
316
|
+
Uses truthound FileWatchTrigger when available for enhanced detection.
|
|
211
317
|
Compares current profile against baseline and checks if
|
|
212
318
|
any monitored metrics have changed beyond the threshold.
|
|
213
319
|
"""
|
|
214
320
|
threshold = self.config.get("change_threshold", 0.05)
|
|
215
321
|
metrics = self.config.get("metrics", self.DEFAULT_METRICS)
|
|
216
322
|
|
|
323
|
+
# Try truthound evaluation first
|
|
324
|
+
if self._truthound_trigger is not None and context.profile_data and context.baseline_profile:
|
|
325
|
+
try:
|
|
326
|
+
result = self._truthound_trigger.evaluate_change(
|
|
327
|
+
current_profile=context.profile_data,
|
|
328
|
+
baseline_profile=context.baseline_profile,
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
return TriggerEvaluation(
|
|
332
|
+
should_trigger=result.should_trigger,
|
|
333
|
+
reason=result.reason,
|
|
334
|
+
details={
|
|
335
|
+
**result.details,
|
|
336
|
+
"provider": "truthound",
|
|
337
|
+
},
|
|
338
|
+
confidence=result.confidence,
|
|
339
|
+
)
|
|
340
|
+
except Exception as e:
|
|
341
|
+
logger.warning(f"truthound FileWatchTrigger evaluation failed: {e}")
|
|
342
|
+
|
|
343
|
+
# Fallback to manual implementation
|
|
217
344
|
# Need both profiles to compare
|
|
218
345
|
if context.profile_data is None:
|
|
219
346
|
return TriggerEvaluation(
|
|
@@ -272,6 +399,7 @@ class DataChangeTrigger(BaseTrigger):
|
|
|
272
399
|
"max_change": max_change,
|
|
273
400
|
"changes": changes,
|
|
274
401
|
"triggered_metrics": triggered_metrics,
|
|
402
|
+
"provider": "manual",
|
|
275
403
|
},
|
|
276
404
|
confidence=max_change if should_trigger else 1.0 - max_change,
|
|
277
405
|
)
|
|
@@ -384,6 +512,9 @@ class CompositeTrigger(BaseTrigger):
|
|
|
384
512
|
class EventTrigger(BaseTrigger):
|
|
385
513
|
"""Event-based trigger.
|
|
386
514
|
|
|
515
|
+
Uses truthound.checkpoint.triggers.EventTrigger when available
|
|
516
|
+
for enhanced event matching and filtering.
|
|
517
|
+
|
|
387
518
|
Triggers in response to specific system events.
|
|
388
519
|
|
|
389
520
|
Config:
|
|
@@ -401,6 +532,25 @@ class EventTrigger(BaseTrigger):
|
|
|
401
532
|
"source_updated",
|
|
402
533
|
}
|
|
403
534
|
|
|
535
|
+
def __init__(self, config: dict[str, Any]) -> None:
|
|
536
|
+
"""Initialize event trigger."""
|
|
537
|
+
super().__init__(config)
|
|
538
|
+
self._truthound_trigger = None
|
|
539
|
+
self._init_truthound_trigger()
|
|
540
|
+
|
|
541
|
+
def _init_truthound_trigger(self) -> None:
|
|
542
|
+
"""Initialize truthound EventTrigger if available."""
|
|
543
|
+
if _TRUTHOUND_TRIGGERS_AVAILABLE:
|
|
544
|
+
try:
|
|
545
|
+
self._truthound_trigger = TruthoundEventTrigger(
|
|
546
|
+
event_types=self.config.get("event_types", []),
|
|
547
|
+
source_filter=self.config.get("source_filter"),
|
|
548
|
+
)
|
|
549
|
+
logger.debug("Using truthound EventTrigger")
|
|
550
|
+
except Exception as e:
|
|
551
|
+
logger.warning(f"Failed to create truthound EventTrigger: {e}")
|
|
552
|
+
self._truthound_trigger = None
|
|
553
|
+
|
|
404
554
|
def _validate_config(self) -> None:
|
|
405
555
|
"""Validate event configuration."""
|
|
406
556
|
event_types = self.config.get("event_types", [])
|
|
@@ -412,7 +562,10 @@ class EventTrigger(BaseTrigger):
|
|
|
412
562
|
raise ValueError(f"Invalid event types: {invalid_events}")
|
|
413
563
|
|
|
414
564
|
async def evaluate(self, context: TriggerContext) -> TriggerEvaluation:
|
|
415
|
-
"""Evaluate if event matches configured types.
|
|
565
|
+
"""Evaluate if event matches configured types.
|
|
566
|
+
|
|
567
|
+
Uses truthound EventTrigger when available.
|
|
568
|
+
"""
|
|
416
569
|
event_types = set(self.config.get("event_types", []))
|
|
417
570
|
source_filter = self.config.get("source_filter")
|
|
418
571
|
|
|
@@ -423,6 +576,22 @@ class EventTrigger(BaseTrigger):
|
|
|
423
576
|
reason="No event data in context",
|
|
424
577
|
)
|
|
425
578
|
|
|
579
|
+
# Try truthound evaluation first
|
|
580
|
+
if self._truthound_trigger is not None:
|
|
581
|
+
try:
|
|
582
|
+
result = self._truthound_trigger.evaluate(context.event_data)
|
|
583
|
+
return TriggerEvaluation(
|
|
584
|
+
should_trigger=result.should_trigger,
|
|
585
|
+
reason=result.reason,
|
|
586
|
+
details={
|
|
587
|
+
**result.details,
|
|
588
|
+
"provider": "truthound",
|
|
589
|
+
},
|
|
590
|
+
)
|
|
591
|
+
except Exception as e:
|
|
592
|
+
logger.warning(f"truthound EventTrigger evaluation failed: {e}")
|
|
593
|
+
|
|
594
|
+
# Fallback to manual implementation
|
|
426
595
|
event_type = context.event_data.get("type")
|
|
427
596
|
event_source = context.event_data.get("source_id")
|
|
428
597
|
|
|
@@ -431,7 +600,7 @@ class EventTrigger(BaseTrigger):
|
|
|
431
600
|
return TriggerEvaluation(
|
|
432
601
|
should_trigger=False,
|
|
433
602
|
reason=f"Event type '{event_type}' not in configured types",
|
|
434
|
-
details={"event_type": event_type, "configured_types": list(event_types)},
|
|
603
|
+
details={"event_type": event_type, "configured_types": list(event_types), "provider": "manual"},
|
|
435
604
|
)
|
|
436
605
|
|
|
437
606
|
# Check source filter if configured
|
|
@@ -439,7 +608,7 @@ class EventTrigger(BaseTrigger):
|
|
|
439
608
|
return TriggerEvaluation(
|
|
440
609
|
should_trigger=False,
|
|
441
610
|
reason=f"Event source '{event_source}' not in filter",
|
|
442
|
-
details={"event_source": event_source, "filter": source_filter},
|
|
611
|
+
details={"event_source": event_source, "filter": source_filter, "provider": "manual"},
|
|
443
612
|
)
|
|
444
613
|
|
|
445
614
|
return TriggerEvaluation(
|
|
@@ -449,6 +618,7 @@ class EventTrigger(BaseTrigger):
|
|
|
449
618
|
"event_type": event_type,
|
|
450
619
|
"event_source": event_source,
|
|
451
620
|
"event_data": context.event_data,
|
|
621
|
+
"provider": "manual",
|
|
452
622
|
},
|
|
453
623
|
)
|
|
454
624
|
|