truthound 1.0.8__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 (877) hide show
  1. truthound/__init__.py +162 -0
  2. truthound/adapters.py +100 -0
  3. truthound/api.py +365 -0
  4. truthound/audit/__init__.py +248 -0
  5. truthound/audit/core.py +967 -0
  6. truthound/audit/filters.py +620 -0
  7. truthound/audit/formatters.py +707 -0
  8. truthound/audit/logger.py +902 -0
  9. truthound/audit/middleware.py +571 -0
  10. truthound/audit/storage.py +1083 -0
  11. truthound/benchmark/__init__.py +123 -0
  12. truthound/benchmark/base.py +757 -0
  13. truthound/benchmark/comparison.py +635 -0
  14. truthound/benchmark/generators.py +706 -0
  15. truthound/benchmark/reporters.py +718 -0
  16. truthound/benchmark/runner.py +635 -0
  17. truthound/benchmark/scenarios.py +712 -0
  18. truthound/cache.py +252 -0
  19. truthound/checkpoint/__init__.py +136 -0
  20. truthound/checkpoint/actions/__init__.py +164 -0
  21. truthound/checkpoint/actions/base.py +324 -0
  22. truthound/checkpoint/actions/custom.py +234 -0
  23. truthound/checkpoint/actions/discord_notify.py +290 -0
  24. truthound/checkpoint/actions/email_notify.py +405 -0
  25. truthound/checkpoint/actions/github_action.py +406 -0
  26. truthound/checkpoint/actions/opsgenie.py +1499 -0
  27. truthound/checkpoint/actions/pagerduty.py +226 -0
  28. truthound/checkpoint/actions/slack_notify.py +233 -0
  29. truthound/checkpoint/actions/store_result.py +249 -0
  30. truthound/checkpoint/actions/teams_notify.py +1570 -0
  31. truthound/checkpoint/actions/telegram_notify.py +419 -0
  32. truthound/checkpoint/actions/update_docs.py +552 -0
  33. truthound/checkpoint/actions/webhook.py +293 -0
  34. truthound/checkpoint/analytics/__init__.py +147 -0
  35. truthound/checkpoint/analytics/aggregations/__init__.py +23 -0
  36. truthound/checkpoint/analytics/aggregations/rollup.py +481 -0
  37. truthound/checkpoint/analytics/aggregations/time_bucket.py +306 -0
  38. truthound/checkpoint/analytics/analyzers/__init__.py +17 -0
  39. truthound/checkpoint/analytics/analyzers/anomaly.py +386 -0
  40. truthound/checkpoint/analytics/analyzers/base.py +270 -0
  41. truthound/checkpoint/analytics/analyzers/forecast.py +421 -0
  42. truthound/checkpoint/analytics/analyzers/trend.py +314 -0
  43. truthound/checkpoint/analytics/models.py +292 -0
  44. truthound/checkpoint/analytics/protocols.py +549 -0
  45. truthound/checkpoint/analytics/service.py +718 -0
  46. truthound/checkpoint/analytics/stores/__init__.py +16 -0
  47. truthound/checkpoint/analytics/stores/base.py +306 -0
  48. truthound/checkpoint/analytics/stores/memory_store.py +353 -0
  49. truthound/checkpoint/analytics/stores/sqlite_store.py +557 -0
  50. truthound/checkpoint/analytics/stores/timescale_store.py +501 -0
  51. truthound/checkpoint/async_actions.py +794 -0
  52. truthound/checkpoint/async_base.py +708 -0
  53. truthound/checkpoint/async_checkpoint.py +617 -0
  54. truthound/checkpoint/async_runner.py +639 -0
  55. truthound/checkpoint/checkpoint.py +527 -0
  56. truthound/checkpoint/ci/__init__.py +61 -0
  57. truthound/checkpoint/ci/detector.py +355 -0
  58. truthound/checkpoint/ci/reporter.py +436 -0
  59. truthound/checkpoint/ci/templates.py +454 -0
  60. truthound/checkpoint/circuitbreaker/__init__.py +133 -0
  61. truthound/checkpoint/circuitbreaker/breaker.py +542 -0
  62. truthound/checkpoint/circuitbreaker/core.py +252 -0
  63. truthound/checkpoint/circuitbreaker/detection.py +459 -0
  64. truthound/checkpoint/circuitbreaker/middleware.py +389 -0
  65. truthound/checkpoint/circuitbreaker/registry.py +357 -0
  66. truthound/checkpoint/distributed/__init__.py +139 -0
  67. truthound/checkpoint/distributed/backends/__init__.py +35 -0
  68. truthound/checkpoint/distributed/backends/celery_backend.py +503 -0
  69. truthound/checkpoint/distributed/backends/kubernetes_backend.py +696 -0
  70. truthound/checkpoint/distributed/backends/local_backend.py +397 -0
  71. truthound/checkpoint/distributed/backends/ray_backend.py +625 -0
  72. truthound/checkpoint/distributed/base.py +774 -0
  73. truthound/checkpoint/distributed/orchestrator.py +765 -0
  74. truthound/checkpoint/distributed/protocols.py +842 -0
  75. truthound/checkpoint/distributed/registry.py +449 -0
  76. truthound/checkpoint/idempotency/__init__.py +120 -0
  77. truthound/checkpoint/idempotency/core.py +295 -0
  78. truthound/checkpoint/idempotency/fingerprint.py +454 -0
  79. truthound/checkpoint/idempotency/locking.py +604 -0
  80. truthound/checkpoint/idempotency/service.py +592 -0
  81. truthound/checkpoint/idempotency/stores.py +653 -0
  82. truthound/checkpoint/monitoring/__init__.py +134 -0
  83. truthound/checkpoint/monitoring/aggregators/__init__.py +15 -0
  84. truthound/checkpoint/monitoring/aggregators/base.py +372 -0
  85. truthound/checkpoint/monitoring/aggregators/realtime.py +300 -0
  86. truthound/checkpoint/monitoring/aggregators/window.py +493 -0
  87. truthound/checkpoint/monitoring/collectors/__init__.py +17 -0
  88. truthound/checkpoint/monitoring/collectors/base.py +257 -0
  89. truthound/checkpoint/monitoring/collectors/memory_collector.py +617 -0
  90. truthound/checkpoint/monitoring/collectors/prometheus_collector.py +451 -0
  91. truthound/checkpoint/monitoring/collectors/redis_collector.py +518 -0
  92. truthound/checkpoint/monitoring/events.py +410 -0
  93. truthound/checkpoint/monitoring/protocols.py +636 -0
  94. truthound/checkpoint/monitoring/service.py +578 -0
  95. truthound/checkpoint/monitoring/views/__init__.py +17 -0
  96. truthound/checkpoint/monitoring/views/base.py +172 -0
  97. truthound/checkpoint/monitoring/views/queue_view.py +220 -0
  98. truthound/checkpoint/monitoring/views/task_view.py +240 -0
  99. truthound/checkpoint/monitoring/views/worker_view.py +263 -0
  100. truthound/checkpoint/registry.py +337 -0
  101. truthound/checkpoint/runner.py +356 -0
  102. truthound/checkpoint/transaction/__init__.py +133 -0
  103. truthound/checkpoint/transaction/base.py +389 -0
  104. truthound/checkpoint/transaction/compensatable.py +537 -0
  105. truthound/checkpoint/transaction/coordinator.py +576 -0
  106. truthound/checkpoint/transaction/executor.py +622 -0
  107. truthound/checkpoint/transaction/idempotency.py +534 -0
  108. truthound/checkpoint/transaction/saga/__init__.py +143 -0
  109. truthound/checkpoint/transaction/saga/builder.py +584 -0
  110. truthound/checkpoint/transaction/saga/definition.py +515 -0
  111. truthound/checkpoint/transaction/saga/event_store.py +542 -0
  112. truthound/checkpoint/transaction/saga/patterns.py +833 -0
  113. truthound/checkpoint/transaction/saga/runner.py +718 -0
  114. truthound/checkpoint/transaction/saga/state_machine.py +793 -0
  115. truthound/checkpoint/transaction/saga/strategies.py +780 -0
  116. truthound/checkpoint/transaction/saga/testing.py +886 -0
  117. truthound/checkpoint/triggers/__init__.py +58 -0
  118. truthound/checkpoint/triggers/base.py +237 -0
  119. truthound/checkpoint/triggers/event.py +385 -0
  120. truthound/checkpoint/triggers/schedule.py +355 -0
  121. truthound/cli.py +2358 -0
  122. truthound/cli_modules/__init__.py +124 -0
  123. truthound/cli_modules/advanced/__init__.py +45 -0
  124. truthound/cli_modules/advanced/benchmark.py +343 -0
  125. truthound/cli_modules/advanced/docs.py +225 -0
  126. truthound/cli_modules/advanced/lineage.py +209 -0
  127. truthound/cli_modules/advanced/ml.py +320 -0
  128. truthound/cli_modules/advanced/realtime.py +196 -0
  129. truthound/cli_modules/checkpoint/__init__.py +46 -0
  130. truthound/cli_modules/checkpoint/init.py +114 -0
  131. truthound/cli_modules/checkpoint/list.py +71 -0
  132. truthound/cli_modules/checkpoint/run.py +159 -0
  133. truthound/cli_modules/checkpoint/validate.py +67 -0
  134. truthound/cli_modules/common/__init__.py +71 -0
  135. truthound/cli_modules/common/errors.py +414 -0
  136. truthound/cli_modules/common/options.py +419 -0
  137. truthound/cli_modules/common/output.py +507 -0
  138. truthound/cli_modules/common/protocol.py +552 -0
  139. truthound/cli_modules/core/__init__.py +48 -0
  140. truthound/cli_modules/core/check.py +123 -0
  141. truthound/cli_modules/core/compare.py +104 -0
  142. truthound/cli_modules/core/learn.py +57 -0
  143. truthound/cli_modules/core/mask.py +77 -0
  144. truthound/cli_modules/core/profile.py +65 -0
  145. truthound/cli_modules/core/scan.py +61 -0
  146. truthound/cli_modules/profiler/__init__.py +51 -0
  147. truthound/cli_modules/profiler/auto_profile.py +175 -0
  148. truthound/cli_modules/profiler/metadata.py +107 -0
  149. truthound/cli_modules/profiler/suite.py +283 -0
  150. truthound/cli_modules/registry.py +431 -0
  151. truthound/cli_modules/scaffolding/__init__.py +89 -0
  152. truthound/cli_modules/scaffolding/base.py +631 -0
  153. truthound/cli_modules/scaffolding/commands.py +545 -0
  154. truthound/cli_modules/scaffolding/plugins.py +1072 -0
  155. truthound/cli_modules/scaffolding/reporters.py +594 -0
  156. truthound/cli_modules/scaffolding/validators.py +1127 -0
  157. truthound/common/__init__.py +18 -0
  158. truthound/common/resilience/__init__.py +130 -0
  159. truthound/common/resilience/bulkhead.py +266 -0
  160. truthound/common/resilience/circuit_breaker.py +516 -0
  161. truthound/common/resilience/composite.py +332 -0
  162. truthound/common/resilience/config.py +292 -0
  163. truthound/common/resilience/protocols.py +217 -0
  164. truthound/common/resilience/rate_limiter.py +404 -0
  165. truthound/common/resilience/retry.py +341 -0
  166. truthound/datadocs/__init__.py +260 -0
  167. truthound/datadocs/base.py +571 -0
  168. truthound/datadocs/builder.py +761 -0
  169. truthound/datadocs/charts.py +764 -0
  170. truthound/datadocs/dashboard/__init__.py +63 -0
  171. truthound/datadocs/dashboard/app.py +576 -0
  172. truthound/datadocs/dashboard/components.py +584 -0
  173. truthound/datadocs/dashboard/state.py +240 -0
  174. truthound/datadocs/engine/__init__.py +46 -0
  175. truthound/datadocs/engine/context.py +376 -0
  176. truthound/datadocs/engine/pipeline.py +618 -0
  177. truthound/datadocs/engine/registry.py +469 -0
  178. truthound/datadocs/exporters/__init__.py +49 -0
  179. truthound/datadocs/exporters/base.py +198 -0
  180. truthound/datadocs/exporters/html.py +178 -0
  181. truthound/datadocs/exporters/json_exporter.py +253 -0
  182. truthound/datadocs/exporters/markdown.py +284 -0
  183. truthound/datadocs/exporters/pdf.py +392 -0
  184. truthound/datadocs/i18n/__init__.py +86 -0
  185. truthound/datadocs/i18n/catalog.py +960 -0
  186. truthound/datadocs/i18n/formatting.py +505 -0
  187. truthound/datadocs/i18n/loader.py +256 -0
  188. truthound/datadocs/i18n/plurals.py +378 -0
  189. truthound/datadocs/renderers/__init__.py +42 -0
  190. truthound/datadocs/renderers/base.py +401 -0
  191. truthound/datadocs/renderers/custom.py +342 -0
  192. truthound/datadocs/renderers/jinja.py +697 -0
  193. truthound/datadocs/sections.py +736 -0
  194. truthound/datadocs/styles.py +931 -0
  195. truthound/datadocs/themes/__init__.py +101 -0
  196. truthound/datadocs/themes/base.py +336 -0
  197. truthound/datadocs/themes/default.py +417 -0
  198. truthound/datadocs/themes/enterprise.py +419 -0
  199. truthound/datadocs/themes/loader.py +336 -0
  200. truthound/datadocs/themes.py +301 -0
  201. truthound/datadocs/transformers/__init__.py +57 -0
  202. truthound/datadocs/transformers/base.py +268 -0
  203. truthound/datadocs/transformers/enrichers.py +544 -0
  204. truthound/datadocs/transformers/filters.py +447 -0
  205. truthound/datadocs/transformers/i18n.py +468 -0
  206. truthound/datadocs/versioning/__init__.py +62 -0
  207. truthound/datadocs/versioning/diff.py +639 -0
  208. truthound/datadocs/versioning/storage.py +497 -0
  209. truthound/datadocs/versioning/version.py +358 -0
  210. truthound/datasources/__init__.py +223 -0
  211. truthound/datasources/_async_protocols.py +222 -0
  212. truthound/datasources/_protocols.py +159 -0
  213. truthound/datasources/adapters.py +428 -0
  214. truthound/datasources/async_base.py +599 -0
  215. truthound/datasources/async_factory.py +511 -0
  216. truthound/datasources/base.py +516 -0
  217. truthound/datasources/factory.py +433 -0
  218. truthound/datasources/nosql/__init__.py +47 -0
  219. truthound/datasources/nosql/base.py +487 -0
  220. truthound/datasources/nosql/elasticsearch.py +801 -0
  221. truthound/datasources/nosql/mongodb.py +636 -0
  222. truthound/datasources/pandas_optimized.py +582 -0
  223. truthound/datasources/pandas_source.py +216 -0
  224. truthound/datasources/polars_source.py +395 -0
  225. truthound/datasources/spark_source.py +479 -0
  226. truthound/datasources/sql/__init__.py +154 -0
  227. truthound/datasources/sql/base.py +710 -0
  228. truthound/datasources/sql/bigquery.py +410 -0
  229. truthound/datasources/sql/cloud_base.py +199 -0
  230. truthound/datasources/sql/databricks.py +471 -0
  231. truthound/datasources/sql/mysql.py +316 -0
  232. truthound/datasources/sql/oracle.py +427 -0
  233. truthound/datasources/sql/postgresql.py +321 -0
  234. truthound/datasources/sql/redshift.py +479 -0
  235. truthound/datasources/sql/snowflake.py +439 -0
  236. truthound/datasources/sql/sqlite.py +286 -0
  237. truthound/datasources/sql/sqlserver.py +437 -0
  238. truthound/datasources/streaming/__init__.py +47 -0
  239. truthound/datasources/streaming/base.py +350 -0
  240. truthound/datasources/streaming/kafka.py +670 -0
  241. truthound/decorators.py +98 -0
  242. truthound/docs/__init__.py +69 -0
  243. truthound/docs/extractor.py +971 -0
  244. truthound/docs/generator.py +601 -0
  245. truthound/docs/parser.py +1037 -0
  246. truthound/docs/renderer.py +999 -0
  247. truthound/drift/__init__.py +22 -0
  248. truthound/drift/compare.py +189 -0
  249. truthound/drift/detectors.py +464 -0
  250. truthound/drift/report.py +160 -0
  251. truthound/execution/__init__.py +65 -0
  252. truthound/execution/_protocols.py +324 -0
  253. truthound/execution/base.py +576 -0
  254. truthound/execution/distributed/__init__.py +179 -0
  255. truthound/execution/distributed/aggregations.py +731 -0
  256. truthound/execution/distributed/arrow_bridge.py +817 -0
  257. truthound/execution/distributed/base.py +550 -0
  258. truthound/execution/distributed/dask_engine.py +976 -0
  259. truthound/execution/distributed/mixins.py +766 -0
  260. truthound/execution/distributed/protocols.py +756 -0
  261. truthound/execution/distributed/ray_engine.py +1127 -0
  262. truthound/execution/distributed/registry.py +446 -0
  263. truthound/execution/distributed/spark_engine.py +1011 -0
  264. truthound/execution/distributed/validator_adapter.py +682 -0
  265. truthound/execution/pandas_engine.py +401 -0
  266. truthound/execution/polars_engine.py +497 -0
  267. truthound/execution/pushdown/__init__.py +230 -0
  268. truthound/execution/pushdown/ast.py +1550 -0
  269. truthound/execution/pushdown/builder.py +1550 -0
  270. truthound/execution/pushdown/dialects.py +1072 -0
  271. truthound/execution/pushdown/executor.py +829 -0
  272. truthound/execution/pushdown/optimizer.py +1041 -0
  273. truthound/execution/sql_engine.py +518 -0
  274. truthound/infrastructure/__init__.py +189 -0
  275. truthound/infrastructure/audit.py +1515 -0
  276. truthound/infrastructure/config.py +1133 -0
  277. truthound/infrastructure/encryption.py +1132 -0
  278. truthound/infrastructure/logging.py +1503 -0
  279. truthound/infrastructure/metrics.py +1220 -0
  280. truthound/lineage/__init__.py +89 -0
  281. truthound/lineage/base.py +746 -0
  282. truthound/lineage/impact_analysis.py +474 -0
  283. truthound/lineage/integrations/__init__.py +22 -0
  284. truthound/lineage/integrations/openlineage.py +548 -0
  285. truthound/lineage/tracker.py +512 -0
  286. truthound/lineage/visualization/__init__.py +33 -0
  287. truthound/lineage/visualization/protocols.py +145 -0
  288. truthound/lineage/visualization/renderers/__init__.py +20 -0
  289. truthound/lineage/visualization/renderers/cytoscape.py +329 -0
  290. truthound/lineage/visualization/renderers/d3.py +331 -0
  291. truthound/lineage/visualization/renderers/graphviz.py +276 -0
  292. truthound/lineage/visualization/renderers/mermaid.py +308 -0
  293. truthound/maskers.py +113 -0
  294. truthound/ml/__init__.py +124 -0
  295. truthound/ml/anomaly_models/__init__.py +31 -0
  296. truthound/ml/anomaly_models/ensemble.py +362 -0
  297. truthound/ml/anomaly_models/isolation_forest.py +444 -0
  298. truthound/ml/anomaly_models/statistical.py +392 -0
  299. truthound/ml/base.py +1178 -0
  300. truthound/ml/drift_detection/__init__.py +26 -0
  301. truthound/ml/drift_detection/concept.py +381 -0
  302. truthound/ml/drift_detection/distribution.py +361 -0
  303. truthound/ml/drift_detection/feature.py +442 -0
  304. truthound/ml/drift_detection/multivariate.py +495 -0
  305. truthound/ml/monitoring/__init__.py +88 -0
  306. truthound/ml/monitoring/alerting/__init__.py +33 -0
  307. truthound/ml/monitoring/alerting/handlers.py +427 -0
  308. truthound/ml/monitoring/alerting/rules.py +508 -0
  309. truthound/ml/monitoring/collectors/__init__.py +19 -0
  310. truthound/ml/monitoring/collectors/composite.py +105 -0
  311. truthound/ml/monitoring/collectors/drift.py +324 -0
  312. truthound/ml/monitoring/collectors/performance.py +179 -0
  313. truthound/ml/monitoring/collectors/quality.py +369 -0
  314. truthound/ml/monitoring/monitor.py +536 -0
  315. truthound/ml/monitoring/protocols.py +451 -0
  316. truthound/ml/monitoring/stores/__init__.py +15 -0
  317. truthound/ml/monitoring/stores/memory.py +201 -0
  318. truthound/ml/monitoring/stores/prometheus.py +296 -0
  319. truthound/ml/rule_learning/__init__.py +25 -0
  320. truthound/ml/rule_learning/constraint_miner.py +443 -0
  321. truthound/ml/rule_learning/pattern_learner.py +499 -0
  322. truthound/ml/rule_learning/profile_learner.py +462 -0
  323. truthound/multitenancy/__init__.py +326 -0
  324. truthound/multitenancy/core.py +852 -0
  325. truthound/multitenancy/integration.py +597 -0
  326. truthound/multitenancy/isolation.py +630 -0
  327. truthound/multitenancy/manager.py +770 -0
  328. truthound/multitenancy/middleware.py +765 -0
  329. truthound/multitenancy/quota.py +537 -0
  330. truthound/multitenancy/resolvers.py +603 -0
  331. truthound/multitenancy/storage.py +703 -0
  332. truthound/observability/__init__.py +307 -0
  333. truthound/observability/context.py +531 -0
  334. truthound/observability/instrumentation.py +611 -0
  335. truthound/observability/logging.py +887 -0
  336. truthound/observability/metrics.py +1157 -0
  337. truthound/observability/tracing/__init__.py +178 -0
  338. truthound/observability/tracing/baggage.py +310 -0
  339. truthound/observability/tracing/config.py +426 -0
  340. truthound/observability/tracing/exporter.py +787 -0
  341. truthound/observability/tracing/integration.py +1018 -0
  342. truthound/observability/tracing/otel/__init__.py +146 -0
  343. truthound/observability/tracing/otel/adapter.py +982 -0
  344. truthound/observability/tracing/otel/bridge.py +1177 -0
  345. truthound/observability/tracing/otel/compat.py +681 -0
  346. truthound/observability/tracing/otel/config.py +691 -0
  347. truthound/observability/tracing/otel/detection.py +327 -0
  348. truthound/observability/tracing/otel/protocols.py +426 -0
  349. truthound/observability/tracing/processor.py +561 -0
  350. truthound/observability/tracing/propagator.py +757 -0
  351. truthound/observability/tracing/provider.py +569 -0
  352. truthound/observability/tracing/resource.py +515 -0
  353. truthound/observability/tracing/sampler.py +487 -0
  354. truthound/observability/tracing/span.py +676 -0
  355. truthound/plugins/__init__.py +198 -0
  356. truthound/plugins/base.py +599 -0
  357. truthound/plugins/cli.py +680 -0
  358. truthound/plugins/dependencies/__init__.py +42 -0
  359. truthound/plugins/dependencies/graph.py +422 -0
  360. truthound/plugins/dependencies/resolver.py +417 -0
  361. truthound/plugins/discovery.py +379 -0
  362. truthound/plugins/docs/__init__.py +46 -0
  363. truthound/plugins/docs/extractor.py +444 -0
  364. truthound/plugins/docs/renderer.py +499 -0
  365. truthound/plugins/enterprise_manager.py +877 -0
  366. truthound/plugins/examples/__init__.py +19 -0
  367. truthound/plugins/examples/custom_validators.py +317 -0
  368. truthound/plugins/examples/slack_notifier.py +312 -0
  369. truthound/plugins/examples/xml_reporter.py +254 -0
  370. truthound/plugins/hooks.py +558 -0
  371. truthound/plugins/lifecycle/__init__.py +43 -0
  372. truthound/plugins/lifecycle/hot_reload.py +402 -0
  373. truthound/plugins/lifecycle/manager.py +371 -0
  374. truthound/plugins/manager.py +736 -0
  375. truthound/plugins/registry.py +338 -0
  376. truthound/plugins/security/__init__.py +93 -0
  377. truthound/plugins/security/exceptions.py +332 -0
  378. truthound/plugins/security/policies.py +348 -0
  379. truthound/plugins/security/protocols.py +643 -0
  380. truthound/plugins/security/sandbox/__init__.py +45 -0
  381. truthound/plugins/security/sandbox/context.py +158 -0
  382. truthound/plugins/security/sandbox/engines/__init__.py +19 -0
  383. truthound/plugins/security/sandbox/engines/container.py +379 -0
  384. truthound/plugins/security/sandbox/engines/noop.py +144 -0
  385. truthound/plugins/security/sandbox/engines/process.py +336 -0
  386. truthound/plugins/security/sandbox/factory.py +211 -0
  387. truthound/plugins/security/signing/__init__.py +57 -0
  388. truthound/plugins/security/signing/service.py +330 -0
  389. truthound/plugins/security/signing/trust_store.py +368 -0
  390. truthound/plugins/security/signing/verifier.py +459 -0
  391. truthound/plugins/versioning/__init__.py +41 -0
  392. truthound/plugins/versioning/constraints.py +297 -0
  393. truthound/plugins/versioning/resolver.py +329 -0
  394. truthound/profiler/__init__.py +1729 -0
  395. truthound/profiler/_lazy.py +452 -0
  396. truthound/profiler/ab_testing/__init__.py +80 -0
  397. truthound/profiler/ab_testing/analysis.py +449 -0
  398. truthound/profiler/ab_testing/base.py +257 -0
  399. truthound/profiler/ab_testing/experiment.py +395 -0
  400. truthound/profiler/ab_testing/tracking.py +368 -0
  401. truthound/profiler/auto_threshold.py +1170 -0
  402. truthound/profiler/base.py +579 -0
  403. truthound/profiler/cache_patterns.py +911 -0
  404. truthound/profiler/caching.py +1303 -0
  405. truthound/profiler/column_profiler.py +712 -0
  406. truthound/profiler/comparison.py +1007 -0
  407. truthound/profiler/custom_patterns.py +1170 -0
  408. truthound/profiler/dashboard/__init__.py +50 -0
  409. truthound/profiler/dashboard/app.py +476 -0
  410. truthound/profiler/dashboard/components.py +457 -0
  411. truthound/profiler/dashboard/config.py +72 -0
  412. truthound/profiler/distributed/__init__.py +83 -0
  413. truthound/profiler/distributed/base.py +281 -0
  414. truthound/profiler/distributed/dask_backend.py +498 -0
  415. truthound/profiler/distributed/local_backend.py +293 -0
  416. truthound/profiler/distributed/profiler.py +304 -0
  417. truthound/profiler/distributed/ray_backend.py +374 -0
  418. truthound/profiler/distributed/spark_backend.py +375 -0
  419. truthound/profiler/distributed.py +1366 -0
  420. truthound/profiler/enterprise_sampling.py +1065 -0
  421. truthound/profiler/errors.py +488 -0
  422. truthound/profiler/evolution/__init__.py +91 -0
  423. truthound/profiler/evolution/alerts.py +426 -0
  424. truthound/profiler/evolution/changes.py +206 -0
  425. truthound/profiler/evolution/compatibility.py +365 -0
  426. truthound/profiler/evolution/detector.py +372 -0
  427. truthound/profiler/evolution/protocols.py +121 -0
  428. truthound/profiler/generators/__init__.py +48 -0
  429. truthound/profiler/generators/base.py +384 -0
  430. truthound/profiler/generators/ml_rules.py +375 -0
  431. truthound/profiler/generators/pattern_rules.py +384 -0
  432. truthound/profiler/generators/schema_rules.py +267 -0
  433. truthound/profiler/generators/stats_rules.py +324 -0
  434. truthound/profiler/generators/suite_generator.py +857 -0
  435. truthound/profiler/i18n.py +1542 -0
  436. truthound/profiler/incremental.py +554 -0
  437. truthound/profiler/incremental_validation.py +1710 -0
  438. truthound/profiler/integration/__init__.py +73 -0
  439. truthound/profiler/integration/adapters.py +345 -0
  440. truthound/profiler/integration/context.py +371 -0
  441. truthound/profiler/integration/executor.py +527 -0
  442. truthound/profiler/integration/naming.py +75 -0
  443. truthound/profiler/integration/protocols.py +243 -0
  444. truthound/profiler/memory.py +1185 -0
  445. truthound/profiler/migration/__init__.py +60 -0
  446. truthound/profiler/migration/base.py +345 -0
  447. truthound/profiler/migration/manager.py +444 -0
  448. truthound/profiler/migration/v1_0_to_v1_1.py +484 -0
  449. truthound/profiler/ml/__init__.py +73 -0
  450. truthound/profiler/ml/base.py +244 -0
  451. truthound/profiler/ml/classifier.py +507 -0
  452. truthound/profiler/ml/feature_extraction.py +604 -0
  453. truthound/profiler/ml/pretrained.py +448 -0
  454. truthound/profiler/ml_inference.py +1276 -0
  455. truthound/profiler/native_patterns.py +815 -0
  456. truthound/profiler/observability.py +1184 -0
  457. truthound/profiler/process_timeout.py +1566 -0
  458. truthound/profiler/progress.py +568 -0
  459. truthound/profiler/progress_callbacks.py +1734 -0
  460. truthound/profiler/quality.py +1345 -0
  461. truthound/profiler/resilience.py +1180 -0
  462. truthound/profiler/sampled_matcher.py +794 -0
  463. truthound/profiler/sampling.py +1288 -0
  464. truthound/profiler/scheduling/__init__.py +82 -0
  465. truthound/profiler/scheduling/protocols.py +214 -0
  466. truthound/profiler/scheduling/scheduler.py +474 -0
  467. truthound/profiler/scheduling/storage.py +457 -0
  468. truthound/profiler/scheduling/triggers.py +449 -0
  469. truthound/profiler/schema.py +603 -0
  470. truthound/profiler/streaming.py +685 -0
  471. truthound/profiler/streaming_patterns.py +1354 -0
  472. truthound/profiler/suite_cli.py +625 -0
  473. truthound/profiler/suite_config.py +789 -0
  474. truthound/profiler/suite_export.py +1268 -0
  475. truthound/profiler/table_profiler.py +547 -0
  476. truthound/profiler/timeout.py +565 -0
  477. truthound/profiler/validation.py +1532 -0
  478. truthound/profiler/visualization/__init__.py +118 -0
  479. truthound/profiler/visualization/base.py +346 -0
  480. truthound/profiler/visualization/generator.py +1259 -0
  481. truthound/profiler/visualization/plotly_renderer.py +811 -0
  482. truthound/profiler/visualization/renderers.py +669 -0
  483. truthound/profiler/visualization/sections.py +540 -0
  484. truthound/profiler/visualization.py +2122 -0
  485. truthound/profiler/yaml_validation.py +1151 -0
  486. truthound/py.typed +0 -0
  487. truthound/ratelimit/__init__.py +248 -0
  488. truthound/ratelimit/algorithms.py +1108 -0
  489. truthound/ratelimit/core.py +573 -0
  490. truthound/ratelimit/integration.py +532 -0
  491. truthound/ratelimit/limiter.py +663 -0
  492. truthound/ratelimit/middleware.py +700 -0
  493. truthound/ratelimit/policy.py +792 -0
  494. truthound/ratelimit/storage.py +763 -0
  495. truthound/rbac/__init__.py +340 -0
  496. truthound/rbac/core.py +976 -0
  497. truthound/rbac/integration.py +760 -0
  498. truthound/rbac/manager.py +1052 -0
  499. truthound/rbac/middleware.py +842 -0
  500. truthound/rbac/policy.py +954 -0
  501. truthound/rbac/storage.py +878 -0
  502. truthound/realtime/__init__.py +141 -0
  503. truthound/realtime/adapters/__init__.py +43 -0
  504. truthound/realtime/adapters/base.py +533 -0
  505. truthound/realtime/adapters/kafka.py +487 -0
  506. truthound/realtime/adapters/kinesis.py +479 -0
  507. truthound/realtime/adapters/mock.py +243 -0
  508. truthound/realtime/base.py +553 -0
  509. truthound/realtime/factory.py +382 -0
  510. truthound/realtime/incremental.py +660 -0
  511. truthound/realtime/processing/__init__.py +67 -0
  512. truthound/realtime/processing/exactly_once.py +575 -0
  513. truthound/realtime/processing/state.py +547 -0
  514. truthound/realtime/processing/windows.py +647 -0
  515. truthound/realtime/protocols.py +569 -0
  516. truthound/realtime/streaming.py +605 -0
  517. truthound/realtime/testing/__init__.py +32 -0
  518. truthound/realtime/testing/containers.py +615 -0
  519. truthound/realtime/testing/fixtures.py +484 -0
  520. truthound/report.py +280 -0
  521. truthound/reporters/__init__.py +46 -0
  522. truthound/reporters/_protocols.py +30 -0
  523. truthound/reporters/base.py +324 -0
  524. truthound/reporters/ci/__init__.py +66 -0
  525. truthound/reporters/ci/azure.py +436 -0
  526. truthound/reporters/ci/base.py +509 -0
  527. truthound/reporters/ci/bitbucket.py +567 -0
  528. truthound/reporters/ci/circleci.py +547 -0
  529. truthound/reporters/ci/detection.py +364 -0
  530. truthound/reporters/ci/factory.py +182 -0
  531. truthound/reporters/ci/github.py +388 -0
  532. truthound/reporters/ci/gitlab.py +471 -0
  533. truthound/reporters/ci/jenkins.py +525 -0
  534. truthound/reporters/console_reporter.py +299 -0
  535. truthound/reporters/factory.py +211 -0
  536. truthound/reporters/html_reporter.py +524 -0
  537. truthound/reporters/json_reporter.py +256 -0
  538. truthound/reporters/markdown_reporter.py +280 -0
  539. truthound/reporters/sdk/__init__.py +174 -0
  540. truthound/reporters/sdk/builder.py +558 -0
  541. truthound/reporters/sdk/mixins.py +1150 -0
  542. truthound/reporters/sdk/schema.py +1493 -0
  543. truthound/reporters/sdk/templates.py +666 -0
  544. truthound/reporters/sdk/testing.py +968 -0
  545. truthound/scanners.py +170 -0
  546. truthound/scheduling/__init__.py +122 -0
  547. truthound/scheduling/cron.py +1136 -0
  548. truthound/scheduling/presets.py +212 -0
  549. truthound/schema.py +275 -0
  550. truthound/secrets/__init__.py +173 -0
  551. truthound/secrets/base.py +618 -0
  552. truthound/secrets/cloud.py +682 -0
  553. truthound/secrets/integration.py +507 -0
  554. truthound/secrets/manager.py +633 -0
  555. truthound/secrets/oidc/__init__.py +172 -0
  556. truthound/secrets/oidc/base.py +902 -0
  557. truthound/secrets/oidc/credential_provider.py +623 -0
  558. truthound/secrets/oidc/exchangers.py +1001 -0
  559. truthound/secrets/oidc/github/__init__.py +110 -0
  560. truthound/secrets/oidc/github/claims.py +718 -0
  561. truthound/secrets/oidc/github/enhanced_provider.py +693 -0
  562. truthound/secrets/oidc/github/trust_policy.py +742 -0
  563. truthound/secrets/oidc/github/verification.py +723 -0
  564. truthound/secrets/oidc/github/workflow.py +691 -0
  565. truthound/secrets/oidc/providers.py +825 -0
  566. truthound/secrets/providers.py +506 -0
  567. truthound/secrets/resolver.py +495 -0
  568. truthound/stores/__init__.py +177 -0
  569. truthound/stores/backends/__init__.py +18 -0
  570. truthound/stores/backends/_protocols.py +340 -0
  571. truthound/stores/backends/azure_blob.py +530 -0
  572. truthound/stores/backends/concurrent_filesystem.py +915 -0
  573. truthound/stores/backends/connection_pool.py +1365 -0
  574. truthound/stores/backends/database.py +743 -0
  575. truthound/stores/backends/filesystem.py +538 -0
  576. truthound/stores/backends/gcs.py +399 -0
  577. truthound/stores/backends/memory.py +354 -0
  578. truthound/stores/backends/s3.py +434 -0
  579. truthound/stores/backpressure/__init__.py +84 -0
  580. truthound/stores/backpressure/base.py +375 -0
  581. truthound/stores/backpressure/circuit_breaker.py +434 -0
  582. truthound/stores/backpressure/monitor.py +376 -0
  583. truthound/stores/backpressure/strategies.py +677 -0
  584. truthound/stores/base.py +551 -0
  585. truthound/stores/batching/__init__.py +65 -0
  586. truthound/stores/batching/base.py +305 -0
  587. truthound/stores/batching/buffer.py +370 -0
  588. truthound/stores/batching/store.py +248 -0
  589. truthound/stores/batching/writer.py +521 -0
  590. truthound/stores/caching/__init__.py +60 -0
  591. truthound/stores/caching/backends.py +684 -0
  592. truthound/stores/caching/base.py +356 -0
  593. truthound/stores/caching/store.py +305 -0
  594. truthound/stores/compression/__init__.py +193 -0
  595. truthound/stores/compression/adaptive.py +694 -0
  596. truthound/stores/compression/base.py +514 -0
  597. truthound/stores/compression/pipeline.py +868 -0
  598. truthound/stores/compression/providers.py +672 -0
  599. truthound/stores/compression/streaming.py +832 -0
  600. truthound/stores/concurrency/__init__.py +81 -0
  601. truthound/stores/concurrency/atomic.py +556 -0
  602. truthound/stores/concurrency/index.py +775 -0
  603. truthound/stores/concurrency/locks.py +576 -0
  604. truthound/stores/concurrency/manager.py +482 -0
  605. truthound/stores/encryption/__init__.py +297 -0
  606. truthound/stores/encryption/base.py +952 -0
  607. truthound/stores/encryption/keys.py +1191 -0
  608. truthound/stores/encryption/pipeline.py +903 -0
  609. truthound/stores/encryption/providers.py +953 -0
  610. truthound/stores/encryption/streaming.py +950 -0
  611. truthound/stores/expectations.py +227 -0
  612. truthound/stores/factory.py +246 -0
  613. truthound/stores/migration/__init__.py +75 -0
  614. truthound/stores/migration/base.py +480 -0
  615. truthound/stores/migration/manager.py +347 -0
  616. truthound/stores/migration/registry.py +382 -0
  617. truthound/stores/migration/store.py +559 -0
  618. truthound/stores/observability/__init__.py +106 -0
  619. truthound/stores/observability/audit.py +718 -0
  620. truthound/stores/observability/config.py +270 -0
  621. truthound/stores/observability/factory.py +208 -0
  622. truthound/stores/observability/metrics.py +636 -0
  623. truthound/stores/observability/protocols.py +410 -0
  624. truthound/stores/observability/store.py +570 -0
  625. truthound/stores/observability/tracing.py +784 -0
  626. truthound/stores/replication/__init__.py +76 -0
  627. truthound/stores/replication/base.py +260 -0
  628. truthound/stores/replication/monitor.py +269 -0
  629. truthound/stores/replication/store.py +439 -0
  630. truthound/stores/replication/syncer.py +391 -0
  631. truthound/stores/results.py +359 -0
  632. truthound/stores/retention/__init__.py +77 -0
  633. truthound/stores/retention/base.py +378 -0
  634. truthound/stores/retention/policies.py +621 -0
  635. truthound/stores/retention/scheduler.py +279 -0
  636. truthound/stores/retention/store.py +526 -0
  637. truthound/stores/streaming/__init__.py +138 -0
  638. truthound/stores/streaming/base.py +801 -0
  639. truthound/stores/streaming/database.py +984 -0
  640. truthound/stores/streaming/filesystem.py +719 -0
  641. truthound/stores/streaming/reader.py +629 -0
  642. truthound/stores/streaming/s3.py +843 -0
  643. truthound/stores/streaming/writer.py +790 -0
  644. truthound/stores/tiering/__init__.py +108 -0
  645. truthound/stores/tiering/base.py +462 -0
  646. truthound/stores/tiering/manager.py +249 -0
  647. truthound/stores/tiering/policies.py +692 -0
  648. truthound/stores/tiering/store.py +526 -0
  649. truthound/stores/versioning/__init__.py +56 -0
  650. truthound/stores/versioning/base.py +376 -0
  651. truthound/stores/versioning/store.py +660 -0
  652. truthound/stores/versioning/strategies.py +353 -0
  653. truthound/types.py +56 -0
  654. truthound/validators/__init__.py +774 -0
  655. truthound/validators/aggregate/__init__.py +27 -0
  656. truthound/validators/aggregate/central.py +116 -0
  657. truthound/validators/aggregate/extremes.py +116 -0
  658. truthound/validators/aggregate/spread.py +118 -0
  659. truthound/validators/aggregate/sum.py +64 -0
  660. truthound/validators/aggregate/type.py +78 -0
  661. truthound/validators/anomaly/__init__.py +93 -0
  662. truthound/validators/anomaly/base.py +431 -0
  663. truthound/validators/anomaly/ml_based.py +1190 -0
  664. truthound/validators/anomaly/multivariate.py +647 -0
  665. truthound/validators/anomaly/statistical.py +599 -0
  666. truthound/validators/base.py +1089 -0
  667. truthound/validators/business_rule/__init__.py +46 -0
  668. truthound/validators/business_rule/base.py +147 -0
  669. truthound/validators/business_rule/checksum.py +509 -0
  670. truthound/validators/business_rule/financial.py +526 -0
  671. truthound/validators/cache.py +733 -0
  672. truthound/validators/completeness/__init__.py +39 -0
  673. truthound/validators/completeness/conditional.py +73 -0
  674. truthound/validators/completeness/default.py +98 -0
  675. truthound/validators/completeness/empty.py +103 -0
  676. truthound/validators/completeness/nan.py +337 -0
  677. truthound/validators/completeness/null.py +152 -0
  678. truthound/validators/cross_table/__init__.py +17 -0
  679. truthound/validators/cross_table/aggregate.py +333 -0
  680. truthound/validators/cross_table/row_count.py +122 -0
  681. truthound/validators/datetime/__init__.py +29 -0
  682. truthound/validators/datetime/format.py +78 -0
  683. truthound/validators/datetime/freshness.py +269 -0
  684. truthound/validators/datetime/order.py +73 -0
  685. truthound/validators/datetime/parseable.py +185 -0
  686. truthound/validators/datetime/range.py +202 -0
  687. truthound/validators/datetime/timezone.py +69 -0
  688. truthound/validators/distribution/__init__.py +49 -0
  689. truthound/validators/distribution/distribution.py +128 -0
  690. truthound/validators/distribution/monotonic.py +119 -0
  691. truthound/validators/distribution/outlier.py +178 -0
  692. truthound/validators/distribution/quantile.py +80 -0
  693. truthound/validators/distribution/range.py +254 -0
  694. truthound/validators/distribution/set.py +125 -0
  695. truthound/validators/distribution/statistical.py +459 -0
  696. truthound/validators/drift/__init__.py +79 -0
  697. truthound/validators/drift/base.py +427 -0
  698. truthound/validators/drift/multi_feature.py +401 -0
  699. truthound/validators/drift/numeric.py +395 -0
  700. truthound/validators/drift/psi.py +446 -0
  701. truthound/validators/drift/statistical.py +510 -0
  702. truthound/validators/enterprise.py +1658 -0
  703. truthound/validators/geospatial/__init__.py +80 -0
  704. truthound/validators/geospatial/base.py +97 -0
  705. truthound/validators/geospatial/boundary.py +238 -0
  706. truthound/validators/geospatial/coordinate.py +351 -0
  707. truthound/validators/geospatial/distance.py +399 -0
  708. truthound/validators/geospatial/polygon.py +665 -0
  709. truthound/validators/i18n/__init__.py +308 -0
  710. truthound/validators/i18n/bidi.py +571 -0
  711. truthound/validators/i18n/catalogs.py +570 -0
  712. truthound/validators/i18n/dialects.py +763 -0
  713. truthound/validators/i18n/extended_catalogs.py +549 -0
  714. truthound/validators/i18n/formatting.py +1434 -0
  715. truthound/validators/i18n/loader.py +1020 -0
  716. truthound/validators/i18n/messages.py +521 -0
  717. truthound/validators/i18n/plural.py +683 -0
  718. truthound/validators/i18n/protocols.py +855 -0
  719. truthound/validators/i18n/tms.py +1162 -0
  720. truthound/validators/localization/__init__.py +53 -0
  721. truthound/validators/localization/base.py +122 -0
  722. truthound/validators/localization/chinese.py +362 -0
  723. truthound/validators/localization/japanese.py +275 -0
  724. truthound/validators/localization/korean.py +524 -0
  725. truthound/validators/memory/__init__.py +94 -0
  726. truthound/validators/memory/approximate_knn.py +506 -0
  727. truthound/validators/memory/base.py +547 -0
  728. truthound/validators/memory/sgd_online.py +719 -0
  729. truthound/validators/memory/streaming_ecdf.py +753 -0
  730. truthound/validators/ml_feature/__init__.py +54 -0
  731. truthound/validators/ml_feature/base.py +249 -0
  732. truthound/validators/ml_feature/correlation.py +299 -0
  733. truthound/validators/ml_feature/leakage.py +344 -0
  734. truthound/validators/ml_feature/null_impact.py +270 -0
  735. truthound/validators/ml_feature/scale.py +264 -0
  736. truthound/validators/multi_column/__init__.py +89 -0
  737. truthound/validators/multi_column/arithmetic.py +284 -0
  738. truthound/validators/multi_column/base.py +231 -0
  739. truthound/validators/multi_column/comparison.py +273 -0
  740. truthound/validators/multi_column/consistency.py +312 -0
  741. truthound/validators/multi_column/statistical.py +299 -0
  742. truthound/validators/optimization/__init__.py +164 -0
  743. truthound/validators/optimization/aggregation.py +563 -0
  744. truthound/validators/optimization/covariance.py +556 -0
  745. truthound/validators/optimization/geo.py +626 -0
  746. truthound/validators/optimization/graph.py +587 -0
  747. truthound/validators/optimization/orchestrator.py +970 -0
  748. truthound/validators/optimization/profiling.py +1312 -0
  749. truthound/validators/privacy/__init__.py +223 -0
  750. truthound/validators/privacy/base.py +635 -0
  751. truthound/validators/privacy/ccpa.py +670 -0
  752. truthound/validators/privacy/gdpr.py +728 -0
  753. truthound/validators/privacy/global_patterns.py +604 -0
  754. truthound/validators/privacy/plugins.py +867 -0
  755. truthound/validators/profiling/__init__.py +52 -0
  756. truthound/validators/profiling/base.py +175 -0
  757. truthound/validators/profiling/cardinality.py +312 -0
  758. truthound/validators/profiling/entropy.py +391 -0
  759. truthound/validators/profiling/frequency.py +455 -0
  760. truthound/validators/pushdown_support.py +660 -0
  761. truthound/validators/query/__init__.py +91 -0
  762. truthound/validators/query/aggregate.py +346 -0
  763. truthound/validators/query/base.py +246 -0
  764. truthound/validators/query/column.py +249 -0
  765. truthound/validators/query/expression.py +274 -0
  766. truthound/validators/query/result.py +323 -0
  767. truthound/validators/query/row_count.py +264 -0
  768. truthound/validators/referential/__init__.py +80 -0
  769. truthound/validators/referential/base.py +395 -0
  770. truthound/validators/referential/cascade.py +391 -0
  771. truthound/validators/referential/circular.py +563 -0
  772. truthound/validators/referential/foreign_key.py +624 -0
  773. truthound/validators/referential/orphan.py +485 -0
  774. truthound/validators/registry.py +112 -0
  775. truthound/validators/schema/__init__.py +41 -0
  776. truthound/validators/schema/column_count.py +142 -0
  777. truthound/validators/schema/column_exists.py +80 -0
  778. truthound/validators/schema/column_order.py +82 -0
  779. truthound/validators/schema/column_pair.py +85 -0
  780. truthound/validators/schema/column_pair_set.py +195 -0
  781. truthound/validators/schema/column_type.py +94 -0
  782. truthound/validators/schema/multi_column.py +53 -0
  783. truthound/validators/schema/multi_column_aggregate.py +175 -0
  784. truthound/validators/schema/referential.py +274 -0
  785. truthound/validators/schema/table_schema.py +91 -0
  786. truthound/validators/schema_validator.py +219 -0
  787. truthound/validators/sdk/__init__.py +250 -0
  788. truthound/validators/sdk/builder.py +680 -0
  789. truthound/validators/sdk/decorators.py +474 -0
  790. truthound/validators/sdk/enterprise/__init__.py +211 -0
  791. truthound/validators/sdk/enterprise/docs.py +725 -0
  792. truthound/validators/sdk/enterprise/fuzzing.py +659 -0
  793. truthound/validators/sdk/enterprise/licensing.py +709 -0
  794. truthound/validators/sdk/enterprise/manager.py +543 -0
  795. truthound/validators/sdk/enterprise/resources.py +628 -0
  796. truthound/validators/sdk/enterprise/sandbox.py +766 -0
  797. truthound/validators/sdk/enterprise/signing.py +603 -0
  798. truthound/validators/sdk/enterprise/templates.py +865 -0
  799. truthound/validators/sdk/enterprise/versioning.py +659 -0
  800. truthound/validators/sdk/templates.py +757 -0
  801. truthound/validators/sdk/testing.py +807 -0
  802. truthound/validators/security/__init__.py +181 -0
  803. truthound/validators/security/redos/__init__.py +182 -0
  804. truthound/validators/security/redos/core.py +861 -0
  805. truthound/validators/security/redos/cpu_monitor.py +593 -0
  806. truthound/validators/security/redos/cve_database.py +791 -0
  807. truthound/validators/security/redos/ml/__init__.py +155 -0
  808. truthound/validators/security/redos/ml/base.py +785 -0
  809. truthound/validators/security/redos/ml/datasets.py +618 -0
  810. truthound/validators/security/redos/ml/features.py +359 -0
  811. truthound/validators/security/redos/ml/models.py +1000 -0
  812. truthound/validators/security/redos/ml/predictor.py +507 -0
  813. truthound/validators/security/redos/ml/storage.py +632 -0
  814. truthound/validators/security/redos/ml/training.py +571 -0
  815. truthound/validators/security/redos/ml_analyzer.py +937 -0
  816. truthound/validators/security/redos/optimizer.py +674 -0
  817. truthound/validators/security/redos/profiler.py +682 -0
  818. truthound/validators/security/redos/re2_engine.py +709 -0
  819. truthound/validators/security/redos.py +886 -0
  820. truthound/validators/security/sql_security.py +1247 -0
  821. truthound/validators/streaming/__init__.py +126 -0
  822. truthound/validators/streaming/base.py +292 -0
  823. truthound/validators/streaming/completeness.py +210 -0
  824. truthound/validators/streaming/mixin.py +575 -0
  825. truthound/validators/streaming/range.py +308 -0
  826. truthound/validators/streaming/sources.py +846 -0
  827. truthound/validators/string/__init__.py +57 -0
  828. truthound/validators/string/casing.py +158 -0
  829. truthound/validators/string/charset.py +96 -0
  830. truthound/validators/string/format.py +501 -0
  831. truthound/validators/string/json.py +77 -0
  832. truthound/validators/string/json_schema.py +184 -0
  833. truthound/validators/string/length.py +104 -0
  834. truthound/validators/string/like_pattern.py +237 -0
  835. truthound/validators/string/regex.py +202 -0
  836. truthound/validators/string/regex_extended.py +435 -0
  837. truthound/validators/table/__init__.py +88 -0
  838. truthound/validators/table/base.py +78 -0
  839. truthound/validators/table/column_count.py +198 -0
  840. truthound/validators/table/freshness.py +362 -0
  841. truthound/validators/table/row_count.py +251 -0
  842. truthound/validators/table/schema.py +333 -0
  843. truthound/validators/table/size.py +285 -0
  844. truthound/validators/timeout/__init__.py +102 -0
  845. truthound/validators/timeout/advanced/__init__.py +247 -0
  846. truthound/validators/timeout/advanced/circuit_breaker.py +675 -0
  847. truthound/validators/timeout/advanced/prediction.py +773 -0
  848. truthound/validators/timeout/advanced/priority.py +618 -0
  849. truthound/validators/timeout/advanced/redis_backend.py +770 -0
  850. truthound/validators/timeout/advanced/retry.py +721 -0
  851. truthound/validators/timeout/advanced/sampling.py +788 -0
  852. truthound/validators/timeout/advanced/sla.py +661 -0
  853. truthound/validators/timeout/advanced/telemetry.py +804 -0
  854. truthound/validators/timeout/cascade.py +477 -0
  855. truthound/validators/timeout/deadline.py +657 -0
  856. truthound/validators/timeout/degradation.py +525 -0
  857. truthound/validators/timeout/distributed.py +597 -0
  858. truthound/validators/timeseries/__init__.py +89 -0
  859. truthound/validators/timeseries/base.py +326 -0
  860. truthound/validators/timeseries/completeness.py +617 -0
  861. truthound/validators/timeseries/gap.py +485 -0
  862. truthound/validators/timeseries/monotonic.py +310 -0
  863. truthound/validators/timeseries/seasonality.py +422 -0
  864. truthound/validators/timeseries/trend.py +510 -0
  865. truthound/validators/uniqueness/__init__.py +59 -0
  866. truthound/validators/uniqueness/approximate.py +475 -0
  867. truthound/validators/uniqueness/distinct_values.py +253 -0
  868. truthound/validators/uniqueness/duplicate.py +118 -0
  869. truthound/validators/uniqueness/primary_key.py +140 -0
  870. truthound/validators/uniqueness/unique.py +191 -0
  871. truthound/validators/uniqueness/within_record.py +599 -0
  872. truthound/validators/utils.py +756 -0
  873. truthound-1.0.8.dist-info/METADATA +474 -0
  874. truthound-1.0.8.dist-info/RECORD +877 -0
  875. truthound-1.0.8.dist-info/WHEEL +4 -0
  876. truthound-1.0.8.dist-info/entry_points.txt +2 -0
  877. truthound-1.0.8.dist-info/licenses/LICENSE +190 -0
@@ -0,0 +1,743 @@
1
+ """SQL Database store backend.
2
+
3
+ This module provides a store implementation that persists data to SQL databases.
4
+ Requires the sqlalchemy package.
5
+
6
+ Features:
7
+ - Enterprise-grade connection pooling with multiple strategies
8
+ - Circuit breaker pattern for fault tolerance
9
+ - Automatic retry with exponential backoff
10
+ - Comprehensive metrics and health monitoring
11
+ - Database-specific optimizations
12
+
13
+ Install with: pip install truthound[database]
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ from dataclasses import dataclass, field
20
+ from datetime import datetime
21
+ from typing import TYPE_CHECKING, Any
22
+
23
+ # Lazy import to avoid ImportError when sqlalchemy is not installed
24
+ try:
25
+ from sqlalchemy import (
26
+ Column,
27
+ DateTime,
28
+ Index,
29
+ Integer,
30
+ String,
31
+ Text,
32
+ create_engine,
33
+ text,
34
+ )
35
+ from sqlalchemy.orm import Session, declarative_base, sessionmaker
36
+ from sqlalchemy.exc import SQLAlchemyError
37
+
38
+ HAS_SQLALCHEMY = True
39
+ Base = declarative_base()
40
+ except ImportError:
41
+ HAS_SQLALCHEMY = False
42
+ Base = object # type: ignore
43
+ SQLAlchemyError = Exception # type: ignore
44
+
45
+ if TYPE_CHECKING:
46
+ from collections.abc import Callable
47
+
48
+ from truthound.stores.backends._protocols import (
49
+ SessionFactoryProtocol,
50
+ SQLEngineProtocol,
51
+ )
52
+ from truthound.stores.backends.connection_pool import (
53
+ ConnectionPoolManager,
54
+ PoolMetrics,
55
+ )
56
+
57
+ from truthound.stores.base import (
58
+ StoreConfig,
59
+ StoreConnectionError,
60
+ StoreNotFoundError,
61
+ StoreQuery,
62
+ StoreReadError,
63
+ StoreWriteError,
64
+ ValidationStore,
65
+ )
66
+ from truthound.stores.results import ValidationResult
67
+
68
+
69
+ def _require_sqlalchemy() -> None:
70
+ """Check if sqlalchemy is available."""
71
+ if not HAS_SQLALCHEMY:
72
+ raise ImportError(
73
+ "sqlalchemy is required for DatabaseStore. "
74
+ "Install with: pip install truthound[database]"
75
+ )
76
+
77
+
78
+ # Define table model only if sqlalchemy is available
79
+ if HAS_SQLALCHEMY:
80
+
81
+ class ValidationResultModel(Base): # type: ignore
82
+ """SQLAlchemy model for validation results."""
83
+
84
+ __tablename__ = "validation_results"
85
+
86
+ id = Column(Integer, primary_key=True, autoincrement=True)
87
+ run_id = Column(String(255), unique=True, nullable=False, index=True)
88
+ data_asset = Column(String(500), nullable=False, index=True)
89
+ run_time = Column(DateTime, nullable=False, index=True)
90
+ status = Column(String(50), nullable=False, index=True)
91
+ namespace = Column(String(255), nullable=False, default="default", index=True)
92
+ tags_json = Column(Text, nullable=True)
93
+ data_json = Column(Text, nullable=False)
94
+ created_at = Column(DateTime, default=datetime.utcnow)
95
+ updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
96
+
97
+ # Create composite indexes
98
+ __table_args__ = (
99
+ Index("ix_namespace_data_asset", "namespace", "data_asset"),
100
+ Index("ix_namespace_run_time", "namespace", "run_time"),
101
+ )
102
+
103
+
104
+ @dataclass
105
+ class PoolingConfig:
106
+ """Advanced connection pooling configuration.
107
+
108
+ Attributes:
109
+ pool_size: Number of connections to maintain in pool.
110
+ max_overflow: Maximum overflow connections beyond pool_size.
111
+ pool_timeout: Seconds to wait for available connection.
112
+ pool_recycle: Seconds before a connection is recycled (-1 = never).
113
+ pool_pre_ping: Whether to test connections before use.
114
+ enable_circuit_breaker: Enable circuit breaker for fault tolerance.
115
+ enable_health_checks: Enable background health monitoring.
116
+ enable_retry: Enable automatic retry on transient errors.
117
+ max_retries: Maximum retry attempts for transient errors.
118
+ retry_base_delay: Base delay between retries in seconds.
119
+ """
120
+
121
+ pool_size: int = 5
122
+ max_overflow: int = 10
123
+ pool_timeout: float = 30.0
124
+ pool_recycle: int = 3600
125
+ pool_pre_ping: bool = True
126
+ enable_circuit_breaker: bool = True
127
+ enable_health_checks: bool = True
128
+ enable_retry: bool = True
129
+ max_retries: int = 3
130
+ retry_base_delay: float = 0.1
131
+
132
+
133
+ @dataclass
134
+ class DatabaseConfig(StoreConfig):
135
+ """Configuration for database store.
136
+
137
+ Attributes:
138
+ connection_url: SQLAlchemy connection URL.
139
+ table_prefix: Prefix for table names.
140
+ pool_size: Connection pool size (deprecated, use pooling.pool_size).
141
+ max_overflow: Maximum overflow connections (deprecated, use pooling.max_overflow).
142
+ echo: Whether to echo SQL statements.
143
+ create_tables: Whether to create tables on initialization.
144
+ pooling: Advanced pooling configuration.
145
+ use_pool_manager: Whether to use the enterprise ConnectionPoolManager.
146
+ """
147
+
148
+ connection_url: str = "sqlite:///.truthound/store.db"
149
+ table_prefix: str = ""
150
+ pool_size: int = 5
151
+ max_overflow: int = 10
152
+ echo: bool = False
153
+ create_tables: bool = True
154
+ pooling: PoolingConfig = field(default_factory=PoolingConfig)
155
+ use_pool_manager: bool = True # Use enterprise pool manager by default
156
+
157
+
158
+ class DatabaseStore(ValidationStore["DatabaseConfig"]):
159
+ """SQL Database validation store.
160
+
161
+ Stores validation results in a SQL database using SQLAlchemy.
162
+ Supports PostgreSQL, MySQL, SQLite, and other SQLAlchemy-compatible databases.
163
+
164
+ Features:
165
+ - Enterprise-grade connection pooling with configurable strategies
166
+ - Circuit breaker pattern for fault tolerance
167
+ - Automatic retry with exponential backoff
168
+ - Health monitoring and metrics collection
169
+ - Database-specific optimizations (PostgreSQL, MySQL, SQLite, etc.)
170
+
171
+ Example:
172
+ >>> # SQLite (default)
173
+ >>> store = DatabaseStore(
174
+ ... connection_url="sqlite:///validations.db"
175
+ ... )
176
+ >>>
177
+ >>> # PostgreSQL with custom pooling
178
+ >>> store = DatabaseStore(
179
+ ... connection_url="postgresql://user:pass@localhost/validations",
180
+ ... pooling=PoolingConfig(
181
+ ... pool_size=10,
182
+ ... max_overflow=20,
183
+ ... enable_circuit_breaker=True,
184
+ ... )
185
+ ... )
186
+ >>>
187
+ >>> result = ValidationResult.from_report(report, "customers.csv")
188
+ >>> run_id = store.save(result)
189
+ >>>
190
+ >>> # Access pool metrics
191
+ >>> print(store.pool_metrics.to_dict())
192
+ """
193
+
194
+ def __init__(
195
+ self,
196
+ connection_url: str = "sqlite:///.truthound/store.db",
197
+ namespace: str = "default",
198
+ pool_size: int = 5,
199
+ max_overflow: int = 10,
200
+ echo: bool = False,
201
+ create_tables: bool = True,
202
+ pooling: PoolingConfig | None = None,
203
+ use_pool_manager: bool = True,
204
+ **kwargs: Any,
205
+ ) -> None:
206
+ """Initialize the database store.
207
+
208
+ Args:
209
+ connection_url: SQLAlchemy connection URL.
210
+ namespace: Namespace for organizing data.
211
+ pool_size: Connection pool size.
212
+ max_overflow: Maximum overflow connections.
213
+ echo: Whether to echo SQL statements.
214
+ create_tables: Whether to create tables on initialization.
215
+ pooling: Advanced pooling configuration (overrides pool_size/max_overflow).
216
+ use_pool_manager: Whether to use enterprise ConnectionPoolManager.
217
+ **kwargs: Additional configuration options.
218
+
219
+ Note:
220
+ Dependency check is handled by the factory. Direct instantiation
221
+ requires sqlalchemy to be installed.
222
+ """
223
+ # Build pooling config from individual params if not provided
224
+ if pooling is None:
225
+ pooling = PoolingConfig(
226
+ pool_size=pool_size,
227
+ max_overflow=max_overflow,
228
+ )
229
+
230
+ config = DatabaseConfig(
231
+ connection_url=connection_url,
232
+ namespace=namespace,
233
+ pool_size=pooling.pool_size,
234
+ max_overflow=pooling.max_overflow,
235
+ echo=echo,
236
+ create_tables=create_tables,
237
+ pooling=pooling,
238
+ use_pool_manager=use_pool_manager,
239
+ **{k: v for k, v in kwargs.items() if hasattr(DatabaseConfig, k)},
240
+ )
241
+ super().__init__(config)
242
+
243
+ # Connection management
244
+ self._engine: SQLEngineProtocol | None = None
245
+ self._session_factory: SessionFactoryProtocol | None = None
246
+ self._pool_manager: ConnectionPoolManager | None = None
247
+
248
+ @classmethod
249
+ def _default_config(cls) -> "DatabaseConfig":
250
+ """Create default configuration."""
251
+ return DatabaseConfig()
252
+
253
+ @property
254
+ def pool_metrics(self) -> "PoolMetrics | None":
255
+ """Get connection pool metrics.
256
+
257
+ Returns:
258
+ Pool metrics if using pool manager, None otherwise.
259
+ """
260
+ if self._pool_manager:
261
+ return self._pool_manager.metrics
262
+ return None
263
+
264
+ @property
265
+ def is_healthy(self) -> bool:
266
+ """Check if database connection is healthy.
267
+
268
+ Returns:
269
+ True if healthy, False otherwise.
270
+ """
271
+ if self._pool_manager:
272
+ return self._pool_manager.is_healthy
273
+ return self._engine is not None
274
+
275
+ def get_pool_status(self) -> dict[str, Any]:
276
+ """Get comprehensive pool status.
277
+
278
+ Returns:
279
+ Dictionary with pool status information.
280
+ """
281
+ if self._pool_manager:
282
+ return self._pool_manager.get_pool_status()
283
+ return {
284
+ "initialized": self._initialized,
285
+ "using_pool_manager": False,
286
+ "config": {
287
+ "connection_url": self._mask_password(self._config.connection_url),
288
+ "pool_size": self._config.pool_size,
289
+ "max_overflow": self._config.max_overflow,
290
+ },
291
+ }
292
+
293
+ def _mask_password(self, url: str) -> str:
294
+ """Mask password in connection URL."""
295
+ import re
296
+
297
+ return re.sub(r"://([^:]+):([^@]+)@", r"://\1:***@", url)
298
+
299
+ def _do_initialize(self) -> None:
300
+ """Initialize the database connection and tables."""
301
+ if self._config.use_pool_manager:
302
+ self._initialize_with_pool_manager()
303
+ else:
304
+ self._initialize_legacy()
305
+
306
+ def _initialize_with_pool_manager(self) -> None:
307
+ """Initialize using enterprise ConnectionPoolManager."""
308
+ try:
309
+ from truthound.stores.backends.connection_pool import (
310
+ CircuitBreakerConfig,
311
+ ConnectionPoolConfig,
312
+ ConnectionPoolManager,
313
+ HealthCheckConfig,
314
+ PoolConfig,
315
+ PoolStrategy,
316
+ RetryConfig,
317
+ )
318
+
319
+ pooling = self._config.pooling
320
+
321
+ # Build pool configuration
322
+ pool_config = PoolConfig(
323
+ strategy=PoolStrategy.QUEUE_POOL,
324
+ pool_size=pooling.pool_size,
325
+ max_overflow=pooling.max_overflow,
326
+ pool_timeout=pooling.pool_timeout,
327
+ pool_recycle=pooling.pool_recycle,
328
+ pool_pre_ping=pooling.pool_pre_ping,
329
+ )
330
+
331
+ # Build retry configuration
332
+ retry_config = RetryConfig(
333
+ max_retries=pooling.max_retries if pooling.enable_retry else 0,
334
+ base_delay=pooling.retry_base_delay,
335
+ )
336
+
337
+ # Build circuit breaker configuration
338
+ circuit_config = CircuitBreakerConfig()
339
+ if not pooling.enable_circuit_breaker:
340
+ circuit_config.failure_threshold = 999999 # Effectively disabled
341
+
342
+ # Build health check configuration
343
+ health_config = HealthCheckConfig(enabled=pooling.enable_health_checks)
344
+
345
+ # Create pool manager configuration
346
+ config = ConnectionPoolConfig(
347
+ connection_url=self._config.connection_url,
348
+ pool=pool_config,
349
+ retry=retry_config,
350
+ circuit_breaker=circuit_config,
351
+ health_check=health_config,
352
+ echo=self._config.echo,
353
+ )
354
+
355
+ # Create and initialize pool manager
356
+ self._pool_manager = ConnectionPoolManager(config)
357
+ self._pool_manager.initialize()
358
+
359
+ # Get engine for table creation
360
+ self._engine = self._pool_manager.get_engine()
361
+
362
+ # Create tables if needed
363
+ if self._config.create_tables:
364
+ Base.metadata.create_all(self._engine)
365
+
366
+ except ImportError:
367
+ # Fall back to legacy initialization
368
+ self._initialize_legacy()
369
+ except SQLAlchemyError as e:
370
+ raise StoreConnectionError("Database", str(e))
371
+
372
+ def _initialize_legacy(self) -> None:
373
+ """Legacy initialization without pool manager."""
374
+ try:
375
+ # Create engine
376
+ connect_args = {}
377
+
378
+ # SQLite specific settings
379
+ if self._config.connection_url.startswith("sqlite"):
380
+ connect_args["check_same_thread"] = False
381
+
382
+ self._engine = create_engine(
383
+ self._config.connection_url,
384
+ pool_size=self._config.pool_size,
385
+ max_overflow=self._config.max_overflow,
386
+ echo=self._config.echo,
387
+ connect_args=connect_args,
388
+ )
389
+
390
+ # Test connection
391
+ with self._engine.connect() as conn:
392
+ conn.execute(text("SELECT 1"))
393
+
394
+ # Create session factory
395
+ self._session_factory = sessionmaker(bind=self._engine)
396
+
397
+ # Create tables if needed
398
+ if self._config.create_tables:
399
+ Base.metadata.create_all(self._engine)
400
+
401
+ except SQLAlchemyError as e:
402
+ raise StoreConnectionError("Database", str(e))
403
+
404
+ def _get_session(self) -> "Session":
405
+ """Get a new database session."""
406
+ if self._pool_manager:
407
+ return self._pool_manager.get_session()
408
+ return self._session_factory()
409
+
410
+ def save(self, item: ValidationResult) -> str:
411
+ """Save a validation result to the database.
412
+
413
+ Args:
414
+ item: The validation result to save.
415
+
416
+ Returns:
417
+ The run ID of the saved result.
418
+
419
+ Raises:
420
+ StoreWriteError: If saving fails.
421
+ """
422
+ self.initialize()
423
+
424
+ try:
425
+ with self._get_session() as session:
426
+ # Check if exists and update, otherwise insert
427
+ existing = (
428
+ session.query(ValidationResultModel)
429
+ .filter(ValidationResultModel.run_id == item.run_id)
430
+ .first()
431
+ )
432
+
433
+ data_json = json.dumps(item.to_dict(), default=str)
434
+ tags_json = json.dumps(item.tags, default=str)
435
+
436
+ if existing:
437
+ existing.data_asset = item.data_asset
438
+ existing.run_time = item.run_time
439
+ existing.status = item.status.value
440
+ existing.namespace = self._config.namespace
441
+ existing.tags_json = tags_json
442
+ existing.data_json = data_json
443
+ else:
444
+ model = ValidationResultModel(
445
+ run_id=item.run_id,
446
+ data_asset=item.data_asset,
447
+ run_time=item.run_time,
448
+ status=item.status.value,
449
+ namespace=self._config.namespace,
450
+ tags_json=tags_json,
451
+ data_json=data_json,
452
+ )
453
+ session.add(model)
454
+
455
+ session.commit()
456
+ return item.run_id
457
+
458
+ except SQLAlchemyError as e:
459
+ raise StoreWriteError(f"Failed to save to database: {e}")
460
+
461
+ def get(self, item_id: str) -> ValidationResult:
462
+ """Retrieve a validation result from the database.
463
+
464
+ Args:
465
+ item_id: The run ID of the result to retrieve.
466
+
467
+ Returns:
468
+ The validation result.
469
+
470
+ Raises:
471
+ StoreNotFoundError: If the result doesn't exist.
472
+ StoreReadError: If reading fails.
473
+ """
474
+ self.initialize()
475
+
476
+ try:
477
+ with self._get_session() as session:
478
+ model = (
479
+ session.query(ValidationResultModel)
480
+ .filter(
481
+ ValidationResultModel.run_id == item_id,
482
+ ValidationResultModel.namespace == self._config.namespace,
483
+ )
484
+ .first()
485
+ )
486
+
487
+ if not model:
488
+ raise StoreNotFoundError("ValidationResult", item_id)
489
+
490
+ data = json.loads(model.data_json)
491
+ return ValidationResult.from_dict(data)
492
+
493
+ except StoreNotFoundError:
494
+ raise
495
+ except (json.JSONDecodeError, SQLAlchemyError) as e:
496
+ raise StoreReadError(f"Failed to read from database: {e}")
497
+
498
+ def exists(self, item_id: str) -> bool:
499
+ """Check if a validation result exists.
500
+
501
+ Args:
502
+ item_id: The run ID to check.
503
+
504
+ Returns:
505
+ True if the result exists.
506
+ """
507
+ self.initialize()
508
+
509
+ try:
510
+ with self._get_session() as session:
511
+ count = (
512
+ session.query(ValidationResultModel)
513
+ .filter(
514
+ ValidationResultModel.run_id == item_id,
515
+ ValidationResultModel.namespace == self._config.namespace,
516
+ )
517
+ .count()
518
+ )
519
+ return count > 0
520
+
521
+ except SQLAlchemyError:
522
+ return False
523
+
524
+ def delete(self, item_id: str) -> bool:
525
+ """Delete a validation result from the database.
526
+
527
+ Args:
528
+ item_id: The run ID of the result to delete.
529
+
530
+ Returns:
531
+ True if the result was deleted, False if it didn't exist.
532
+
533
+ Raises:
534
+ StoreWriteError: If deletion fails.
535
+ """
536
+ self.initialize()
537
+
538
+ try:
539
+ with self._get_session() as session:
540
+ deleted = (
541
+ session.query(ValidationResultModel)
542
+ .filter(
543
+ ValidationResultModel.run_id == item_id,
544
+ ValidationResultModel.namespace == self._config.namespace,
545
+ )
546
+ .delete()
547
+ )
548
+ session.commit()
549
+ return deleted > 0
550
+
551
+ except SQLAlchemyError as e:
552
+ raise StoreWriteError(f"Failed to delete from database: {e}")
553
+
554
+ def list_ids(self, query: StoreQuery | None = None) -> list[str]:
555
+ """List validation result IDs matching the query.
556
+
557
+ Args:
558
+ query: Optional query to filter results.
559
+
560
+ Returns:
561
+ List of matching run IDs.
562
+ """
563
+ self.initialize()
564
+
565
+ try:
566
+ with self._get_session() as session:
567
+ q = session.query(ValidationResultModel.run_id).filter(
568
+ ValidationResultModel.namespace == self._config.namespace
569
+ )
570
+
571
+ if query:
572
+ if query.data_asset:
573
+ q = q.filter(ValidationResultModel.data_asset == query.data_asset)
574
+ if query.status:
575
+ q = q.filter(ValidationResultModel.status == query.status)
576
+ if query.start_time:
577
+ q = q.filter(ValidationResultModel.run_time >= query.start_time)
578
+ if query.end_time:
579
+ q = q.filter(ValidationResultModel.run_time <= query.end_time)
580
+
581
+ # Sorting
582
+ order_column = getattr(
583
+ ValidationResultModel,
584
+ query.order_by if query.order_by != "run_time" else "run_time",
585
+ ValidationResultModel.run_time,
586
+ )
587
+ if query.ascending:
588
+ q = q.order_by(order_column.asc())
589
+ else:
590
+ q = q.order_by(order_column.desc())
591
+
592
+ # Pagination
593
+ if query.offset:
594
+ q = q.offset(query.offset)
595
+ if query.limit:
596
+ q = q.limit(query.limit)
597
+ else:
598
+ q = q.order_by(ValidationResultModel.run_time.desc())
599
+
600
+ return [row[0] for row in q.all()]
601
+
602
+ except SQLAlchemyError:
603
+ return []
604
+
605
+ def query(self, query: StoreQuery) -> list[ValidationResult]:
606
+ """Query validation results from the database.
607
+
608
+ Args:
609
+ query: Query parameters for filtering.
610
+
611
+ Returns:
612
+ List of matching validation results.
613
+ """
614
+ self.initialize()
615
+
616
+ try:
617
+ with self._get_session() as session:
618
+ q = session.query(ValidationResultModel).filter(
619
+ ValidationResultModel.namespace == self._config.namespace
620
+ )
621
+
622
+ if query.data_asset:
623
+ q = q.filter(ValidationResultModel.data_asset == query.data_asset)
624
+ if query.status:
625
+ q = q.filter(ValidationResultModel.status == query.status)
626
+ if query.start_time:
627
+ q = q.filter(ValidationResultModel.run_time >= query.start_time)
628
+ if query.end_time:
629
+ q = q.filter(ValidationResultModel.run_time <= query.end_time)
630
+
631
+ # Sorting
632
+ if query.ascending:
633
+ q = q.order_by(ValidationResultModel.run_time.asc())
634
+ else:
635
+ q = q.order_by(ValidationResultModel.run_time.desc())
636
+
637
+ # Pagination
638
+ if query.offset:
639
+ q = q.offset(query.offset)
640
+ if query.limit:
641
+ q = q.limit(query.limit)
642
+
643
+ results: list[ValidationResult] = []
644
+ for model in q.all():
645
+ try:
646
+ data = json.loads(model.data_json)
647
+ results.append(ValidationResult.from_dict(data))
648
+ except (json.JSONDecodeError, KeyError):
649
+ continue
650
+
651
+ return results
652
+
653
+ except SQLAlchemyError:
654
+ return []
655
+
656
+ def count(self, query: StoreQuery | None = None) -> int:
657
+ """Count validation results matching the query.
658
+
659
+ Args:
660
+ query: Optional query to filter.
661
+
662
+ Returns:
663
+ Number of matching results.
664
+ """
665
+ self.initialize()
666
+
667
+ try:
668
+ with self._get_session() as session:
669
+ q = session.query(ValidationResultModel).filter(
670
+ ValidationResultModel.namespace == self._config.namespace
671
+ )
672
+
673
+ if query:
674
+ if query.data_asset:
675
+ q = q.filter(ValidationResultModel.data_asset == query.data_asset)
676
+ if query.status:
677
+ q = q.filter(ValidationResultModel.status == query.status)
678
+ if query.start_time:
679
+ q = q.filter(ValidationResultModel.run_time >= query.start_time)
680
+ if query.end_time:
681
+ q = q.filter(ValidationResultModel.run_time <= query.end_time)
682
+
683
+ return q.count()
684
+
685
+ except SQLAlchemyError:
686
+ return 0
687
+
688
+ def close(self) -> None:
689
+ """Close the database connection and release all resources."""
690
+ if self._pool_manager:
691
+ self._pool_manager.dispose()
692
+ self._pool_manager = None
693
+ self._engine = None
694
+ elif self._engine:
695
+ self._engine.dispose()
696
+ self._engine = None
697
+ self._session_factory = None
698
+
699
+ def recycle_connections(self) -> int:
700
+ """Manually recycle all pool connections.
701
+
702
+ Useful for forcing reconnection after configuration changes
703
+ or when connections have become stale.
704
+
705
+ Returns:
706
+ Number of connections recycled.
707
+ """
708
+ if self._pool_manager:
709
+ return self._pool_manager.recycle_connections()
710
+ return 0
711
+
712
+ def execute_with_retry(
713
+ self,
714
+ operation: "Callable[[Session], Any]",
715
+ ) -> Any:
716
+ """Execute database operation with automatic retry.
717
+
718
+ Uses exponential backoff for transient errors.
719
+
720
+ Args:
721
+ operation: Callable that takes a session and returns a result.
722
+
723
+ Returns:
724
+ Result of the operation.
725
+
726
+ Raises:
727
+ SQLAlchemyError: If all retries exhausted.
728
+
729
+ Example:
730
+ >>> def insert_data(session):
731
+ ... session.execute(text("INSERT INTO ..."))
732
+ ... return session.execute(text("SELECT ...")).scalar()
733
+ >>> result = store.execute_with_retry(insert_data)
734
+ """
735
+ if self._pool_manager:
736
+ return self._pool_manager.execute_with_retry(operation)
737
+
738
+ # Legacy fallback - no retry
739
+ self.initialize()
740
+ with self._get_session() as session:
741
+ result = operation(session)
742
+ session.commit()
743
+ return result