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.
Files changed (169) hide show
  1. truthound_dashboard/api/alerts.py +258 -0
  2. truthound_dashboard/api/anomaly.py +1302 -0
  3. truthound_dashboard/api/cross_alerts.py +352 -0
  4. truthound_dashboard/api/deps.py +143 -0
  5. truthound_dashboard/api/drift_monitor.py +540 -0
  6. truthound_dashboard/api/lineage.py +1151 -0
  7. truthound_dashboard/api/maintenance.py +363 -0
  8. truthound_dashboard/api/middleware.py +373 -1
  9. truthound_dashboard/api/model_monitoring.py +805 -0
  10. truthound_dashboard/api/notifications_advanced.py +2452 -0
  11. truthound_dashboard/api/plugins.py +2096 -0
  12. truthound_dashboard/api/profile.py +211 -14
  13. truthound_dashboard/api/reports.py +853 -0
  14. truthound_dashboard/api/router.py +147 -0
  15. truthound_dashboard/api/rule_suggestions.py +310 -0
  16. truthound_dashboard/api/schema_evolution.py +231 -0
  17. truthound_dashboard/api/sources.py +47 -3
  18. truthound_dashboard/api/triggers.py +190 -0
  19. truthound_dashboard/api/validations.py +13 -0
  20. truthound_dashboard/api/validators.py +333 -4
  21. truthound_dashboard/api/versioning.py +309 -0
  22. truthound_dashboard/api/websocket.py +301 -0
  23. truthound_dashboard/core/__init__.py +27 -0
  24. truthound_dashboard/core/anomaly.py +1395 -0
  25. truthound_dashboard/core/anomaly_explainer.py +633 -0
  26. truthound_dashboard/core/cache.py +206 -0
  27. truthound_dashboard/core/cached_services.py +422 -0
  28. truthound_dashboard/core/charts.py +352 -0
  29. truthound_dashboard/core/connections.py +1069 -42
  30. truthound_dashboard/core/cross_alerts.py +837 -0
  31. truthound_dashboard/core/drift_monitor.py +1477 -0
  32. truthound_dashboard/core/drift_sampling.py +669 -0
  33. truthound_dashboard/core/i18n/__init__.py +42 -0
  34. truthound_dashboard/core/i18n/detector.py +173 -0
  35. truthound_dashboard/core/i18n/messages.py +564 -0
  36. truthound_dashboard/core/lineage.py +971 -0
  37. truthound_dashboard/core/maintenance.py +443 -5
  38. truthound_dashboard/core/model_monitoring.py +1043 -0
  39. truthound_dashboard/core/notifications/channels.py +1020 -1
  40. truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
  41. truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
  42. truthound_dashboard/core/notifications/deduplication/service.py +400 -0
  43. truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
  44. truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
  45. truthound_dashboard/core/notifications/dispatcher.py +43 -0
  46. truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
  47. truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
  48. truthound_dashboard/core/notifications/escalation/engine.py +429 -0
  49. truthound_dashboard/core/notifications/escalation/models.py +336 -0
  50. truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
  51. truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
  52. truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
  53. truthound_dashboard/core/notifications/events.py +49 -0
  54. truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
  55. truthound_dashboard/core/notifications/metrics/base.py +528 -0
  56. truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
  57. truthound_dashboard/core/notifications/routing/__init__.py +169 -0
  58. truthound_dashboard/core/notifications/routing/combinators.py +184 -0
  59. truthound_dashboard/core/notifications/routing/config.py +375 -0
  60. truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
  61. truthound_dashboard/core/notifications/routing/engine.py +382 -0
  62. truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
  63. truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
  64. truthound_dashboard/core/notifications/routing/rules.py +625 -0
  65. truthound_dashboard/core/notifications/routing/validator.py +678 -0
  66. truthound_dashboard/core/notifications/service.py +2 -0
  67. truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
  68. truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
  69. truthound_dashboard/core/notifications/throttling/builder.py +311 -0
  70. truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
  71. truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
  72. truthound_dashboard/core/openlineage.py +1028 -0
  73. truthound_dashboard/core/plugins/__init__.py +39 -0
  74. truthound_dashboard/core/plugins/docs/__init__.py +39 -0
  75. truthound_dashboard/core/plugins/docs/extractor.py +703 -0
  76. truthound_dashboard/core/plugins/docs/renderers.py +804 -0
  77. truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
  78. truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
  79. truthound_dashboard/core/plugins/hooks/manager.py +403 -0
  80. truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
  81. truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
  82. truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
  83. truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
  84. truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
  85. truthound_dashboard/core/plugins/loader.py +504 -0
  86. truthound_dashboard/core/plugins/registry.py +810 -0
  87. truthound_dashboard/core/plugins/reporter_executor.py +588 -0
  88. truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
  89. truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
  90. truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
  91. truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
  92. truthound_dashboard/core/plugins/sandbox.py +617 -0
  93. truthound_dashboard/core/plugins/security/__init__.py +68 -0
  94. truthound_dashboard/core/plugins/security/analyzer.py +535 -0
  95. truthound_dashboard/core/plugins/security/policies.py +311 -0
  96. truthound_dashboard/core/plugins/security/protocols.py +296 -0
  97. truthound_dashboard/core/plugins/security/signing.py +842 -0
  98. truthound_dashboard/core/plugins/security.py +446 -0
  99. truthound_dashboard/core/plugins/validator_executor.py +401 -0
  100. truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
  101. truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
  102. truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
  103. truthound_dashboard/core/plugins/versioning/semver.py +266 -0
  104. truthound_dashboard/core/profile_comparison.py +601 -0
  105. truthound_dashboard/core/report_history.py +570 -0
  106. truthound_dashboard/core/reporters/__init__.py +57 -0
  107. truthound_dashboard/core/reporters/base.py +296 -0
  108. truthound_dashboard/core/reporters/csv_reporter.py +155 -0
  109. truthound_dashboard/core/reporters/html_reporter.py +598 -0
  110. truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
  111. truthound_dashboard/core/reporters/i18n/base.py +494 -0
  112. truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
  113. truthound_dashboard/core/reporters/json_reporter.py +160 -0
  114. truthound_dashboard/core/reporters/junit_reporter.py +233 -0
  115. truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
  116. truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
  117. truthound_dashboard/core/reporters/registry.py +272 -0
  118. truthound_dashboard/core/rule_generator.py +2088 -0
  119. truthound_dashboard/core/scheduler.py +822 -12
  120. truthound_dashboard/core/schema_evolution.py +858 -0
  121. truthound_dashboard/core/services.py +152 -9
  122. truthound_dashboard/core/statistics.py +718 -0
  123. truthound_dashboard/core/streaming_anomaly.py +883 -0
  124. truthound_dashboard/core/triggers/__init__.py +45 -0
  125. truthound_dashboard/core/triggers/base.py +226 -0
  126. truthound_dashboard/core/triggers/evaluators.py +609 -0
  127. truthound_dashboard/core/triggers/factory.py +363 -0
  128. truthound_dashboard/core/unified_alerts.py +870 -0
  129. truthound_dashboard/core/validation_limits.py +509 -0
  130. truthound_dashboard/core/versioning.py +709 -0
  131. truthound_dashboard/core/websocket/__init__.py +59 -0
  132. truthound_dashboard/core/websocket/manager.py +512 -0
  133. truthound_dashboard/core/websocket/messages.py +130 -0
  134. truthound_dashboard/db/__init__.py +30 -0
  135. truthound_dashboard/db/models.py +3375 -3
  136. truthound_dashboard/main.py +22 -0
  137. truthound_dashboard/schemas/__init__.py +396 -1
  138. truthound_dashboard/schemas/anomaly.py +1258 -0
  139. truthound_dashboard/schemas/base.py +4 -0
  140. truthound_dashboard/schemas/cross_alerts.py +334 -0
  141. truthound_dashboard/schemas/drift_monitor.py +890 -0
  142. truthound_dashboard/schemas/lineage.py +428 -0
  143. truthound_dashboard/schemas/maintenance.py +154 -0
  144. truthound_dashboard/schemas/model_monitoring.py +374 -0
  145. truthound_dashboard/schemas/notifications_advanced.py +1363 -0
  146. truthound_dashboard/schemas/openlineage.py +704 -0
  147. truthound_dashboard/schemas/plugins.py +1293 -0
  148. truthound_dashboard/schemas/profile.py +420 -34
  149. truthound_dashboard/schemas/profile_comparison.py +242 -0
  150. truthound_dashboard/schemas/reports.py +285 -0
  151. truthound_dashboard/schemas/rule_suggestion.py +434 -0
  152. truthound_dashboard/schemas/schema_evolution.py +164 -0
  153. truthound_dashboard/schemas/source.py +117 -2
  154. truthound_dashboard/schemas/triggers.py +511 -0
  155. truthound_dashboard/schemas/unified_alerts.py +223 -0
  156. truthound_dashboard/schemas/validation.py +25 -1
  157. truthound_dashboard/schemas/validators/__init__.py +11 -0
  158. truthound_dashboard/schemas/validators/base.py +151 -0
  159. truthound_dashboard/schemas/versioning.py +152 -0
  160. truthound_dashboard/static/index.html +2 -2
  161. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -22
  162. truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
  163. truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
  164. truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
  165. truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
  166. truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
  167. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
  168. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
  169. {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)