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,773 @@
1
+ """Performance prediction models for execution time estimation.
2
+
3
+ This module provides historical data-based prediction models for
4
+ estimating validator execution times. It enables:
5
+ - Proactive timeout configuration
6
+ - Resource planning
7
+ - SLA compliance prediction
8
+
9
+ Multiple prediction models are supported:
10
+ - Moving Average: Simple rolling average
11
+ - Exponential Smoothing: Recent data weighted more heavily
12
+ - Quantile Regression: Predict percentiles for safety margins
13
+
14
+ Example:
15
+ from truthound.validators.timeout.advanced.prediction import (
16
+ PerformancePredictor,
17
+ predict_execution_time,
18
+ )
19
+
20
+ predictor = PerformancePredictor()
21
+
22
+ # Record historical executions
23
+ predictor.record("null_check", 150.0, {"rows": 10000})
24
+ predictor.record("null_check", 145.0, {"rows": 10000})
25
+ predictor.record("null_check", 160.0, {"rows": 10000})
26
+
27
+ # Predict execution time
28
+ prediction = predictor.predict("null_check", {"rows": 10000})
29
+ print(f"Predicted: {prediction.estimated_ms:.0f}ms")
30
+ print(f"P95 estimate: {prediction.p95_ms:.0f}ms")
31
+ """
32
+
33
+ from __future__ import annotations
34
+
35
+ import math
36
+ import statistics
37
+ import threading
38
+ import time
39
+ from abc import ABC, abstractmethod
40
+ from collections import defaultdict, deque
41
+ from dataclasses import dataclass, field
42
+ from datetime import datetime, timezone
43
+ from typing import Any, Deque
44
+
45
+
46
+ @dataclass
47
+ class ExecutionRecord:
48
+ """Record of a single execution.
49
+
50
+ Attributes:
51
+ operation: Operation name
52
+ duration_ms: Execution duration in milliseconds
53
+ features: Features (e.g., row count, column count)
54
+ timestamp: When the execution occurred
55
+ success: Whether execution succeeded
56
+ metadata: Additional metadata
57
+ """
58
+
59
+ operation: str
60
+ duration_ms: float
61
+ features: dict[str, Any] = field(default_factory=dict)
62
+ timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
63
+ success: bool = True
64
+ metadata: dict[str, Any] = field(default_factory=dict)
65
+
66
+
67
+ @dataclass
68
+ class ExecutionHistory:
69
+ """History of execution records for an operation.
70
+
71
+ Maintains a sliding window of recent executions for analysis.
72
+ """
73
+
74
+ max_size: int = 1000
75
+ _records: Deque[ExecutionRecord] = field(default_factory=lambda: deque(maxlen=1000))
76
+
77
+ def __post_init__(self) -> None:
78
+ """Initialize with proper maxlen."""
79
+ self._records = deque(maxlen=self.max_size)
80
+
81
+ def add(self, record: ExecutionRecord) -> None:
82
+ """Add a record to history."""
83
+ self._records.append(record)
84
+
85
+ def get_durations(self) -> list[float]:
86
+ """Get list of durations."""
87
+ return [r.duration_ms for r in self._records]
88
+
89
+ def get_recent(self, n: int = 10) -> list[ExecutionRecord]:
90
+ """Get N most recent records."""
91
+ return list(self._records)[-n:]
92
+
93
+ def filter_by_features(
94
+ self,
95
+ features: dict[str, Any],
96
+ tolerance: float = 0.2,
97
+ ) -> list[ExecutionRecord]:
98
+ """Filter records by similar features.
99
+
100
+ Args:
101
+ features: Features to match
102
+ tolerance: Tolerance for numeric comparisons (0.2 = 20%)
103
+
104
+ Returns:
105
+ Matching records
106
+ """
107
+ matching = []
108
+ for record in self._records:
109
+ if self._features_match(record.features, features, tolerance):
110
+ matching.append(record)
111
+ return matching
112
+
113
+ def _features_match(
114
+ self,
115
+ record_features: dict[str, Any],
116
+ target_features: dict[str, Any],
117
+ tolerance: float,
118
+ ) -> bool:
119
+ """Check if features match within tolerance."""
120
+ for key, target_value in target_features.items():
121
+ if key not in record_features:
122
+ continue
123
+ record_value = record_features[key]
124
+
125
+ if isinstance(target_value, (int, float)) and isinstance(record_value, (int, float)):
126
+ if target_value == 0:
127
+ if record_value != 0:
128
+ return False
129
+ elif abs(record_value - target_value) / abs(target_value) > tolerance:
130
+ return False
131
+ elif record_value != target_value:
132
+ return False
133
+
134
+ return True
135
+
136
+ def __len__(self) -> int:
137
+ return len(self._records)
138
+
139
+
140
+ @dataclass
141
+ class PredictionResult:
142
+ """Result of a performance prediction.
143
+
144
+ Attributes:
145
+ operation: Operation name
146
+ estimated_ms: Estimated execution time in milliseconds
147
+ confidence: Confidence level (0.0-1.0)
148
+ p50_ms: 50th percentile estimate
149
+ p90_ms: 90th percentile estimate
150
+ p95_ms: 95th percentile estimate
151
+ p99_ms: 99th percentile estimate
152
+ sample_count: Number of samples used for prediction
153
+ model_used: Name of prediction model used
154
+ features: Features used for prediction
155
+ metadata: Additional metadata
156
+ """
157
+
158
+ operation: str
159
+ estimated_ms: float
160
+ confidence: float = 0.5
161
+ p50_ms: float | None = None
162
+ p90_ms: float | None = None
163
+ p95_ms: float | None = None
164
+ p99_ms: float | None = None
165
+ sample_count: int = 0
166
+ model_used: str = "unknown"
167
+ features: dict[str, Any] = field(default_factory=dict)
168
+ metadata: dict[str, Any] = field(default_factory=dict)
169
+
170
+ @property
171
+ def suggested_timeout_ms(self) -> float:
172
+ """Get suggested timeout (P95 with 20% buffer)."""
173
+ if self.p95_ms is not None:
174
+ return self.p95_ms * 1.2
175
+ return self.estimated_ms * 2.0
176
+
177
+ def to_dict(self) -> dict[str, Any]:
178
+ """Convert to dictionary."""
179
+ return {
180
+ "operation": self.operation,
181
+ "estimated_ms": self.estimated_ms,
182
+ "confidence": self.confidence,
183
+ "p50_ms": self.p50_ms,
184
+ "p90_ms": self.p90_ms,
185
+ "p95_ms": self.p95_ms,
186
+ "p99_ms": self.p99_ms,
187
+ "suggested_timeout_ms": self.suggested_timeout_ms,
188
+ "sample_count": self.sample_count,
189
+ "model_used": self.model_used,
190
+ }
191
+
192
+
193
+ class PredictionModel(ABC):
194
+ """Base class for prediction models."""
195
+
196
+ @property
197
+ @abstractmethod
198
+ def name(self) -> str:
199
+ """Model name."""
200
+ pass
201
+
202
+ @abstractmethod
203
+ def predict(
204
+ self,
205
+ history: ExecutionHistory,
206
+ features: dict[str, Any] | None = None,
207
+ ) -> PredictionResult:
208
+ """Make a prediction based on history.
209
+
210
+ Args:
211
+ history: Execution history
212
+ features: Optional features for feature-based prediction
213
+
214
+ Returns:
215
+ PredictionResult
216
+ """
217
+ pass
218
+
219
+
220
+ class MovingAverageModel(PredictionModel):
221
+ """Simple moving average prediction model.
222
+
223
+ Uses the mean of the last N executions.
224
+ """
225
+
226
+ def __init__(self, window_size: int = 20):
227
+ """Initialize moving average model.
228
+
229
+ Args:
230
+ window_size: Number of recent executions to average
231
+ """
232
+ self.window_size = window_size
233
+
234
+ @property
235
+ def name(self) -> str:
236
+ return f"moving_average_{self.window_size}"
237
+
238
+ def predict(
239
+ self,
240
+ history: ExecutionHistory,
241
+ features: dict[str, Any] | None = None,
242
+ ) -> PredictionResult:
243
+ """Predict using moving average."""
244
+ durations = history.get_durations()
245
+ if not durations:
246
+ return PredictionResult(
247
+ operation="unknown",
248
+ estimated_ms=0.0,
249
+ confidence=0.0,
250
+ model_used=self.name,
251
+ )
252
+
253
+ # Use recent values
254
+ recent = durations[-self.window_size:]
255
+ n = len(recent)
256
+
257
+ mean = statistics.mean(recent)
258
+ confidence = min(1.0, n / self.window_size)
259
+
260
+ # Calculate percentiles
261
+ sorted_recent = sorted(recent)
262
+ p50 = sorted_recent[n // 2] if n > 0 else mean
263
+ p90 = sorted_recent[int(n * 0.9)] if n >= 10 else mean * 1.5
264
+ p95 = sorted_recent[int(n * 0.95)] if n >= 20 else mean * 1.8
265
+ p99 = sorted_recent[int(n * 0.99)] if n >= 100 else mean * 2.5
266
+
267
+ return PredictionResult(
268
+ operation="",
269
+ estimated_ms=mean,
270
+ confidence=confidence,
271
+ p50_ms=p50,
272
+ p90_ms=p90,
273
+ p95_ms=p95,
274
+ p99_ms=p99,
275
+ sample_count=n,
276
+ model_used=self.name,
277
+ features=features or {},
278
+ )
279
+
280
+
281
+ class ExponentialSmoothingModel(PredictionModel):
282
+ """Exponential smoothing prediction model.
283
+
284
+ Gives more weight to recent observations.
285
+ """
286
+
287
+ def __init__(self, alpha: float = 0.3):
288
+ """Initialize exponential smoothing model.
289
+
290
+ Args:
291
+ alpha: Smoothing factor (0.0-1.0), higher = more weight on recent
292
+ """
293
+ self.alpha = alpha
294
+
295
+ @property
296
+ def name(self) -> str:
297
+ return f"exponential_smoothing_{self.alpha}"
298
+
299
+ def predict(
300
+ self,
301
+ history: ExecutionHistory,
302
+ features: dict[str, Any] | None = None,
303
+ ) -> PredictionResult:
304
+ """Predict using exponential smoothing."""
305
+ durations = history.get_durations()
306
+ if not durations:
307
+ return PredictionResult(
308
+ operation="unknown",
309
+ estimated_ms=0.0,
310
+ confidence=0.0,
311
+ model_used=self.name,
312
+ )
313
+
314
+ # Exponential smoothing
315
+ smoothed = durations[0]
316
+ for value in durations[1:]:
317
+ smoothed = self.alpha * value + (1 - self.alpha) * smoothed
318
+
319
+ n = len(durations)
320
+ confidence = min(1.0, n / 20)
321
+
322
+ # Calculate variance for percentiles
323
+ if n > 1:
324
+ variance = statistics.variance(durations)
325
+ std_dev = math.sqrt(variance)
326
+ else:
327
+ std_dev = smoothed * 0.3 # Assume 30% variability
328
+
329
+ return PredictionResult(
330
+ operation="",
331
+ estimated_ms=smoothed,
332
+ confidence=confidence,
333
+ p50_ms=smoothed,
334
+ p90_ms=smoothed + 1.28 * std_dev,
335
+ p95_ms=smoothed + 1.645 * std_dev,
336
+ p99_ms=smoothed + 2.326 * std_dev,
337
+ sample_count=n,
338
+ model_used=self.name,
339
+ features=features or {},
340
+ )
341
+
342
+
343
+ class QuantileRegressionModel(PredictionModel):
344
+ """Quantile regression model for percentile prediction.
345
+
346
+ This model directly estimates percentiles from the data,
347
+ providing more accurate tail estimates for timeout planning.
348
+ """
349
+
350
+ def __init__(self, quantiles: list[float] | None = None):
351
+ """Initialize quantile regression model.
352
+
353
+ Args:
354
+ quantiles: Quantiles to estimate (default: [0.5, 0.9, 0.95, 0.99])
355
+ """
356
+ self.quantiles = quantiles or [0.5, 0.9, 0.95, 0.99]
357
+
358
+ @property
359
+ def name(self) -> str:
360
+ return "quantile_regression"
361
+
362
+ def predict(
363
+ self,
364
+ history: ExecutionHistory,
365
+ features: dict[str, Any] | None = None,
366
+ ) -> PredictionResult:
367
+ """Predict using quantile regression."""
368
+ # Filter by features if provided
369
+ if features:
370
+ records = history.filter_by_features(features)
371
+ durations = [r.duration_ms for r in records]
372
+ else:
373
+ durations = history.get_durations()
374
+
375
+ if not durations:
376
+ return PredictionResult(
377
+ operation="unknown",
378
+ estimated_ms=0.0,
379
+ confidence=0.0,
380
+ model_used=self.name,
381
+ )
382
+
383
+ n = len(durations)
384
+ sorted_durations = sorted(durations)
385
+
386
+ def get_quantile(q: float) -> float:
387
+ """Get quantile value."""
388
+ idx = int(n * q)
389
+ idx = max(0, min(idx, n - 1))
390
+ return sorted_durations[idx]
391
+
392
+ p50 = get_quantile(0.5)
393
+ p90 = get_quantile(0.9)
394
+ p95 = get_quantile(0.95)
395
+ p99 = get_quantile(0.99)
396
+
397
+ # Confidence based on sample size
398
+ confidence = min(1.0, n / 50)
399
+
400
+ return PredictionResult(
401
+ operation="",
402
+ estimated_ms=p50, # Use median as estimate
403
+ confidence=confidence,
404
+ p50_ms=p50,
405
+ p90_ms=p90,
406
+ p95_ms=p95,
407
+ p99_ms=p99,
408
+ sample_count=n,
409
+ model_used=self.name,
410
+ features=features or {},
411
+ )
412
+
413
+
414
+ class FeatureBasedModel(PredictionModel):
415
+ """Feature-based prediction model.
416
+
417
+ Uses linear regression on features (e.g., row count) to
418
+ predict execution time.
419
+ """
420
+
421
+ def __init__(self, feature_key: str = "rows"):
422
+ """Initialize feature-based model.
423
+
424
+ Args:
425
+ feature_key: Feature to use for prediction
426
+ """
427
+ self.feature_key = feature_key
428
+
429
+ @property
430
+ def name(self) -> str:
431
+ return f"feature_based_{self.feature_key}"
432
+
433
+ def predict(
434
+ self,
435
+ history: ExecutionHistory,
436
+ features: dict[str, Any] | None = None,
437
+ ) -> PredictionResult:
438
+ """Predict using feature-based regression."""
439
+ if not features or self.feature_key not in features:
440
+ # Fall back to simple average
441
+ durations = history.get_durations()
442
+ if not durations:
443
+ return PredictionResult(
444
+ operation="unknown",
445
+ estimated_ms=0.0,
446
+ confidence=0.0,
447
+ model_used=self.name,
448
+ )
449
+ return PredictionResult(
450
+ operation="",
451
+ estimated_ms=statistics.mean(durations),
452
+ confidence=0.3,
453
+ model_used=self.name,
454
+ )
455
+
456
+ target_feature = features[self.feature_key]
457
+ if not isinstance(target_feature, (int, float)) or target_feature <= 0:
458
+ return PredictionResult(
459
+ operation="",
460
+ estimated_ms=0.0,
461
+ confidence=0.0,
462
+ model_used=self.name,
463
+ )
464
+
465
+ # Collect data points
466
+ x_values = []
467
+ y_values = []
468
+
469
+ for record in history.get_recent(100):
470
+ feature_value = record.features.get(self.feature_key)
471
+ if isinstance(feature_value, (int, float)) and feature_value > 0:
472
+ x_values.append(feature_value)
473
+ y_values.append(record.duration_ms)
474
+
475
+ if len(x_values) < 2:
476
+ return PredictionResult(
477
+ operation="",
478
+ estimated_ms=0.0,
479
+ confidence=0.0,
480
+ model_used=self.name,
481
+ )
482
+
483
+ # Simple linear regression
484
+ n = len(x_values)
485
+ mean_x = sum(x_values) / n
486
+ mean_y = sum(y_values) / n
487
+
488
+ # Calculate slope and intercept
489
+ numerator = sum((x - mean_x) * (y - mean_y) for x, y in zip(x_values, y_values))
490
+ denominator = sum((x - mean_x) ** 2 for x in x_values)
491
+
492
+ if denominator == 0:
493
+ slope = 0
494
+ intercept = mean_y
495
+ else:
496
+ slope = numerator / denominator
497
+ intercept = mean_y - slope * mean_x
498
+
499
+ # Predict
500
+ predicted = intercept + slope * target_feature
501
+ predicted = max(0, predicted) # Ensure non-negative
502
+
503
+ # Calculate residuals for confidence
504
+ residuals = [
505
+ abs(y - (intercept + slope * x))
506
+ for x, y in zip(x_values, y_values)
507
+ ]
508
+ mean_residual = sum(residuals) / n
509
+ confidence = max(0.1, 1.0 - (mean_residual / max(mean_y, 1.0)))
510
+
511
+ return PredictionResult(
512
+ operation="",
513
+ estimated_ms=predicted,
514
+ confidence=min(1.0, confidence),
515
+ p50_ms=predicted,
516
+ p90_ms=predicted * 1.5,
517
+ p95_ms=predicted * 2.0,
518
+ p99_ms=predicted * 3.0,
519
+ sample_count=n,
520
+ model_used=self.name,
521
+ features=features,
522
+ metadata={
523
+ "slope": slope,
524
+ "intercept": intercept,
525
+ "r_squared": self._calculate_r_squared(x_values, y_values, slope, intercept),
526
+ },
527
+ )
528
+
529
+ def _calculate_r_squared(
530
+ self,
531
+ x_values: list[float],
532
+ y_values: list[float],
533
+ slope: float,
534
+ intercept: float,
535
+ ) -> float:
536
+ """Calculate R-squared for the regression."""
537
+ n = len(y_values)
538
+ if n == 0:
539
+ return 0.0
540
+
541
+ mean_y = sum(y_values) / n
542
+ ss_tot = sum((y - mean_y) ** 2 for y in y_values)
543
+ ss_res = sum((y - (intercept + slope * x)) ** 2 for x, y in zip(x_values, y_values))
544
+
545
+ if ss_tot == 0:
546
+ return 1.0 if ss_res == 0 else 0.0
547
+ return 1.0 - (ss_res / ss_tot)
548
+
549
+
550
+ class PerformancePredictor:
551
+ """Main performance predictor using ensemble of models.
552
+
553
+ This class manages execution history and uses multiple prediction
554
+ models to provide robust performance estimates.
555
+
556
+ Example:
557
+ predictor = PerformancePredictor()
558
+
559
+ # Record executions
560
+ predictor.record("validate", 100.0, {"rows": 10000})
561
+ predictor.record("validate", 105.0, {"rows": 10000})
562
+
563
+ # Predict
564
+ result = predictor.predict("validate", {"rows": 20000})
565
+ print(f"Estimated: {result.estimated_ms}ms")
566
+ """
567
+
568
+ def __init__(
569
+ self,
570
+ models: list[PredictionModel] | None = None,
571
+ history_size: int = 1000,
572
+ ):
573
+ """Initialize predictor.
574
+
575
+ Args:
576
+ models: Prediction models to use (default: all available)
577
+ history_size: Maximum history size per operation
578
+ """
579
+ self.models = models or [
580
+ MovingAverageModel(20),
581
+ ExponentialSmoothingModel(0.3),
582
+ QuantileRegressionModel(),
583
+ FeatureBasedModel("rows"),
584
+ ]
585
+ self.history_size = history_size
586
+ self._histories: dict[str, ExecutionHistory] = defaultdict(
587
+ lambda: ExecutionHistory(max_size=history_size)
588
+ )
589
+ self._lock = threading.Lock()
590
+
591
+ def record(
592
+ self,
593
+ operation: str,
594
+ duration_ms: float,
595
+ features: dict[str, Any] | None = None,
596
+ success: bool = True,
597
+ metadata: dict[str, Any] | None = None,
598
+ ) -> None:
599
+ """Record an execution.
600
+
601
+ Args:
602
+ operation: Operation name
603
+ duration_ms: Duration in milliseconds
604
+ features: Features of the execution
605
+ success: Whether execution succeeded
606
+ metadata: Additional metadata
607
+ """
608
+ record = ExecutionRecord(
609
+ operation=operation,
610
+ duration_ms=duration_ms,
611
+ features=features or {},
612
+ success=success,
613
+ metadata=metadata or {},
614
+ )
615
+
616
+ with self._lock:
617
+ self._histories[operation].add(record)
618
+
619
+ def predict(
620
+ self,
621
+ operation: str,
622
+ features: dict[str, Any] | None = None,
623
+ ) -> PredictionResult:
624
+ """Predict execution time.
625
+
626
+ Args:
627
+ operation: Operation name
628
+ features: Features for feature-based prediction
629
+
630
+ Returns:
631
+ PredictionResult with estimates
632
+ """
633
+ with self._lock:
634
+ history = self._histories.get(operation)
635
+
636
+ if not history or len(history) == 0:
637
+ return PredictionResult(
638
+ operation=operation,
639
+ estimated_ms=0.0,
640
+ confidence=0.0,
641
+ model_used="none",
642
+ metadata={"reason": "no_history"},
643
+ )
644
+
645
+ # Get predictions from all models
646
+ predictions = []
647
+ for model in self.models:
648
+ try:
649
+ result = model.predict(history, features)
650
+ if result.confidence > 0:
651
+ predictions.append(result)
652
+ except Exception:
653
+ continue
654
+
655
+ if not predictions:
656
+ return PredictionResult(
657
+ operation=operation,
658
+ estimated_ms=0.0,
659
+ confidence=0.0,
660
+ model_used="none",
661
+ metadata={"reason": "all_models_failed"},
662
+ )
663
+
664
+ # Weighted ensemble
665
+ total_weight = sum(p.confidence for p in predictions)
666
+ if total_weight == 0:
667
+ total_weight = len(predictions)
668
+ weights = [1.0 / len(predictions)] * len(predictions)
669
+ else:
670
+ weights = [p.confidence / total_weight for p in predictions]
671
+
672
+ estimated_ms = sum(p.estimated_ms * w for p, w in zip(predictions, weights))
673
+ p50_ms = sum((p.p50_ms or p.estimated_ms) * w for p, w in zip(predictions, weights))
674
+ p90_ms = sum((p.p90_ms or p.estimated_ms * 1.5) * w for p, w in zip(predictions, weights))
675
+ p95_ms = sum((p.p95_ms or p.estimated_ms * 2.0) * w for p, w in zip(predictions, weights))
676
+ p99_ms = sum((p.p99_ms or p.estimated_ms * 3.0) * w for p, w in zip(predictions, weights))
677
+
678
+ avg_confidence = sum(p.confidence * w for p, w in zip(predictions, weights))
679
+ total_samples = sum(p.sample_count for p in predictions)
680
+
681
+ return PredictionResult(
682
+ operation=operation,
683
+ estimated_ms=estimated_ms,
684
+ confidence=avg_confidence,
685
+ p50_ms=p50_ms,
686
+ p90_ms=p90_ms,
687
+ p95_ms=p95_ms,
688
+ p99_ms=p99_ms,
689
+ sample_count=total_samples,
690
+ model_used="ensemble",
691
+ features=features or {},
692
+ metadata={
693
+ "models_used": [p.model_used for p in predictions],
694
+ "model_estimates": [p.estimated_ms for p in predictions],
695
+ },
696
+ )
697
+
698
+ def get_history(self, operation: str) -> ExecutionHistory | None:
699
+ """Get execution history for an operation.
700
+
701
+ Args:
702
+ operation: Operation name
703
+
704
+ Returns:
705
+ ExecutionHistory or None
706
+ """
707
+ with self._lock:
708
+ return self._histories.get(operation)
709
+
710
+ def get_operations(self) -> list[str]:
711
+ """Get list of operations with history.
712
+
713
+ Returns:
714
+ List of operation names
715
+ """
716
+ with self._lock:
717
+ return list(self._histories.keys())
718
+
719
+ def clear(self, operation: str | None = None) -> None:
720
+ """Clear history.
721
+
722
+ Args:
723
+ operation: Operation to clear (None = all)
724
+ """
725
+ with self._lock:
726
+ if operation:
727
+ if operation in self._histories:
728
+ del self._histories[operation]
729
+ else:
730
+ self._histories.clear()
731
+
732
+
733
+ # Module-level predictor instance
734
+ _default_predictor: PerformancePredictor | None = None
735
+
736
+
737
+ def predict_execution_time(
738
+ operation: str,
739
+ features: dict[str, Any] | None = None,
740
+ ) -> PredictionResult:
741
+ """Predict execution time using default predictor.
742
+
743
+ Args:
744
+ operation: Operation name
745
+ features: Features for prediction
746
+
747
+ Returns:
748
+ PredictionResult
749
+ """
750
+ global _default_predictor
751
+ if _default_predictor is None:
752
+ _default_predictor = PerformancePredictor()
753
+ return _default_predictor.predict(operation, features)
754
+
755
+
756
+ def record_execution(
757
+ operation: str,
758
+ duration_ms: float,
759
+ features: dict[str, Any] | None = None,
760
+ success: bool = True,
761
+ ) -> None:
762
+ """Record execution using default predictor.
763
+
764
+ Args:
765
+ operation: Operation name
766
+ duration_ms: Duration in milliseconds
767
+ features: Features of execution
768
+ success: Whether execution succeeded
769
+ """
770
+ global _default_predictor
771
+ if _default_predictor is None:
772
+ _default_predictor = PerformancePredictor()
773
+ _default_predictor.record(operation, duration_ms, features, success)