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,6 +1,10 @@
|
|
|
1
1
|
"""Profile API endpoints.
|
|
2
2
|
|
|
3
3
|
This module provides endpoints for data profiling and comparison.
|
|
4
|
+
|
|
5
|
+
Note: truthound's th.profile() only supports (data, source) parameters.
|
|
6
|
+
Advanced options like sampling strategies, pattern detection configuration,
|
|
7
|
+
and correlation analysis are NOT supported by the underlying library.
|
|
4
8
|
"""
|
|
5
9
|
|
|
6
10
|
from __future__ import annotations
|
|
@@ -11,12 +15,12 @@ from fastapi import APIRouter, HTTPException, Path, Query
|
|
|
11
15
|
|
|
12
16
|
from truthound_dashboard.schemas import (
|
|
13
17
|
LatestComparisonResponse,
|
|
18
|
+
ProfileAdvancedRequest,
|
|
14
19
|
ProfileComparisonRequest,
|
|
15
20
|
ProfileComparisonResponse,
|
|
16
21
|
ProfileListResponse,
|
|
17
22
|
ProfileRequest,
|
|
18
23
|
ProfileResponse,
|
|
19
|
-
ProfileTrendRequest,
|
|
20
24
|
ProfileTrendResponse,
|
|
21
25
|
)
|
|
22
26
|
|
|
@@ -29,7 +33,7 @@ router = APIRouter()
|
|
|
29
33
|
"/sources/{source_id}/profile",
|
|
30
34
|
response_model=ProfileResponse,
|
|
31
35
|
summary="Profile source",
|
|
32
|
-
description="Run data profiling on a source
|
|
36
|
+
description="Run data profiling on a source",
|
|
33
37
|
)
|
|
34
38
|
async def profile_source(
|
|
35
39
|
service: ProfileServiceDep,
|
|
@@ -39,19 +43,17 @@ async def profile_source(
|
|
|
39
43
|
) -> ProfileResponse:
|
|
40
44
|
"""Run data profiling on a source.
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- Pattern detection: email, phone, uuid, url, ip_address, credit_card, etc.
|
|
45
|
-
- Statistical analysis options: histograms, correlations, cardinality
|
|
46
|
+
Note: truthound's th.profile() only supports (data, source) parameters.
|
|
47
|
+
Advanced configuration options are not supported.
|
|
46
48
|
|
|
47
49
|
Args:
|
|
48
50
|
service: Injected profile service.
|
|
49
51
|
source_service: Injected source service.
|
|
50
52
|
source_id: Source to profile.
|
|
51
|
-
request: Optional
|
|
53
|
+
request: Optional request body (not used, kept for API compatibility).
|
|
52
54
|
|
|
53
55
|
Returns:
|
|
54
|
-
Profiling result with column statistics
|
|
56
|
+
Profiling result with column statistics.
|
|
55
57
|
|
|
56
58
|
Raises:
|
|
57
59
|
HTTPException: 404 if source not found, 500 on profiling error.
|
|
@@ -61,38 +63,73 @@ async def profile_source(
|
|
|
61
63
|
if source is None:
|
|
62
64
|
raise HTTPException(status_code=404, detail="Source not found")
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
66
|
+
try:
|
|
67
|
+
result = await service.profile_source(source_id)
|
|
68
|
+
return ProfileResponse.from_result(result)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@router.post(
|
|
74
|
+
"/sources/{source_id}/profile/advanced",
|
|
75
|
+
response_model=ProfileResponse,
|
|
76
|
+
summary="Profile source with advanced configuration",
|
|
77
|
+
description="Run data profiling with custom ProfilerConfig options",
|
|
78
|
+
)
|
|
79
|
+
async def profile_source_advanced(
|
|
80
|
+
service: ProfileServiceDep,
|
|
81
|
+
source_service: SourceServiceDep,
|
|
82
|
+
source_id: Annotated[str, Path(description="Source ID to profile")],
|
|
83
|
+
request: ProfileAdvancedRequest,
|
|
84
|
+
) -> ProfileResponse:
|
|
85
|
+
"""Run advanced data profiling with custom configuration.
|
|
86
|
+
|
|
87
|
+
Uses truthound's ProfilerConfig for fine-grained control over:
|
|
88
|
+
- Sampling: sample_size, random_seed
|
|
89
|
+
- Features: include_patterns, include_correlations, include_distributions
|
|
90
|
+
- Pattern detection: pattern_sample_size, min_pattern_match_ratio
|
|
91
|
+
- Output: top_n_values, correlation_threshold
|
|
92
|
+
- Performance: n_jobs
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
service: Injected profile service.
|
|
96
|
+
source_service: Injected source service.
|
|
97
|
+
source_id: Source to profile.
|
|
98
|
+
request: Advanced profiling configuration.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Profiling result with column statistics.
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
HTTPException: 404 if source not found, 501 if not supported, 500 on error.
|
|
105
|
+
"""
|
|
106
|
+
# Verify source exists
|
|
107
|
+
source = await source_service.get_by_id(source_id)
|
|
108
|
+
if source is None:
|
|
109
|
+
raise HTTPException(status_code=404, detail="Source not found")
|
|
92
110
|
|
|
93
111
|
try:
|
|
94
|
-
|
|
112
|
+
# Convert request to config dict
|
|
113
|
+
config = {
|
|
114
|
+
"sample_size": request.sample_size,
|
|
115
|
+
"random_seed": request.random_seed,
|
|
116
|
+
"include_patterns": request.include_patterns,
|
|
117
|
+
"include_correlations": request.include_correlations,
|
|
118
|
+
"include_distributions": request.include_distributions,
|
|
119
|
+
"top_n_values": request.top_n_values,
|
|
120
|
+
"pattern_sample_size": request.pattern_sample_size,
|
|
121
|
+
"correlation_threshold": request.correlation_threshold,
|
|
122
|
+
"min_pattern_match_ratio": request.min_pattern_match_ratio,
|
|
123
|
+
"n_jobs": request.n_jobs,
|
|
124
|
+
}
|
|
125
|
+
result = await service.profile_source_advanced(source_id, config=config)
|
|
95
126
|
return ProfileResponse.from_result(result)
|
|
127
|
+
except ImportError as e:
|
|
128
|
+
raise HTTPException(
|
|
129
|
+
status_code=501,
|
|
130
|
+
detail=f"Advanced profiling not available: {e}. "
|
|
131
|
+
"Please upgrade truthound to the latest version.",
|
|
132
|
+
)
|
|
96
133
|
except Exception as e:
|
|
97
134
|
raise HTTPException(status_code=500, detail=str(e))
|
|
98
135
|
|
|
@@ -102,6 +139,41 @@ async def profile_source(
|
|
|
102
139
|
# =============================================================================
|
|
103
140
|
|
|
104
141
|
|
|
142
|
+
@router.get(
|
|
143
|
+
"/sources/{source_id}/profile/latest",
|
|
144
|
+
response_model=ProfileResponse | None,
|
|
145
|
+
summary="Get latest profile",
|
|
146
|
+
description="Retrieve the most recent profile result for a source",
|
|
147
|
+
)
|
|
148
|
+
async def get_latest_profile(
|
|
149
|
+
service: ProfileServiceDep,
|
|
150
|
+
source_service: SourceServiceDep,
|
|
151
|
+
source_id: Annotated[str, Path(description="Source ID")],
|
|
152
|
+
) -> ProfileResponse | None:
|
|
153
|
+
"""Get the latest profile for a source.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
service: Injected profile service.
|
|
157
|
+
source_service: Injected source service.
|
|
158
|
+
source_id: Source ID.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Latest profile result or null.
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
HTTPException: 404 if source not found.
|
|
165
|
+
"""
|
|
166
|
+
source = await source_service.get_by_id(source_id)
|
|
167
|
+
if source is None:
|
|
168
|
+
raise HTTPException(status_code=404, detail="Source not found")
|
|
169
|
+
|
|
170
|
+
profile = await service.get_latest_profile(source_id)
|
|
171
|
+
if profile is None:
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
return ProfileResponse.from_result(profile)
|
|
175
|
+
|
|
176
|
+
|
|
105
177
|
@router.get(
|
|
106
178
|
"/sources/{source_id}/profiles",
|
|
107
179
|
response_model=ProfileListResponse,
|
|
@@ -255,3 +327,93 @@ async def get_latest_profile_comparison(
|
|
|
255
327
|
raise HTTPException(status_code=404, detail="Source not found")
|
|
256
328
|
|
|
257
329
|
return await comparison_service.get_latest_comparison(source)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
# =============================================================================
|
|
333
|
+
# Rule Generation from Profile
|
|
334
|
+
# =============================================================================
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@router.post(
|
|
338
|
+
"/sources/{source_id}/profiles/generate-rules",
|
|
339
|
+
summary="Generate validation rules from profile",
|
|
340
|
+
description="Automatically generate validation rules based on profiled data characteristics.",
|
|
341
|
+
)
|
|
342
|
+
async def generate_rules_from_profile(
|
|
343
|
+
source_id: Annotated[str, Path(description="Source ID")],
|
|
344
|
+
service: ProfileServiceDep,
|
|
345
|
+
source_service: SourceServiceDep,
|
|
346
|
+
strictness: str = Query(
|
|
347
|
+
default="medium",
|
|
348
|
+
description="Rule strictness: loose, medium, strict",
|
|
349
|
+
),
|
|
350
|
+
preset: str = Query(
|
|
351
|
+
default="default",
|
|
352
|
+
description="Rule preset: default, strict, loose, minimal, comprehensive, ci_cd, schema_only, format_only",
|
|
353
|
+
),
|
|
354
|
+
include_categories: list[str] | None = Query(
|
|
355
|
+
default=None,
|
|
356
|
+
description="Rule categories to include (schema, stats, pattern, completeness, uniqueness, distribution)",
|
|
357
|
+
),
|
|
358
|
+
exclude_categories: list[str] | None = Query(
|
|
359
|
+
default=None,
|
|
360
|
+
description="Rule categories to exclude",
|
|
361
|
+
),
|
|
362
|
+
profile_if_needed: bool = Query(
|
|
363
|
+
default=True,
|
|
364
|
+
description="Profile source if no recent profile exists",
|
|
365
|
+
),
|
|
366
|
+
sample_size: int | None = Query(
|
|
367
|
+
default=None,
|
|
368
|
+
description="Sample size for profiling if needed",
|
|
369
|
+
),
|
|
370
|
+
) -> dict:
|
|
371
|
+
"""Generate validation rules from source profile.
|
|
372
|
+
|
|
373
|
+
Uses truthound's generate_suite() to automatically create validation
|
|
374
|
+
rules based on the profiled data characteristics.
|
|
375
|
+
|
|
376
|
+
The generated rules can be used directly with th.check() or saved
|
|
377
|
+
as a schema file for repeated validation.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
source_id: Source ID to generate rules for.
|
|
381
|
+
service: Profile service.
|
|
382
|
+
source_service: Source service.
|
|
383
|
+
strictness: Rule strictness level.
|
|
384
|
+
preset: Rule generation preset.
|
|
385
|
+
include_categories: Rule categories to include.
|
|
386
|
+
exclude_categories: Rule categories to exclude.
|
|
387
|
+
profile_if_needed: Profile source if no recent profile exists.
|
|
388
|
+
sample_size: Sample size for profiling if needed.
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
Generated rules with YAML content and metadata.
|
|
392
|
+
|
|
393
|
+
Raises:
|
|
394
|
+
HTTPException: 404 if source not found, 400 if no profile available.
|
|
395
|
+
"""
|
|
396
|
+
# Verify source exists
|
|
397
|
+
source = await source_service.get_by_id(source_id)
|
|
398
|
+
if source is None:
|
|
399
|
+
raise HTTPException(status_code=404, detail="Source not found")
|
|
400
|
+
|
|
401
|
+
try:
|
|
402
|
+
result = await service.generate_rules_from_profile(
|
|
403
|
+
source_id,
|
|
404
|
+
strictness=strictness,
|
|
405
|
+
preset=preset,
|
|
406
|
+
include_categories=include_categories,
|
|
407
|
+
exclude_categories=exclude_categories,
|
|
408
|
+
profile_if_needed=profile_if_needed,
|
|
409
|
+
sample_size=sample_size,
|
|
410
|
+
)
|
|
411
|
+
return result
|
|
412
|
+
except ValueError as e:
|
|
413
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
414
|
+
except ImportError as e:
|
|
415
|
+
raise HTTPException(
|
|
416
|
+
status_code=501,
|
|
417
|
+
detail=f"Rule generation not available: {e}. "
|
|
418
|
+
"Please upgrade truthound to the latest version.",
|
|
419
|
+
)
|