truthound-dashboard 1.3.1__py3-none-any.whl → 1.4.0__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 +258 -0
- truthound_dashboard/api/anomaly.py +1302 -0
- truthound_dashboard/api/cross_alerts.py +352 -0
- truthound_dashboard/api/deps.py +143 -0
- truthound_dashboard/api/drift_monitor.py +540 -0
- truthound_dashboard/api/lineage.py +1151 -0
- truthound_dashboard/api/maintenance.py +363 -0
- truthound_dashboard/api/middleware.py +373 -1
- truthound_dashboard/api/model_monitoring.py +805 -0
- truthound_dashboard/api/notifications_advanced.py +2452 -0
- truthound_dashboard/api/plugins.py +2096 -0
- truthound_dashboard/api/profile.py +211 -14
- truthound_dashboard/api/reports.py +853 -0
- truthound_dashboard/api/router.py +147 -0
- truthound_dashboard/api/rule_suggestions.py +310 -0
- truthound_dashboard/api/schema_evolution.py +231 -0
- truthound_dashboard/api/sources.py +47 -3
- truthound_dashboard/api/triggers.py +190 -0
- truthound_dashboard/api/validations.py +13 -0
- truthound_dashboard/api/validators.py +333 -4
- truthound_dashboard/api/versioning.py +309 -0
- truthound_dashboard/api/websocket.py +301 -0
- truthound_dashboard/core/__init__.py +27 -0
- truthound_dashboard/core/anomaly.py +1395 -0
- truthound_dashboard/core/anomaly_explainer.py +633 -0
- truthound_dashboard/core/cache.py +206 -0
- truthound_dashboard/core/cached_services.py +422 -0
- truthound_dashboard/core/charts.py +352 -0
- truthound_dashboard/core/connections.py +1069 -42
- truthound_dashboard/core/cross_alerts.py +837 -0
- truthound_dashboard/core/drift_monitor.py +1477 -0
- truthound_dashboard/core/drift_sampling.py +669 -0
- truthound_dashboard/core/i18n/__init__.py +42 -0
- truthound_dashboard/core/i18n/detector.py +173 -0
- truthound_dashboard/core/i18n/messages.py +564 -0
- truthound_dashboard/core/lineage.py +971 -0
- truthound_dashboard/core/maintenance.py +443 -5
- truthound_dashboard/core/model_monitoring.py +1043 -0
- truthound_dashboard/core/notifications/channels.py +1020 -1
- truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
- truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
- truthound_dashboard/core/notifications/deduplication/service.py +400 -0
- truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
- truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
- truthound_dashboard/core/notifications/dispatcher.py +43 -0
- truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
- truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
- truthound_dashboard/core/notifications/escalation/engine.py +429 -0
- truthound_dashboard/core/notifications/escalation/models.py +336 -0
- truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
- truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
- truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
- truthound_dashboard/core/notifications/events.py +49 -0
- truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
- truthound_dashboard/core/notifications/metrics/base.py +528 -0
- truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
- truthound_dashboard/core/notifications/routing/__init__.py +169 -0
- truthound_dashboard/core/notifications/routing/combinators.py +184 -0
- truthound_dashboard/core/notifications/routing/config.py +375 -0
- truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
- truthound_dashboard/core/notifications/routing/engine.py +382 -0
- truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
- truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
- truthound_dashboard/core/notifications/routing/rules.py +625 -0
- truthound_dashboard/core/notifications/routing/validator.py +678 -0
- truthound_dashboard/core/notifications/service.py +2 -0
- truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
- truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
- truthound_dashboard/core/notifications/throttling/builder.py +311 -0
- truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
- truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
- truthound_dashboard/core/openlineage.py +1028 -0
- truthound_dashboard/core/plugins/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/extractor.py +703 -0
- truthound_dashboard/core/plugins/docs/renderers.py +804 -0
- truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
- truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
- truthound_dashboard/core/plugins/hooks/manager.py +403 -0
- truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
- truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
- truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
- truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
- truthound_dashboard/core/plugins/loader.py +504 -0
- truthound_dashboard/core/plugins/registry.py +810 -0
- truthound_dashboard/core/plugins/reporter_executor.py +588 -0
- truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
- truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
- truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
- truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
- truthound_dashboard/core/plugins/sandbox.py +617 -0
- truthound_dashboard/core/plugins/security/__init__.py +68 -0
- truthound_dashboard/core/plugins/security/analyzer.py +535 -0
- truthound_dashboard/core/plugins/security/policies.py +311 -0
- truthound_dashboard/core/plugins/security/protocols.py +296 -0
- truthound_dashboard/core/plugins/security/signing.py +842 -0
- truthound_dashboard/core/plugins/security.py +446 -0
- truthound_dashboard/core/plugins/validator_executor.py +401 -0
- truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
- truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
- truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
- truthound_dashboard/core/plugins/versioning/semver.py +266 -0
- truthound_dashboard/core/profile_comparison.py +601 -0
- truthound_dashboard/core/report_history.py +570 -0
- truthound_dashboard/core/reporters/__init__.py +57 -0
- truthound_dashboard/core/reporters/base.py +296 -0
- truthound_dashboard/core/reporters/csv_reporter.py +155 -0
- truthound_dashboard/core/reporters/html_reporter.py +598 -0
- truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
- truthound_dashboard/core/reporters/i18n/base.py +494 -0
- truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
- truthound_dashboard/core/reporters/json_reporter.py +160 -0
- truthound_dashboard/core/reporters/junit_reporter.py +233 -0
- truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
- truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
- truthound_dashboard/core/reporters/registry.py +272 -0
- truthound_dashboard/core/rule_generator.py +2088 -0
- truthound_dashboard/core/scheduler.py +822 -12
- truthound_dashboard/core/schema_evolution.py +858 -0
- truthound_dashboard/core/services.py +152 -9
- truthound_dashboard/core/statistics.py +718 -0
- truthound_dashboard/core/streaming_anomaly.py +883 -0
- truthound_dashboard/core/triggers/__init__.py +45 -0
- truthound_dashboard/core/triggers/base.py +226 -0
- truthound_dashboard/core/triggers/evaluators.py +609 -0
- truthound_dashboard/core/triggers/factory.py +363 -0
- truthound_dashboard/core/unified_alerts.py +870 -0
- truthound_dashboard/core/validation_limits.py +509 -0
- truthound_dashboard/core/versioning.py +709 -0
- truthound_dashboard/core/websocket/__init__.py +59 -0
- truthound_dashboard/core/websocket/manager.py +512 -0
- truthound_dashboard/core/websocket/messages.py +130 -0
- truthound_dashboard/db/__init__.py +30 -0
- truthound_dashboard/db/models.py +3375 -3
- truthound_dashboard/main.py +22 -0
- truthound_dashboard/schemas/__init__.py +396 -1
- truthound_dashboard/schemas/anomaly.py +1258 -0
- truthound_dashboard/schemas/base.py +4 -0
- truthound_dashboard/schemas/cross_alerts.py +334 -0
- truthound_dashboard/schemas/drift_monitor.py +890 -0
- truthound_dashboard/schemas/lineage.py +428 -0
- truthound_dashboard/schemas/maintenance.py +154 -0
- truthound_dashboard/schemas/model_monitoring.py +374 -0
- truthound_dashboard/schemas/notifications_advanced.py +1363 -0
- truthound_dashboard/schemas/openlineage.py +704 -0
- truthound_dashboard/schemas/plugins.py +1293 -0
- truthound_dashboard/schemas/profile.py +420 -34
- truthound_dashboard/schemas/profile_comparison.py +242 -0
- truthound_dashboard/schemas/reports.py +285 -0
- truthound_dashboard/schemas/rule_suggestion.py +434 -0
- truthound_dashboard/schemas/schema_evolution.py +164 -0
- truthound_dashboard/schemas/source.py +117 -2
- truthound_dashboard/schemas/triggers.py +511 -0
- truthound_dashboard/schemas/unified_alerts.py +223 -0
- truthound_dashboard/schemas/validation.py +25 -1
- truthound_dashboard/schemas/validators/__init__.py +11 -0
- truthound_dashboard/schemas/validators/base.py +151 -0
- truthound_dashboard/schemas/versioning.py +152 -0
- truthound_dashboard/static/index.html +2 -2
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -22
- truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
- truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
- truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
- truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
- truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Locale detection utilities.
|
|
2
|
+
|
|
3
|
+
This module provides functions to detect the user's preferred locale
|
|
4
|
+
from HTTP headers (Accept-Language) following RFC 7231.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
from fastapi import Request
|
|
8
|
+
from truthound_dashboard.core.i18n import detect_locale
|
|
9
|
+
|
|
10
|
+
@app.get("/api/v1/example")
|
|
11
|
+
async def example(request: Request):
|
|
12
|
+
locale = detect_locale(request)
|
|
13
|
+
# Use locale for localized responses
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import re
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
|
+
|
|
21
|
+
from truthound_dashboard.core.reporters.i18n.base import SupportedLocale
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from fastapi import Request
|
|
25
|
+
|
|
26
|
+
# Regex pattern for parsing Accept-Language header
|
|
27
|
+
# Matches: en-US, en;q=0.9, zh-Hans;q=0.8, etc.
|
|
28
|
+
ACCEPT_LANGUAGE_PATTERN = re.compile(
|
|
29
|
+
r"([a-zA-Z]{1,8}(?:-[a-zA-Z0-9]{1,8})?)\s*(?:;\s*q\s*=\s*([\d.]+))?"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def parse_accept_language(header: str | None) -> list[tuple[str, float]]:
|
|
34
|
+
"""Parse Accept-Language header into list of (locale, quality) tuples.
|
|
35
|
+
|
|
36
|
+
Follows RFC 7231 Section 5.3.5 for quality value parsing.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
header: Accept-Language header value (e.g., "en-US,en;q=0.9,ko;q=0.8")
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
List of (locale_code, quality) tuples, sorted by quality descending.
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
>>> parse_accept_language("en-US,en;q=0.9,ko;q=0.8")
|
|
46
|
+
[('en-US', 1.0), ('en', 0.9), ('ko', 0.8)]
|
|
47
|
+
"""
|
|
48
|
+
if not header:
|
|
49
|
+
return []
|
|
50
|
+
|
|
51
|
+
results: list[tuple[str, float]] = []
|
|
52
|
+
|
|
53
|
+
for match in ACCEPT_LANGUAGE_PATTERN.finditer(header):
|
|
54
|
+
locale = match.group(1)
|
|
55
|
+
quality_str = match.group(2)
|
|
56
|
+
|
|
57
|
+
# Default quality is 1.0 if not specified
|
|
58
|
+
try:
|
|
59
|
+
quality = float(quality_str) if quality_str else 1.0
|
|
60
|
+
# Clamp quality to valid range [0, 1]
|
|
61
|
+
quality = max(0.0, min(1.0, quality))
|
|
62
|
+
except ValueError:
|
|
63
|
+
quality = 1.0
|
|
64
|
+
|
|
65
|
+
results.append((locale, quality))
|
|
66
|
+
|
|
67
|
+
# Sort by quality descending
|
|
68
|
+
results.sort(key=lambda x: x[1], reverse=True)
|
|
69
|
+
return results
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def normalize_locale_code(code: str) -> str:
|
|
73
|
+
"""Normalize locale code to base language code.
|
|
74
|
+
|
|
75
|
+
Extracts the primary language subtag from a locale code.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
code: Locale code (e.g., "en-US", "zh-Hans", "ko")
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Normalized locale code (e.g., "en", "zh", "ko")
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
>>> normalize_locale_code("en-US")
|
|
85
|
+
'en'
|
|
86
|
+
>>> normalize_locale_code("zh-Hans")
|
|
87
|
+
'zh'
|
|
88
|
+
"""
|
|
89
|
+
return code.lower().split("-")[0].split("_")[0]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def find_best_locale(
|
|
93
|
+
preferred_locales: list[tuple[str, float]],
|
|
94
|
+
default: SupportedLocale = SupportedLocale.ENGLISH,
|
|
95
|
+
) -> SupportedLocale:
|
|
96
|
+
"""Find the best matching supported locale from a list of preferences.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
preferred_locales: List of (locale_code, quality) tuples.
|
|
100
|
+
default: Default locale if no match found.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Best matching SupportedLocale.
|
|
104
|
+
"""
|
|
105
|
+
supported_codes = {locale.value for locale in SupportedLocale}
|
|
106
|
+
|
|
107
|
+
for locale_code, _ in preferred_locales:
|
|
108
|
+
normalized = normalize_locale_code(locale_code)
|
|
109
|
+
|
|
110
|
+
if normalized in supported_codes:
|
|
111
|
+
return SupportedLocale(normalized)
|
|
112
|
+
|
|
113
|
+
return default
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def detect_locale(
|
|
117
|
+
request: Request,
|
|
118
|
+
default: SupportedLocale = SupportedLocale.ENGLISH,
|
|
119
|
+
) -> SupportedLocale:
|
|
120
|
+
"""Detect locale from FastAPI request.
|
|
121
|
+
|
|
122
|
+
Checks in order:
|
|
123
|
+
1. Query parameter: ?lang=ko
|
|
124
|
+
2. Accept-Language header
|
|
125
|
+
3. Default locale
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
request: FastAPI Request object.
|
|
129
|
+
default: Default locale if detection fails.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Detected SupportedLocale.
|
|
133
|
+
|
|
134
|
+
Example:
|
|
135
|
+
@app.get("/api/v1/example")
|
|
136
|
+
async def example(request: Request):
|
|
137
|
+
locale = detect_locale(request)
|
|
138
|
+
return {"locale": locale.value}
|
|
139
|
+
"""
|
|
140
|
+
# 1. Check query parameter
|
|
141
|
+
lang_param = request.query_params.get("lang")
|
|
142
|
+
if lang_param:
|
|
143
|
+
normalized = normalize_locale_code(lang_param)
|
|
144
|
+
try:
|
|
145
|
+
return SupportedLocale(normalized)
|
|
146
|
+
except ValueError:
|
|
147
|
+
pass # Invalid locale, continue to next method
|
|
148
|
+
|
|
149
|
+
# 2. Check Accept-Language header
|
|
150
|
+
accept_language = request.headers.get("Accept-Language")
|
|
151
|
+
if accept_language:
|
|
152
|
+
preferred_locales = parse_accept_language(accept_language)
|
|
153
|
+
if preferred_locales:
|
|
154
|
+
return find_best_locale(preferred_locales, default)
|
|
155
|
+
|
|
156
|
+
# 3. Return default
|
|
157
|
+
return default
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def get_locale_from_state(
|
|
161
|
+
request: Request,
|
|
162
|
+
default: SupportedLocale = SupportedLocale.ENGLISH,
|
|
163
|
+
) -> SupportedLocale:
|
|
164
|
+
"""Get locale from request state (set by middleware).
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
request: FastAPI Request object.
|
|
168
|
+
default: Default locale if not set in state.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
SupportedLocale from request state or default.
|
|
172
|
+
"""
|
|
173
|
+
return getattr(request.state, "locale", default)
|