truthound-dashboard 1.4.4__py3-none-any.whl → 1.5.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 (205) hide show
  1. truthound_dashboard/api/alerts.py +75 -86
  2. truthound_dashboard/api/anomaly.py +7 -13
  3. truthound_dashboard/api/cross_alerts.py +38 -52
  4. truthound_dashboard/api/drift.py +49 -59
  5. truthound_dashboard/api/drift_monitor.py +234 -79
  6. truthound_dashboard/api/enterprise_sampling.py +498 -0
  7. truthound_dashboard/api/history.py +57 -5
  8. truthound_dashboard/api/lineage.py +3 -48
  9. truthound_dashboard/api/maintenance.py +104 -49
  10. truthound_dashboard/api/mask.py +1 -2
  11. truthound_dashboard/api/middleware.py +2 -1
  12. truthound_dashboard/api/model_monitoring.py +435 -311
  13. truthound_dashboard/api/notifications.py +227 -191
  14. truthound_dashboard/api/notifications_advanced.py +21 -20
  15. truthound_dashboard/api/observability.py +586 -0
  16. truthound_dashboard/api/plugins.py +2 -433
  17. truthound_dashboard/api/profile.py +199 -37
  18. truthound_dashboard/api/quality_reporter.py +701 -0
  19. truthound_dashboard/api/reports.py +7 -16
  20. truthound_dashboard/api/router.py +66 -0
  21. truthound_dashboard/api/rule_suggestions.py +5 -5
  22. truthound_dashboard/api/scan.py +17 -19
  23. truthound_dashboard/api/schedules.py +85 -50
  24. truthound_dashboard/api/schema_evolution.py +6 -6
  25. truthound_dashboard/api/schema_watcher.py +667 -0
  26. truthound_dashboard/api/sources.py +98 -27
  27. truthound_dashboard/api/tiering.py +1323 -0
  28. truthound_dashboard/api/triggers.py +14 -11
  29. truthound_dashboard/api/validations.py +12 -11
  30. truthound_dashboard/api/versioning.py +1 -6
  31. truthound_dashboard/core/__init__.py +129 -3
  32. truthound_dashboard/core/actions/__init__.py +62 -0
  33. truthound_dashboard/core/actions/custom.py +426 -0
  34. truthound_dashboard/core/actions/notifications.py +910 -0
  35. truthound_dashboard/core/actions/storage.py +472 -0
  36. truthound_dashboard/core/actions/webhook.py +281 -0
  37. truthound_dashboard/core/anomaly.py +262 -67
  38. truthound_dashboard/core/anomaly_explainer.py +4 -3
  39. truthound_dashboard/core/backends/__init__.py +67 -0
  40. truthound_dashboard/core/backends/base.py +299 -0
  41. truthound_dashboard/core/backends/errors.py +191 -0
  42. truthound_dashboard/core/backends/factory.py +423 -0
  43. truthound_dashboard/core/backends/mock_backend.py +451 -0
  44. truthound_dashboard/core/backends/truthound_backend.py +718 -0
  45. truthound_dashboard/core/checkpoint/__init__.py +87 -0
  46. truthound_dashboard/core/checkpoint/adapters.py +814 -0
  47. truthound_dashboard/core/checkpoint/checkpoint.py +491 -0
  48. truthound_dashboard/core/checkpoint/runner.py +270 -0
  49. truthound_dashboard/core/connections.py +437 -10
  50. truthound_dashboard/core/converters/__init__.py +14 -0
  51. truthound_dashboard/core/converters/truthound.py +620 -0
  52. truthound_dashboard/core/cross_alerts.py +540 -320
  53. truthound_dashboard/core/datasource_factory.py +1672 -0
  54. truthound_dashboard/core/drift_monitor.py +216 -20
  55. truthound_dashboard/core/enterprise_sampling.py +1291 -0
  56. truthound_dashboard/core/interfaces/__init__.py +225 -0
  57. truthound_dashboard/core/interfaces/actions.py +652 -0
  58. truthound_dashboard/core/interfaces/base.py +247 -0
  59. truthound_dashboard/core/interfaces/checkpoint.py +676 -0
  60. truthound_dashboard/core/interfaces/protocols.py +664 -0
  61. truthound_dashboard/core/interfaces/reporters.py +650 -0
  62. truthound_dashboard/core/interfaces/routing.py +646 -0
  63. truthound_dashboard/core/interfaces/triggers.py +619 -0
  64. truthound_dashboard/core/lineage.py +407 -71
  65. truthound_dashboard/core/model_monitoring.py +431 -3
  66. truthound_dashboard/core/notifications/base.py +4 -0
  67. truthound_dashboard/core/notifications/channels.py +501 -1203
  68. truthound_dashboard/core/notifications/deduplication/__init__.py +81 -115
  69. truthound_dashboard/core/notifications/deduplication/service.py +131 -348
  70. truthound_dashboard/core/notifications/dispatcher.py +202 -11
  71. truthound_dashboard/core/notifications/escalation/__init__.py +119 -106
  72. truthound_dashboard/core/notifications/escalation/engine.py +168 -358
  73. truthound_dashboard/core/notifications/routing/__init__.py +88 -128
  74. truthound_dashboard/core/notifications/routing/engine.py +90 -317
  75. truthound_dashboard/core/notifications/stats_aggregator.py +246 -1
  76. truthound_dashboard/core/notifications/throttling/__init__.py +67 -50
  77. truthound_dashboard/core/notifications/throttling/builder.py +117 -255
  78. truthound_dashboard/core/notifications/truthound_adapter.py +842 -0
  79. truthound_dashboard/core/phase5/collaboration.py +1 -1
  80. truthound_dashboard/core/plugins/lifecycle/__init__.py +0 -13
  81. truthound_dashboard/core/quality_reporter.py +1359 -0
  82. truthound_dashboard/core/report_history.py +0 -6
  83. truthound_dashboard/core/reporters/__init__.py +175 -14
  84. truthound_dashboard/core/reporters/adapters.py +943 -0
  85. truthound_dashboard/core/reporters/base.py +0 -3
  86. truthound_dashboard/core/reporters/builtin/__init__.py +18 -0
  87. truthound_dashboard/core/reporters/builtin/csv_reporter.py +111 -0
  88. truthound_dashboard/core/reporters/builtin/html_reporter.py +270 -0
  89. truthound_dashboard/core/reporters/builtin/json_reporter.py +127 -0
  90. truthound_dashboard/core/reporters/compat.py +266 -0
  91. truthound_dashboard/core/reporters/csv_reporter.py +2 -35
  92. truthound_dashboard/core/reporters/factory.py +526 -0
  93. truthound_dashboard/core/reporters/interfaces.py +745 -0
  94. truthound_dashboard/core/reporters/registry.py +1 -10
  95. truthound_dashboard/core/scheduler.py +165 -0
  96. truthound_dashboard/core/schema_evolution.py +3 -3
  97. truthound_dashboard/core/schema_watcher.py +1528 -0
  98. truthound_dashboard/core/services.py +595 -76
  99. truthound_dashboard/core/store_manager.py +810 -0
  100. truthound_dashboard/core/streaming_anomaly.py +169 -4
  101. truthound_dashboard/core/tiering.py +1309 -0
  102. truthound_dashboard/core/triggers/evaluators.py +178 -8
  103. truthound_dashboard/core/truthound_adapter.py +2620 -197
  104. truthound_dashboard/core/unified_alerts.py +23 -20
  105. truthound_dashboard/db/__init__.py +8 -0
  106. truthound_dashboard/db/database.py +8 -2
  107. truthound_dashboard/db/models.py +944 -25
  108. truthound_dashboard/db/repository.py +2 -0
  109. truthound_dashboard/main.py +11 -0
  110. truthound_dashboard/schemas/__init__.py +177 -16
  111. truthound_dashboard/schemas/base.py +44 -23
  112. truthound_dashboard/schemas/collaboration.py +19 -6
  113. truthound_dashboard/schemas/cross_alerts.py +19 -3
  114. truthound_dashboard/schemas/drift.py +61 -55
  115. truthound_dashboard/schemas/drift_monitor.py +67 -23
  116. truthound_dashboard/schemas/enterprise_sampling.py +653 -0
  117. truthound_dashboard/schemas/lineage.py +0 -33
  118. truthound_dashboard/schemas/mask.py +10 -8
  119. truthound_dashboard/schemas/model_monitoring.py +89 -10
  120. truthound_dashboard/schemas/notifications_advanced.py +13 -0
  121. truthound_dashboard/schemas/observability.py +453 -0
  122. truthound_dashboard/schemas/plugins.py +0 -280
  123. truthound_dashboard/schemas/profile.py +154 -247
  124. truthound_dashboard/schemas/quality_reporter.py +403 -0
  125. truthound_dashboard/schemas/reports.py +2 -2
  126. truthound_dashboard/schemas/rule_suggestion.py +8 -1
  127. truthound_dashboard/schemas/scan.py +4 -24
  128. truthound_dashboard/schemas/schedule.py +11 -3
  129. truthound_dashboard/schemas/schema_watcher.py +727 -0
  130. truthound_dashboard/schemas/source.py +17 -2
  131. truthound_dashboard/schemas/tiering.py +822 -0
  132. truthound_dashboard/schemas/triggers.py +16 -0
  133. truthound_dashboard/schemas/unified_alerts.py +7 -0
  134. truthound_dashboard/schemas/validation.py +0 -13
  135. truthound_dashboard/schemas/validators/base.py +41 -21
  136. truthound_dashboard/schemas/validators/business_rule_validators.py +244 -0
  137. truthound_dashboard/schemas/validators/localization_validators.py +273 -0
  138. truthound_dashboard/schemas/validators/ml_feature_validators.py +308 -0
  139. truthound_dashboard/schemas/validators/profiling_validators.py +275 -0
  140. truthound_dashboard/schemas/validators/referential_validators.py +312 -0
  141. truthound_dashboard/schemas/validators/registry.py +93 -8
  142. truthound_dashboard/schemas/validators/timeseries_validators.py +389 -0
  143. truthound_dashboard/schemas/versioning.py +1 -6
  144. truthound_dashboard/static/index.html +2 -2
  145. truthound_dashboard-1.5.0.dist-info/METADATA +309 -0
  146. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/RECORD +149 -148
  147. truthound_dashboard/core/plugins/hooks/__init__.py +0 -63
  148. truthound_dashboard/core/plugins/hooks/decorators.py +0 -367
  149. truthound_dashboard/core/plugins/hooks/manager.py +0 -403
  150. truthound_dashboard/core/plugins/hooks/protocols.py +0 -265
  151. truthound_dashboard/core/plugins/lifecycle/hot_reload.py +0 -584
  152. truthound_dashboard/core/reporters/junit_reporter.py +0 -233
  153. truthound_dashboard/core/reporters/markdown_reporter.py +0 -207
  154. truthound_dashboard/core/reporters/pdf_reporter.py +0 -209
  155. truthound_dashboard/static/assets/_baseUniq-BcrSP13d.js +0 -1
  156. truthound_dashboard/static/assets/arc-DlYjKwIL.js +0 -1
  157. truthound_dashboard/static/assets/architectureDiagram-VXUJARFQ-Bb2drbQM.js +0 -36
  158. truthound_dashboard/static/assets/blockDiagram-VD42YOAC-BlsPG1CH.js +0 -122
  159. truthound_dashboard/static/assets/c4Diagram-YG6GDRKO-B9JdUoaC.js +0 -10
  160. truthound_dashboard/static/assets/channel-Q6mHF1Hd.js +0 -1
  161. truthound_dashboard/static/assets/chunk-4BX2VUAB-DmyoPVuJ.js +0 -1
  162. truthound_dashboard/static/assets/chunk-55IACEB6-Bcz6Siv8.js +0 -1
  163. truthound_dashboard/static/assets/chunk-B4BG7PRW-Br3G5Rum.js +0 -165
  164. truthound_dashboard/static/assets/chunk-DI55MBZ5-DuM9c23u.js +0 -220
  165. truthound_dashboard/static/assets/chunk-FMBD7UC4-DNU-5mvT.js +0 -15
  166. truthound_dashboard/static/assets/chunk-QN33PNHL-Im2yNcmS.js +0 -1
  167. truthound_dashboard/static/assets/chunk-QZHKN3VN-kZr8XFm1.js +0 -1
  168. truthound_dashboard/static/assets/chunk-TZMSLE5B-Q__360q_.js +0 -1
  169. truthound_dashboard/static/assets/classDiagram-2ON5EDUG-vtixxUyK.js +0 -1
  170. truthound_dashboard/static/assets/classDiagram-v2-WZHVMYZB-vtixxUyK.js +0 -1
  171. truthound_dashboard/static/assets/clone-BOt2LwD0.js +0 -1
  172. truthound_dashboard/static/assets/cose-bilkent-S5V4N54A-CBDw6iac.js +0 -1
  173. truthound_dashboard/static/assets/dagre-6UL2VRFP-XdKqmmY9.js +0 -4
  174. truthound_dashboard/static/assets/diagram-PSM6KHXK-DAZ8nx9V.js +0 -24
  175. truthound_dashboard/static/assets/diagram-QEK2KX5R-BRvDTbGD.js +0 -43
  176. truthound_dashboard/static/assets/diagram-S2PKOQOG-bQcczUkl.js +0 -24
  177. truthound_dashboard/static/assets/erDiagram-Q2GNP2WA-DPje7VMN.js +0 -60
  178. truthound_dashboard/static/assets/flowDiagram-NV44I4VS-B7BVtFVS.js +0 -162
  179. truthound_dashboard/static/assets/ganttDiagram-JELNMOA3-D6WKSS7U.js +0 -267
  180. truthound_dashboard/static/assets/gitGraphDiagram-NY62KEGX-D3vtVd3y.js +0 -65
  181. truthound_dashboard/static/assets/graph-BKgNKZVp.js +0 -1
  182. truthound_dashboard/static/assets/index-C6JSrkHo.css +0 -1
  183. truthound_dashboard/static/assets/index-DkU82VsU.js +0 -1800
  184. truthound_dashboard/static/assets/infoDiagram-WHAUD3N6-DnNCT429.js +0 -2
  185. truthound_dashboard/static/assets/journeyDiagram-XKPGCS4Q-DGiMozqS.js +0 -139
  186. truthound_dashboard/static/assets/kanban-definition-3W4ZIXB7-BV2gUgli.js +0 -89
  187. truthound_dashboard/static/assets/katex-Cu_Erd72.js +0 -261
  188. truthound_dashboard/static/assets/layout-DI2MfQ5G.js +0 -1
  189. truthound_dashboard/static/assets/min-DYdgXVcT.js +0 -1
  190. truthound_dashboard/static/assets/mindmap-definition-VGOIOE7T-C7x4ruxz.js +0 -68
  191. truthound_dashboard/static/assets/pieDiagram-ADFJNKIX-CAJaAB9f.js +0 -30
  192. truthound_dashboard/static/assets/quadrantDiagram-AYHSOK5B-DeqwDI46.js +0 -7
  193. truthound_dashboard/static/assets/requirementDiagram-UZGBJVZJ-e3XDpZIM.js +0 -64
  194. truthound_dashboard/static/assets/sankeyDiagram-TZEHDZUN-CNnAv5Ux.js +0 -10
  195. truthound_dashboard/static/assets/sequenceDiagram-WL72ISMW-Dsne-Of3.js +0 -145
  196. truthound_dashboard/static/assets/stateDiagram-FKZM4ZOC-Ee0sQXyb.js +0 -1
  197. truthound_dashboard/static/assets/stateDiagram-v2-4FDKWEC3-B26KqW_W.js +0 -1
  198. truthound_dashboard/static/assets/timeline-definition-IT6M3QCI-DZYi2yl3.js +0 -61
  199. truthound_dashboard/static/assets/treemap-KMMF4GRG-CY3f8In2.js +0 -128
  200. truthound_dashboard/static/assets/unmerged_dictionaries-Dd7xcPWG.js +0 -1
  201. truthound_dashboard/static/assets/xychartDiagram-PRI3JC2R-CS7fydZZ.js +0 -7
  202. truthound_dashboard-1.4.4.dist-info/METADATA +0 -507
  203. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/WHEEL +0 -0
  204. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/entry_points.txt +0 -0
  205. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,12 @@
1
1
  """Sources API endpoints.
2
2
 
3
3
  This module provides CRUD endpoints for managing data sources.
4
+
5
+ API Design: Direct Response Style
6
+ - Single resources return the resource directly
7
+ - List endpoints return PaginatedResponse with data, total, offset, limit
8
+ - Errors are handled via HTTPException
9
+ - Success is indicated by HTTP status codes (200, 201, 204)
4
10
  """
5
11
 
6
12
  from __future__ import annotations
@@ -9,13 +15,18 @@ from typing import Annotated
9
15
 
10
16
  from fastapi import APIRouter, HTTPException, Path, Query
11
17
 
18
+ from pydantic import Field
19
+
12
20
  from truthound_dashboard.schemas import (
13
21
  MessageResponse,
14
22
  SourceCreate,
15
23
  SourceListResponse,
16
24
  SourceResponse,
25
+ SourceTypesResponse,
17
26
  SourceUpdate,
27
+ TestConnectionResponse,
18
28
  )
29
+ from truthound_dashboard.schemas.base import BaseSchema
19
30
 
20
31
  from .deps import SourceServiceDep
21
32
 
@@ -49,11 +60,13 @@ async def list_sources(
49
60
  Returns:
50
61
  Paginated list of sources.
51
62
  """
63
+ # Sequential execution required - SQLAlchemy session doesn't support concurrent operations
52
64
  sources = await service.list(offset=offset, limit=limit, active_only=active_only)
65
+ total = await service.count(active_only=active_only)
53
66
 
54
67
  return SourceListResponse(
55
68
  data=[SourceResponse.from_model(s) for s in sources],
56
- total=len(sources), # TODO: Get actual total count
69
+ total=total,
57
70
  offset=offset,
58
71
  limit=limit,
59
72
  )
@@ -180,16 +193,72 @@ async def delete_source(
180
193
  return MessageResponse(message="Source deleted successfully")
181
194
 
182
195
 
196
+ class BulkDeleteRequest(BaseSchema):
197
+ """Request for bulk delete operation."""
198
+
199
+ ids: list[str] = Field(..., description="List of source IDs to delete")
200
+
201
+
202
+ class BulkDeleteResponse(BaseSchema):
203
+ """Response for bulk delete operation."""
204
+
205
+ deleted_count: int = Field(..., description="Number of successfully deleted sources")
206
+ failed_ids: list[str] = Field(default_factory=list, description="IDs that failed to delete")
207
+ total_requested: int = Field(..., description="Total number of IDs requested")
208
+
209
+
210
+ @router.post(
211
+ "/bulk-delete",
212
+ response_model=BulkDeleteResponse,
213
+ summary="Bulk delete sources",
214
+ description="Delete multiple data sources at once",
215
+ )
216
+ async def bulk_delete_sources(
217
+ service: SourceServiceDep,
218
+ request: BulkDeleteRequest,
219
+ ) -> BulkDeleteResponse:
220
+ """Delete multiple data sources.
221
+
222
+ Args:
223
+ service: Injected source service.
224
+ request: Request with list of source IDs.
225
+
226
+ Returns:
227
+ Result with deleted count and any failed IDs.
228
+ """
229
+ if not request.ids:
230
+ raise HTTPException(status_code=400, detail="No source IDs provided")
231
+
232
+ deleted_count = 0
233
+ failed_ids = []
234
+
235
+ for source_id in request.ids:
236
+ try:
237
+ deleted = await service.delete(source_id)
238
+ if deleted:
239
+ deleted_count += 1
240
+ else:
241
+ failed_ids.append(source_id)
242
+ except Exception:
243
+ failed_ids.append(source_id)
244
+
245
+ return BulkDeleteResponse(
246
+ deleted_count=deleted_count,
247
+ failed_ids=failed_ids,
248
+ total_requested=len(request.ids),
249
+ )
250
+
251
+
183
252
  @router.post(
184
253
  "/{source_id}/test",
185
- response_model=dict,
254
+ response_model=TestConnectionResponse,
186
255
  summary="Test source connection",
187
256
  description="Test connection to a data source",
188
257
  )
189
258
  async def test_source_connection(
190
259
  service: SourceServiceDep,
191
260
  source_id: Annotated[str, Path(description="Source ID")],
192
- ) -> dict:
261
+ ) -> TestConnectionResponse:
193
262
  """Test connection to a data source.
194
263
 
195
264
  Args:
@@ -197,7 +266,7 @@ async def test_source_connection(
197
266
  source_id: Source unique identifier.
198
267
 
199
268
  Returns:
200
- Connection test result with success status and message.
269
+ Connection test result.
201
270
 
202
271
  Raises:
203
272
  HTTPException: 404 if source not found.
@@ -209,16 +278,20 @@ async def test_source_connection(
209
278
  raise HTTPException(status_code=404, detail="Source not found")
210
279
 
211
280
  result = await test_connection(source.type, source.config)
212
- return {"success": True, "data": result}
281
+ return TestConnectionResponse(
282
+ connected=result.get("success", False),
283
+ message=result.get("message"),
284
+ error=result.get("error"),
285
+ )
213
286
 
214
287
 
215
288
  @router.get(
216
289
  "/types/supported",
217
- response_model=dict,
290
+ response_model=SourceTypesResponse,
218
291
  summary="Get supported source types",
219
292
  description="Get list of supported data source types and their configuration",
220
293
  )
221
- async def get_supported_types() -> dict:
294
+ async def get_supported_types() -> SourceTypesResponse:
222
295
  """Get list of supported source types.
223
296
 
224
297
  Returns comprehensive information about each source type including
@@ -232,42 +305,40 @@ async def get_supported_types() -> dict:
232
305
  get_supported_source_types,
233
306
  )
234
307
 
235
- return {
236
- "success": True,
237
- "data": {
238
- "types": get_supported_source_types(),
239
- "categories": get_source_type_categories(),
240
- },
241
- }
308
+ return SourceTypesResponse(
309
+ types=get_supported_source_types(),
310
+ categories=get_source_type_categories(),
311
+ )
312
+
313
+
314
+ from truthound_dashboard.schemas.source import TestConnectionRequest
242
315
 
243
316
 
244
317
  @router.post(
245
318
  "/test-connection",
246
- response_model=dict,
319
+ response_model=TestConnectionResponse,
247
320
  summary="Test connection configuration",
248
321
  description="Test a connection configuration before creating a source",
249
322
  )
250
323
  async def test_connection_config(
251
- request: dict,
252
- ) -> dict:
324
+ request: TestConnectionRequest,
325
+ ) -> TestConnectionResponse:
253
326
  """Test connection configuration before creating a source.
254
327
 
255
328
  This endpoint allows testing connection settings without
256
329
  persisting them to the database.
257
330
 
258
331
  Args:
259
- request: Dictionary with 'type' and 'config' keys.
332
+ request: Connection test request with type and config.
260
333
 
261
334
  Returns:
262
- Connection test result with success status and message.
335
+ Connection test result.
263
336
  """
264
337
  from truthound_dashboard.core.connections import test_connection
265
338
 
266
- source_type = request.get("type")
267
- config = request.get("config", {})
268
-
269
- if not source_type:
270
- raise HTTPException(status_code=400, detail="Source type is required")
271
-
272
- result = await test_connection(source_type, config)
273
- return {"success": True, "data": result}
339
+ result = await test_connection(request.type, request.config)
340
+ return TestConnectionResponse(
341
+ connected=result.get("success", False),
342
+ message=result.get("message"),
343
+ error=result.get("error"),
344
+ )