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
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""Abstract base class for data quality backends.
|
|
2
|
+
|
|
3
|
+
This module defines the abstract base class that all data quality
|
|
4
|
+
backends must implement. It provides the contract for validation,
|
|
5
|
+
profiling, schema learning, and other data quality operations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from abc import ABC, abstractmethod
|
|
12
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
13
|
+
from functools import partial
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from truthound_dashboard.core.interfaces import DataInput
|
|
17
|
+
|
|
18
|
+
# Import result types from the main adapter (will be moved later)
|
|
19
|
+
from truthound_dashboard.core.truthound_adapter import (
|
|
20
|
+
CheckResult,
|
|
21
|
+
CompareResult,
|
|
22
|
+
GenerateSuiteResult,
|
|
23
|
+
LearnResult,
|
|
24
|
+
MaskResult,
|
|
25
|
+
ProfileResult,
|
|
26
|
+
ScanResult,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BaseDataQualityBackend(ABC):
|
|
31
|
+
"""Abstract base class for data quality backends.
|
|
32
|
+
|
|
33
|
+
This class defines the interface that all data quality backends
|
|
34
|
+
must implement. Concrete implementations (e.g., TruthoundBackend,
|
|
35
|
+
MockBackend) inherit from this class.
|
|
36
|
+
|
|
37
|
+
The backend is responsible for:
|
|
38
|
+
- Running data validations (check)
|
|
39
|
+
- Learning schemas from data (learn)
|
|
40
|
+
- Profiling data (profile)
|
|
41
|
+
- Detecting drift between datasets (compare)
|
|
42
|
+
- Scanning for PII (scan)
|
|
43
|
+
- Masking sensitive data (mask)
|
|
44
|
+
- Generating validation suites (generate_suite)
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
class MyBackend(BaseDataQualityBackend):
|
|
48
|
+
def is_available(self) -> bool:
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
async def check(self, data, **kwargs) -> CheckResult:
|
|
52
|
+
# Custom implementation
|
|
53
|
+
pass
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(self, max_workers: int = 4) -> None:
|
|
57
|
+
"""Initialize backend.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
max_workers: Maximum worker threads for async operations.
|
|
61
|
+
"""
|
|
62
|
+
self._executor = ThreadPoolExecutor(max_workers=max_workers)
|
|
63
|
+
self._max_workers = max_workers
|
|
64
|
+
|
|
65
|
+
@abstractmethod
|
|
66
|
+
def is_available(self) -> bool:
|
|
67
|
+
"""Check if the backend is available.
|
|
68
|
+
|
|
69
|
+
This method should verify that all required dependencies
|
|
70
|
+
are installed and the backend can function.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
True if the backend is ready to use.
|
|
74
|
+
"""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
def get_version(self) -> str | None:
|
|
78
|
+
"""Get the backend library version.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Version string or None if not available.
|
|
82
|
+
"""
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
@abstractmethod
|
|
86
|
+
async def check(
|
|
87
|
+
self,
|
|
88
|
+
data: DataInput,
|
|
89
|
+
*,
|
|
90
|
+
validators: list[str] | None = None,
|
|
91
|
+
validator_config: dict[str, dict[str, Any]] | None = None,
|
|
92
|
+
schema: str | None = None,
|
|
93
|
+
auto_schema: bool = False,
|
|
94
|
+
columns: list[str] | None = None,
|
|
95
|
+
min_severity: str | None = None,
|
|
96
|
+
strict: bool = False,
|
|
97
|
+
parallel: bool = False,
|
|
98
|
+
max_workers: int | None = None,
|
|
99
|
+
pushdown: bool | None = None,
|
|
100
|
+
) -> CheckResult:
|
|
101
|
+
"""Run data validation.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
data: File path or DataSource object.
|
|
105
|
+
validators: List of validator names to run.
|
|
106
|
+
validator_config: Per-validator configuration.
|
|
107
|
+
schema: Path to schema YAML file.
|
|
108
|
+
auto_schema: Auto-learn schema for validation.
|
|
109
|
+
columns: Columns to validate.
|
|
110
|
+
min_severity: Minimum severity to report.
|
|
111
|
+
strict: Raise exception on failures.
|
|
112
|
+
parallel: Use parallel execution.
|
|
113
|
+
max_workers: Max threads for parallel.
|
|
114
|
+
pushdown: Enable query pushdown.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
CheckResult with validation results.
|
|
118
|
+
"""
|
|
119
|
+
...
|
|
120
|
+
|
|
121
|
+
@abstractmethod
|
|
122
|
+
async def learn(
|
|
123
|
+
self,
|
|
124
|
+
source: DataInput,
|
|
125
|
+
*,
|
|
126
|
+
infer_constraints: bool = True,
|
|
127
|
+
categorical_threshold: int | None = None,
|
|
128
|
+
sample_size: int | None = None,
|
|
129
|
+
) -> LearnResult:
|
|
130
|
+
"""Learn schema from data.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
source: File path or DataSource object.
|
|
134
|
+
infer_constraints: Infer constraints from statistics.
|
|
135
|
+
categorical_threshold: Max unique values for categorical.
|
|
136
|
+
sample_size: Number of rows to sample.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
LearnResult with schema information.
|
|
140
|
+
"""
|
|
141
|
+
...
|
|
142
|
+
|
|
143
|
+
@abstractmethod
|
|
144
|
+
async def profile(
|
|
145
|
+
self,
|
|
146
|
+
source: DataInput,
|
|
147
|
+
*,
|
|
148
|
+
sample_size: int | None = None,
|
|
149
|
+
include_patterns: bool = True,
|
|
150
|
+
include_correlations: bool = False,
|
|
151
|
+
include_distributions: bool = True,
|
|
152
|
+
top_n_values: int = 10,
|
|
153
|
+
pattern_sample_size: int = 1000,
|
|
154
|
+
correlation_threshold: float = 0.7,
|
|
155
|
+
min_pattern_match_ratio: float = 0.8,
|
|
156
|
+
n_jobs: int = 1,
|
|
157
|
+
) -> ProfileResult:
|
|
158
|
+
"""Run data profiling.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
source: File path or DataSource object.
|
|
162
|
+
sample_size: Max rows to sample.
|
|
163
|
+
include_patterns: Enable pattern detection.
|
|
164
|
+
include_correlations: Calculate correlations.
|
|
165
|
+
include_distributions: Include distribution stats.
|
|
166
|
+
top_n_values: Top/bottom values per column.
|
|
167
|
+
pattern_sample_size: Sample size for pattern matching.
|
|
168
|
+
correlation_threshold: Minimum correlation to report.
|
|
169
|
+
min_pattern_match_ratio: Minimum pattern match ratio.
|
|
170
|
+
n_jobs: Number of parallel jobs.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
ProfileResult with profiling information.
|
|
174
|
+
"""
|
|
175
|
+
...
|
|
176
|
+
|
|
177
|
+
@abstractmethod
|
|
178
|
+
async def compare(
|
|
179
|
+
self,
|
|
180
|
+
baseline: DataInput,
|
|
181
|
+
current: DataInput,
|
|
182
|
+
*,
|
|
183
|
+
columns: list[str] | None = None,
|
|
184
|
+
method: str = "auto",
|
|
185
|
+
threshold: float | None = None,
|
|
186
|
+
sample_size: int | None = None,
|
|
187
|
+
) -> CompareResult:
|
|
188
|
+
"""Compare datasets for drift detection.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
baseline: Reference data.
|
|
192
|
+
current: Current data to compare.
|
|
193
|
+
columns: Columns to compare.
|
|
194
|
+
method: Detection method.
|
|
195
|
+
threshold: Drift threshold.
|
|
196
|
+
sample_size: Sample size for large datasets.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
CompareResult with drift results.
|
|
200
|
+
"""
|
|
201
|
+
...
|
|
202
|
+
|
|
203
|
+
@abstractmethod
|
|
204
|
+
async def scan(
|
|
205
|
+
self,
|
|
206
|
+
data: DataInput,
|
|
207
|
+
*,
|
|
208
|
+
columns: list[str] | None = None,
|
|
209
|
+
regulations: list[str] | None = None,
|
|
210
|
+
min_confidence: float = 0.8,
|
|
211
|
+
) -> ScanResult:
|
|
212
|
+
"""Scan for PII.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
data: File path or DataSource object.
|
|
216
|
+
columns: Columns to scan.
|
|
217
|
+
regulations: Regulations to check.
|
|
218
|
+
min_confidence: Minimum PII confidence.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
ScanResult with PII findings.
|
|
222
|
+
"""
|
|
223
|
+
...
|
|
224
|
+
|
|
225
|
+
@abstractmethod
|
|
226
|
+
async def mask(
|
|
227
|
+
self,
|
|
228
|
+
data: DataInput,
|
|
229
|
+
output: str,
|
|
230
|
+
*,
|
|
231
|
+
columns: list[str] | None = None,
|
|
232
|
+
strategy: str = "redact",
|
|
233
|
+
) -> MaskResult:
|
|
234
|
+
"""Mask sensitive data.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
data: File path or DataSource object.
|
|
238
|
+
output: Output file path.
|
|
239
|
+
columns: Columns to mask.
|
|
240
|
+
strategy: Masking strategy.
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
MaskResult with masking details.
|
|
244
|
+
"""
|
|
245
|
+
...
|
|
246
|
+
|
|
247
|
+
async def generate_suite(
|
|
248
|
+
self,
|
|
249
|
+
profile: ProfileResult | dict[str, Any],
|
|
250
|
+
*,
|
|
251
|
+
strictness: str = "medium",
|
|
252
|
+
preset: str = "default",
|
|
253
|
+
include: list[str] | None = None,
|
|
254
|
+
exclude: list[str] | None = None,
|
|
255
|
+
output_format: str = "yaml",
|
|
256
|
+
) -> GenerateSuiteResult:
|
|
257
|
+
"""Generate validation suite from profile.
|
|
258
|
+
|
|
259
|
+
Default implementation raises NotImplementedError.
|
|
260
|
+
Override in backends that support suite generation.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
profile: Profile result or dictionary.
|
|
264
|
+
strictness: Rule strictness level.
|
|
265
|
+
preset: Rule generation preset.
|
|
266
|
+
include: Rule categories to include.
|
|
267
|
+
exclude: Rule categories to exclude.
|
|
268
|
+
output_format: Output format.
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
GenerateSuiteResult with generated rules.
|
|
272
|
+
|
|
273
|
+
Raises:
|
|
274
|
+
NotImplementedError: If backend doesn't support this.
|
|
275
|
+
"""
|
|
276
|
+
raise NotImplementedError(
|
|
277
|
+
f"{self.__class__.__name__} does not support generate_suite"
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
async def _run_in_executor(self, func, *args, **kwargs):
|
|
281
|
+
"""Run a synchronous function in the thread pool executor.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
func: Function to run.
|
|
285
|
+
*args: Positional arguments.
|
|
286
|
+
**kwargs: Keyword arguments.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Function result.
|
|
290
|
+
"""
|
|
291
|
+
loop = asyncio.get_event_loop()
|
|
292
|
+
if kwargs:
|
|
293
|
+
func = partial(func, *args, **kwargs)
|
|
294
|
+
return await loop.run_in_executor(self._executor, func)
|
|
295
|
+
return await loop.run_in_executor(self._executor, func, *args)
|
|
296
|
+
|
|
297
|
+
def shutdown(self) -> None:
|
|
298
|
+
"""Shutdown the executor."""
|
|
299
|
+
self._executor.shutdown(wait=False)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""Backend-specific error types.
|
|
2
|
+
|
|
3
|
+
This module defines errors that can occur during backend operations.
|
|
4
|
+
These errors provide meaningful context for troubleshooting and
|
|
5
|
+
enable graceful degradation when backends are unavailable.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from truthound_dashboard.core.exceptions import (
|
|
11
|
+
ErrorCode,
|
|
12
|
+
TruthoundDashboardError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BackendError(TruthoundDashboardError):
|
|
17
|
+
"""Base error for backend operations.
|
|
18
|
+
|
|
19
|
+
All backend-specific errors inherit from this class.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
code = ErrorCode.INTERNAL_ERROR
|
|
23
|
+
http_status = 500
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
message: str,
|
|
28
|
+
*,
|
|
29
|
+
backend_name: str | None = None,
|
|
30
|
+
operation: str | None = None,
|
|
31
|
+
**kwargs,
|
|
32
|
+
) -> None:
|
|
33
|
+
"""Initialize backend error.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
message: Error message.
|
|
37
|
+
backend_name: Name of the backend that failed.
|
|
38
|
+
operation: Operation that was being performed.
|
|
39
|
+
**kwargs: Additional context.
|
|
40
|
+
"""
|
|
41
|
+
super().__init__(message, **kwargs)
|
|
42
|
+
self.backend_name = backend_name
|
|
43
|
+
self.operation = operation
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class BackendUnavailableError(BackendError):
|
|
47
|
+
"""Backend library is not installed or unavailable.
|
|
48
|
+
|
|
49
|
+
This error is raised when the required backend library (e.g., truthound)
|
|
50
|
+
is not installed or cannot be imported.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
try:
|
|
54
|
+
import truthound
|
|
55
|
+
except ImportError:
|
|
56
|
+
raise BackendUnavailableError("truthound", "Library not installed")
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
code = ErrorCode.INTERNAL_ERROR
|
|
60
|
+
http_status = 503 # Service Unavailable
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
backend_name: str,
|
|
65
|
+
message: str | None = None,
|
|
66
|
+
**kwargs,
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Initialize unavailable error.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
backend_name: Name of the unavailable backend.
|
|
72
|
+
message: Optional additional message.
|
|
73
|
+
**kwargs: Additional context.
|
|
74
|
+
"""
|
|
75
|
+
msg = f"Backend '{backend_name}' is not available"
|
|
76
|
+
if message:
|
|
77
|
+
msg = f"{msg}: {message}"
|
|
78
|
+
super().__init__(msg, backend_name=backend_name, **kwargs)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class BackendVersionError(BackendError):
|
|
82
|
+
"""Backend version is incompatible.
|
|
83
|
+
|
|
84
|
+
This error is raised when the installed backend library version
|
|
85
|
+
is incompatible with the dashboard's expected API.
|
|
86
|
+
|
|
87
|
+
Example:
|
|
88
|
+
if truthound.__version__ < "2.0":
|
|
89
|
+
raise BackendVersionError("truthound", "2.0", truthound.__version__)
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
code = ErrorCode.INTERNAL_ERROR
|
|
93
|
+
http_status = 500
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
backend_name: str,
|
|
98
|
+
required_version: str | None = None,
|
|
99
|
+
current_version: str | None = None,
|
|
100
|
+
message: str | None = None,
|
|
101
|
+
**kwargs,
|
|
102
|
+
) -> None:
|
|
103
|
+
"""Initialize version error.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
backend_name: Name of the backend.
|
|
107
|
+
required_version: Minimum required version.
|
|
108
|
+
current_version: Currently installed version.
|
|
109
|
+
message: Optional additional message.
|
|
110
|
+
**kwargs: Additional context.
|
|
111
|
+
"""
|
|
112
|
+
msg = f"Backend '{backend_name}' version incompatibility"
|
|
113
|
+
if required_version and current_version:
|
|
114
|
+
msg = f"{msg}: requires >={required_version}, found {current_version}"
|
|
115
|
+
elif message:
|
|
116
|
+
msg = f"{msg}: {message}"
|
|
117
|
+
super().__init__(msg, backend_name=backend_name, **kwargs)
|
|
118
|
+
self.required_version = required_version
|
|
119
|
+
self.current_version = current_version
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class BackendOperationError(BackendError):
|
|
123
|
+
"""Backend operation failed.
|
|
124
|
+
|
|
125
|
+
This error wraps exceptions that occur during backend operations,
|
|
126
|
+
providing context about what operation was being performed.
|
|
127
|
+
|
|
128
|
+
Example:
|
|
129
|
+
try:
|
|
130
|
+
result = th.check(data)
|
|
131
|
+
except Exception as e:
|
|
132
|
+
raise BackendOperationError("truthound", "check", str(e))
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
code = ErrorCode.INTERNAL_ERROR
|
|
136
|
+
http_status = 500
|
|
137
|
+
|
|
138
|
+
def __init__(
|
|
139
|
+
self,
|
|
140
|
+
backend_name: str,
|
|
141
|
+
operation: str,
|
|
142
|
+
message: str,
|
|
143
|
+
*,
|
|
144
|
+
original_error: Exception | None = None,
|
|
145
|
+
**kwargs,
|
|
146
|
+
) -> None:
|
|
147
|
+
"""Initialize operation error.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
backend_name: Name of the backend.
|
|
151
|
+
operation: Operation that failed.
|
|
152
|
+
message: Error message.
|
|
153
|
+
original_error: Original exception if available.
|
|
154
|
+
**kwargs: Additional context.
|
|
155
|
+
"""
|
|
156
|
+
msg = f"Backend '{backend_name}' operation '{operation}' failed: {message}"
|
|
157
|
+
super().__init__(msg, backend_name=backend_name, operation=operation, **kwargs)
|
|
158
|
+
self.original_error = original_error
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class BackendConfigError(BackendError):
|
|
162
|
+
"""Backend configuration is invalid.
|
|
163
|
+
|
|
164
|
+
This error is raised when backend configuration is missing or invalid.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
code = ErrorCode.VALIDATION_ERROR
|
|
168
|
+
http_status = 400
|
|
169
|
+
|
|
170
|
+
def __init__(
|
|
171
|
+
self,
|
|
172
|
+
backend_name: str,
|
|
173
|
+
config_key: str | None = None,
|
|
174
|
+
message: str | None = None,
|
|
175
|
+
**kwargs,
|
|
176
|
+
) -> None:
|
|
177
|
+
"""Initialize config error.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
backend_name: Name of the backend.
|
|
181
|
+
config_key: Configuration key that's invalid.
|
|
182
|
+
message: Optional additional message.
|
|
183
|
+
**kwargs: Additional context.
|
|
184
|
+
"""
|
|
185
|
+
msg = f"Backend '{backend_name}' configuration error"
|
|
186
|
+
if config_key:
|
|
187
|
+
msg = f"{msg}: invalid '{config_key}'"
|
|
188
|
+
if message:
|
|
189
|
+
msg = f"{msg}: {message}"
|
|
190
|
+
super().__init__(msg, backend_name=backend_name, **kwargs)
|
|
191
|
+
self.config_key = config_key
|