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,793 @@
1
+ """Saga State Machine Module.
2
+
3
+ This module provides a state machine implementation for managing
4
+ saga execution lifecycle with well-defined states and transitions.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from dataclasses import dataclass, field
11
+ from datetime import datetime
12
+ from enum import Enum, auto
13
+ from typing import TYPE_CHECKING, Any, Callable
14
+ from uuid import uuid4
15
+
16
+ if TYPE_CHECKING:
17
+ from truthound.checkpoint.transaction.saga.definition import SagaDefinition
18
+
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class SagaState(str, Enum):
24
+ """States in the saga lifecycle."""
25
+
26
+ # Initial states
27
+ CREATED = "created" # Saga created but not started
28
+ PENDING = "pending" # Waiting to start
29
+
30
+ # Execution states
31
+ STARTING = "starting" # Beginning execution
32
+ EXECUTING = "executing" # Executing steps
33
+ STEP_EXECUTING = "step_executing" # Executing a specific step
34
+ STEP_COMPLETED = "step_completed" # Step completed successfully
35
+ STEP_FAILED = "step_failed" # Step failed
36
+
37
+ # Compensation states
38
+ COMPENSATING = "compensating" # Running compensations
39
+ STEP_COMPENSATING = "step_compensating" # Compensating a specific step
40
+ STEP_COMPENSATED = "step_compensated" # Step compensated successfully
41
+ COMPENSATION_FAILED = "compensation_failed" # Compensation failed
42
+
43
+ # Terminal states
44
+ COMPLETED = "completed" # All steps completed successfully
45
+ COMPENSATED = "compensated" # All compensations completed
46
+ FAILED = "failed" # Saga failed (unrecoverable)
47
+ ABORTED = "aborted" # Saga aborted by user/system
48
+ TIMED_OUT = "timed_out" # Saga timed out
49
+
50
+ # Recovery states
51
+ SUSPENDED = "suspended" # Execution suspended
52
+ RESUMING = "resuming" # Resuming from suspension
53
+
54
+ def __str__(self) -> str:
55
+ return self.value
56
+
57
+ @property
58
+ def is_terminal(self) -> bool:
59
+ """Check if this is a terminal state."""
60
+ return self in (
61
+ SagaState.COMPLETED,
62
+ SagaState.COMPENSATED,
63
+ SagaState.FAILED,
64
+ SagaState.ABORTED,
65
+ SagaState.TIMED_OUT,
66
+ )
67
+
68
+ @property
69
+ def is_executing(self) -> bool:
70
+ """Check if saga is currently executing."""
71
+ return self in (
72
+ SagaState.STARTING,
73
+ SagaState.EXECUTING,
74
+ SagaState.STEP_EXECUTING,
75
+ SagaState.STEP_COMPLETED,
76
+ )
77
+
78
+ @property
79
+ def is_compensating(self) -> bool:
80
+ """Check if saga is compensating."""
81
+ return self in (
82
+ SagaState.COMPENSATING,
83
+ SagaState.STEP_COMPENSATING,
84
+ SagaState.STEP_COMPENSATED,
85
+ )
86
+
87
+ @property
88
+ def is_success(self) -> bool:
89
+ """Check if saga completed successfully."""
90
+ return self == SagaState.COMPLETED
91
+
92
+ @property
93
+ def is_recoverable(self) -> bool:
94
+ """Check if saga can be recovered."""
95
+ return self in (
96
+ SagaState.STEP_FAILED,
97
+ SagaState.COMPENSATION_FAILED,
98
+ SagaState.SUSPENDED,
99
+ )
100
+
101
+
102
+ class SagaEventType(str, Enum):
103
+ """Types of events in saga execution."""
104
+
105
+ # Lifecycle events
106
+ SAGA_CREATED = "saga_created"
107
+ SAGA_STARTED = "saga_started"
108
+ SAGA_COMPLETED = "saga_completed"
109
+ SAGA_FAILED = "saga_failed"
110
+ SAGA_ABORTED = "saga_aborted"
111
+ SAGA_TIMED_OUT = "saga_timed_out"
112
+
113
+ # Step events
114
+ STEP_STARTED = "step_started"
115
+ STEP_COMPLETED = "step_completed"
116
+ STEP_FAILED = "step_failed"
117
+ STEP_SKIPPED = "step_skipped"
118
+ STEP_RETRYING = "step_retrying"
119
+
120
+ # Compensation events
121
+ COMPENSATION_STARTED = "compensation_started"
122
+ STEP_COMPENSATING = "step_compensating"
123
+ STEP_COMPENSATED = "step_compensated"
124
+ COMPENSATION_FAILED = "compensation_failed"
125
+ COMPENSATION_COMPLETED = "compensation_completed"
126
+
127
+ # Recovery events
128
+ SAGA_SUSPENDED = "saga_suspended"
129
+ SAGA_RESUMED = "saga_resumed"
130
+ SAGA_RECOVERED = "saga_recovered"
131
+
132
+ # Checkpoint events
133
+ CHECKPOINT_CREATED = "checkpoint_created"
134
+ CHECKPOINT_RESTORED = "checkpoint_restored"
135
+
136
+ def __str__(self) -> str:
137
+ return self.value
138
+
139
+
140
+ @dataclass
141
+ class SagaEvent:
142
+ """Event representing a saga state change.
143
+
144
+ Attributes:
145
+ event_id: Unique event identifier.
146
+ saga_id: ID of the saga this event belongs to.
147
+ event_type: Type of event.
148
+ timestamp: When the event occurred.
149
+ source_state: State before the event.
150
+ target_state: State after the event.
151
+ step_id: ID of the step (if step-related event).
152
+ data: Additional event data.
153
+ error: Error information if applicable.
154
+ """
155
+
156
+ event_id: str = field(default_factory=lambda: f"evt_{uuid4().hex[:12]}")
157
+ saga_id: str = ""
158
+ event_type: SagaEventType = SagaEventType.SAGA_CREATED
159
+ timestamp: datetime = field(default_factory=datetime.now)
160
+ source_state: SagaState | None = None
161
+ target_state: SagaState | None = None
162
+ step_id: str | None = None
163
+ data: dict[str, Any] = field(default_factory=dict)
164
+ error: str | None = None
165
+
166
+ def to_dict(self) -> dict[str, Any]:
167
+ """Convert to dictionary for serialization."""
168
+ return {
169
+ "event_id": self.event_id,
170
+ "saga_id": self.saga_id,
171
+ "event_type": self.event_type.value,
172
+ "timestamp": self.timestamp.isoformat(),
173
+ "source_state": self.source_state.value if self.source_state else None,
174
+ "target_state": self.target_state.value if self.target_state else None,
175
+ "step_id": self.step_id,
176
+ "data": self.data,
177
+ "error": self.error,
178
+ }
179
+
180
+ @classmethod
181
+ def from_dict(cls, data: dict[str, Any]) -> "SagaEvent":
182
+ """Create from dictionary."""
183
+ return cls(
184
+ event_id=data.get("event_id", ""),
185
+ saga_id=data.get("saga_id", ""),
186
+ event_type=SagaEventType(data["event_type"]),
187
+ timestamp=datetime.fromisoformat(data["timestamp"]),
188
+ source_state=SagaState(data["source_state"]) if data.get("source_state") else None,
189
+ target_state=SagaState(data["target_state"]) if data.get("target_state") else None,
190
+ step_id=data.get("step_id"),
191
+ data=data.get("data", {}),
192
+ error=data.get("error"),
193
+ )
194
+
195
+
196
+ @dataclass
197
+ class SagaTransition:
198
+ """Represents a valid state transition.
199
+
200
+ Attributes:
201
+ from_state: Source state.
202
+ to_state: Target state.
203
+ event_type: Event that triggers this transition.
204
+ guard: Optional condition for the transition.
205
+ action: Optional action to execute during transition.
206
+ """
207
+
208
+ from_state: SagaState | tuple[SagaState, ...]
209
+ to_state: SagaState
210
+ event_type: SagaEventType
211
+ guard: Callable[[SagaEvent], bool] | None = None
212
+ action: Callable[[SagaEvent], None] | None = None
213
+
214
+ def is_valid_from(self, state: SagaState) -> bool:
215
+ """Check if transition is valid from given state."""
216
+ if isinstance(self.from_state, tuple):
217
+ return state in self.from_state
218
+ return state == self.from_state
219
+
220
+ def can_transition(self, event: SagaEvent) -> bool:
221
+ """Check if transition is allowed for the event."""
222
+ if self.guard:
223
+ return self.guard(event)
224
+ return True
225
+
226
+
227
+ class SagaStateMachine:
228
+ """State machine for managing saga execution lifecycle.
229
+
230
+ This class manages the state transitions of a saga, ensuring that
231
+ only valid transitions occur and triggering appropriate callbacks.
232
+
233
+ Example:
234
+ >>> machine = SagaStateMachine(saga_id="saga_123")
235
+ >>> machine.on_state_change(lambda old, new, evt: print(f"{old} -> {new}"))
236
+ >>> machine.start()
237
+ >>> machine.step_started("step_1")
238
+ >>> machine.step_completed("step_1")
239
+ >>> machine.complete()
240
+ """
241
+
242
+ # Valid transitions definition
243
+ TRANSITIONS: list[SagaTransition] = [
244
+ # Start transitions
245
+ SagaTransition(SagaState.CREATED, SagaState.STARTING, SagaEventType.SAGA_STARTED),
246
+ SagaTransition(SagaState.PENDING, SagaState.STARTING, SagaEventType.SAGA_STARTED),
247
+
248
+ # Step execution transitions - STARTING goes directly to STEP_EXECUTING
249
+ SagaTransition(SagaState.STARTING, SagaState.STEP_EXECUTING, SagaEventType.STEP_STARTED),
250
+ SagaTransition(SagaState.EXECUTING, SagaState.STEP_EXECUTING, SagaEventType.STEP_STARTED),
251
+ SagaTransition(SagaState.STEP_COMPLETED, SagaState.STEP_EXECUTING, SagaEventType.STEP_STARTED),
252
+ # Allow parallel step starts (multiple steps starting from STEP_EXECUTING)
253
+ SagaTransition(SagaState.STEP_EXECUTING, SagaState.STEP_EXECUTING, SagaEventType.STEP_STARTED),
254
+ SagaTransition(SagaState.STEP_EXECUTING, SagaState.STEP_COMPLETED, SagaEventType.STEP_COMPLETED),
255
+ SagaTransition(SagaState.STEP_EXECUTING, SagaState.STEP_FAILED, SagaEventType.STEP_FAILED),
256
+ SagaTransition(SagaState.STEP_EXECUTING, SagaState.STEP_EXECUTING, SagaEventType.STEP_RETRYING),
257
+ # Allow parallel step completions (multiple results coming back)
258
+ SagaTransition(SagaState.STEP_COMPLETED, SagaState.STEP_COMPLETED, SagaEventType.STEP_COMPLETED),
259
+ SagaTransition(SagaState.STEP_COMPLETED, SagaState.STEP_FAILED, SagaEventType.STEP_FAILED),
260
+
261
+ # Completion transitions
262
+ SagaTransition(SagaState.STEP_COMPLETED, SagaState.COMPLETED, SagaEventType.SAGA_COMPLETED),
263
+ SagaTransition(SagaState.EXECUTING, SagaState.COMPLETED, SagaEventType.SAGA_COMPLETED),
264
+ SagaTransition(SagaState.STARTING, SagaState.COMPLETED, SagaEventType.SAGA_COMPLETED),
265
+
266
+ # Failure and compensation transitions
267
+ SagaTransition(SagaState.STEP_FAILED, SagaState.COMPENSATING, SagaEventType.COMPENSATION_STARTED),
268
+ SagaTransition(SagaState.COMPENSATING, SagaState.STEP_COMPENSATING, SagaEventType.STEP_COMPENSATING),
269
+ SagaTransition(SagaState.STEP_COMPENSATED, SagaState.STEP_COMPENSATING, SagaEventType.STEP_COMPENSATING),
270
+ SagaTransition(SagaState.STEP_COMPENSATING, SagaState.STEP_COMPENSATED, SagaEventType.STEP_COMPENSATED),
271
+ SagaTransition(SagaState.STEP_COMPENSATING, SagaState.COMPENSATION_FAILED, SagaEventType.COMPENSATION_FAILED),
272
+
273
+ # Compensation completion
274
+ SagaTransition(SagaState.STEP_COMPENSATED, SagaState.COMPENSATED, SagaEventType.COMPENSATION_COMPLETED),
275
+ SagaTransition(SagaState.COMPENSATING, SagaState.COMPENSATED, SagaEventType.COMPENSATION_COMPLETED),
276
+
277
+ # Failure transitions
278
+ SagaTransition(
279
+ (SagaState.STEP_FAILED, SagaState.COMPENSATION_FAILED),
280
+ SagaState.FAILED,
281
+ SagaEventType.SAGA_FAILED,
282
+ ),
283
+
284
+ # Abort transitions (can abort from most states)
285
+ SagaTransition(
286
+ (
287
+ SagaState.CREATED, SagaState.PENDING, SagaState.STARTING,
288
+ SagaState.EXECUTING, SagaState.STEP_EXECUTING, SagaState.STEP_COMPLETED,
289
+ SagaState.STEP_FAILED, SagaState.COMPENSATING, SagaState.STEP_COMPENSATING,
290
+ ),
291
+ SagaState.ABORTED,
292
+ SagaEventType.SAGA_ABORTED,
293
+ ),
294
+
295
+ # Timeout transitions
296
+ SagaTransition(
297
+ (
298
+ SagaState.STARTING, SagaState.EXECUTING, SagaState.STEP_EXECUTING,
299
+ SagaState.COMPENSATING, SagaState.STEP_COMPENSATING,
300
+ ),
301
+ SagaState.TIMED_OUT,
302
+ SagaEventType.SAGA_TIMED_OUT,
303
+ ),
304
+
305
+ # Suspend and resume transitions
306
+ SagaTransition(
307
+ (SagaState.EXECUTING, SagaState.STEP_EXECUTING, SagaState.STEP_COMPLETED,
308
+ SagaState.STEP_FAILED, SagaState.COMPENSATING, SagaState.STEP_COMPENSATING,
309
+ SagaState.STARTING),
310
+ SagaState.SUSPENDED,
311
+ SagaEventType.SAGA_SUSPENDED,
312
+ ),
313
+ SagaTransition(SagaState.SUSPENDED, SagaState.RESUMING, SagaEventType.SAGA_RESUMED),
314
+ SagaTransition(SagaState.RESUMING, SagaState.STEP_EXECUTING, SagaEventType.STEP_STARTED),
315
+ SagaTransition(SagaState.RESUMING, SagaState.COMPENSATING, SagaEventType.COMPENSATION_STARTED),
316
+ ]
317
+
318
+ def __init__(
319
+ self,
320
+ saga_id: str,
321
+ initial_state: SagaState = SagaState.CREATED,
322
+ ) -> None:
323
+ """Initialize the state machine.
324
+
325
+ Args:
326
+ saga_id: Unique saga identifier.
327
+ initial_state: Initial state.
328
+ """
329
+ self._saga_id = saga_id
330
+ self._state = initial_state
331
+ self._events: list[SagaEvent] = []
332
+ self._callbacks: list[Callable[[SagaState, SagaState, SagaEvent], None]] = []
333
+ self._current_step: str | None = None
334
+ self._step_states: dict[str, SagaState] = {}
335
+ self._metadata: dict[str, Any] = {}
336
+
337
+ @property
338
+ def saga_id(self) -> str:
339
+ """Get saga ID."""
340
+ return self._saga_id
341
+
342
+ @property
343
+ def state(self) -> SagaState:
344
+ """Get current state."""
345
+ return self._state
346
+
347
+ @property
348
+ def current_step(self) -> str | None:
349
+ """Get current step ID."""
350
+ return self._current_step
351
+
352
+ @property
353
+ def events(self) -> list[SagaEvent]:
354
+ """Get all events."""
355
+ return list(self._events)
356
+
357
+ @property
358
+ def is_terminal(self) -> bool:
359
+ """Check if saga is in terminal state."""
360
+ return self._state.is_terminal
361
+
362
+ def on_state_change(
363
+ self,
364
+ callback: Callable[[SagaState, SagaState, SagaEvent], None],
365
+ ) -> None:
366
+ """Register a state change callback.
367
+
368
+ Args:
369
+ callback: Function to call on state change.
370
+ """
371
+ self._callbacks.append(callback)
372
+
373
+ def _find_transition(
374
+ self,
375
+ event_type: SagaEventType,
376
+ event: SagaEvent,
377
+ ) -> SagaTransition | None:
378
+ """Find a valid transition for the event."""
379
+ for transition in self.TRANSITIONS:
380
+ if transition.event_type != event_type:
381
+ continue
382
+ if not transition.is_valid_from(self._state):
383
+ continue
384
+ if not transition.can_transition(event):
385
+ continue
386
+ return transition
387
+ return None
388
+
389
+ def _transition(
390
+ self,
391
+ event_type: SagaEventType,
392
+ step_id: str | None = None,
393
+ data: dict[str, Any] | None = None,
394
+ error: str | None = None,
395
+ ) -> SagaEvent:
396
+ """Execute a state transition.
397
+
398
+ Args:
399
+ event_type: Type of event.
400
+ step_id: Optional step ID.
401
+ data: Optional event data.
402
+ error: Optional error message.
403
+
404
+ Returns:
405
+ The created event.
406
+
407
+ Raises:
408
+ InvalidTransitionError: If transition is not valid.
409
+ """
410
+ event = SagaEvent(
411
+ saga_id=self._saga_id,
412
+ event_type=event_type,
413
+ source_state=self._state,
414
+ step_id=step_id,
415
+ data=data or {},
416
+ error=error,
417
+ )
418
+
419
+ transition = self._find_transition(event_type, event)
420
+ if transition is None:
421
+ raise InvalidTransitionError(
422
+ f"No valid transition from {self._state} with event {event_type}"
423
+ )
424
+
425
+ # Execute transition action if defined
426
+ if transition.action:
427
+ transition.action(event)
428
+
429
+ # Update state
430
+ old_state = self._state
431
+ self._state = transition.to_state
432
+ event.target_state = self._state
433
+
434
+ # Update step tracking
435
+ if step_id:
436
+ self._current_step = step_id
437
+ self._step_states[step_id] = self._state
438
+
439
+ # Record event
440
+ self._events.append(event)
441
+
442
+ # Notify callbacks
443
+ for callback in self._callbacks:
444
+ try:
445
+ callback(old_state, self._state, event)
446
+ except Exception as e:
447
+ logger.warning(f"State change callback failed: {e}")
448
+
449
+ logger.debug(
450
+ f"Saga {self._saga_id}: {old_state.value} -> {self._state.value} "
451
+ f"({event_type.value})"
452
+ )
453
+
454
+ return event
455
+
456
+ # ==========================================================================
457
+ # Public transition methods
458
+ # ==========================================================================
459
+
460
+ def start(self, data: dict[str, Any] | None = None) -> SagaEvent:
461
+ """Start the saga execution.
462
+
463
+ Args:
464
+ data: Optional start data.
465
+
466
+ Returns:
467
+ The start event.
468
+ """
469
+ return self._transition(SagaEventType.SAGA_STARTED, data=data)
470
+
471
+ def step_started(
472
+ self,
473
+ step_id: str,
474
+ data: dict[str, Any] | None = None,
475
+ ) -> SagaEvent:
476
+ """Mark a step as started.
477
+
478
+ Args:
479
+ step_id: Step identifier.
480
+ data: Optional step data.
481
+
482
+ Returns:
483
+ The step start event.
484
+ """
485
+ return self._transition(SagaEventType.STEP_STARTED, step_id=step_id, data=data)
486
+
487
+ def step_completed(
488
+ self,
489
+ step_id: str,
490
+ data: dict[str, Any] | None = None,
491
+ ) -> SagaEvent:
492
+ """Mark a step as completed.
493
+
494
+ Args:
495
+ step_id: Step identifier.
496
+ data: Optional completion data.
497
+
498
+ Returns:
499
+ The step completion event.
500
+ """
501
+ return self._transition(SagaEventType.STEP_COMPLETED, step_id=step_id, data=data)
502
+
503
+ def step_failed(
504
+ self,
505
+ step_id: str,
506
+ error: str,
507
+ data: dict[str, Any] | None = None,
508
+ ) -> SagaEvent:
509
+ """Mark a step as failed.
510
+
511
+ Args:
512
+ step_id: Step identifier.
513
+ error: Error message.
514
+ data: Optional failure data.
515
+
516
+ Returns:
517
+ The step failure event.
518
+ """
519
+ return self._transition(
520
+ SagaEventType.STEP_FAILED,
521
+ step_id=step_id,
522
+ data=data,
523
+ error=error,
524
+ )
525
+
526
+ def step_retrying(
527
+ self,
528
+ step_id: str,
529
+ attempt: int,
530
+ data: dict[str, Any] | None = None,
531
+ ) -> SagaEvent:
532
+ """Mark a step as retrying.
533
+
534
+ Args:
535
+ step_id: Step identifier.
536
+ attempt: Retry attempt number.
537
+ data: Optional retry data.
538
+
539
+ Returns:
540
+ The retry event.
541
+ """
542
+ event_data = data or {}
543
+ event_data["attempt"] = attempt
544
+ return self._transition(
545
+ SagaEventType.STEP_RETRYING,
546
+ step_id=step_id,
547
+ data=event_data,
548
+ )
549
+
550
+ def complete(self, data: dict[str, Any] | None = None) -> SagaEvent:
551
+ """Mark the saga as completed.
552
+
553
+ Args:
554
+ data: Optional completion data.
555
+
556
+ Returns:
557
+ The completion event.
558
+ """
559
+ return self._transition(SagaEventType.SAGA_COMPLETED, data=data)
560
+
561
+ def start_compensation(self, data: dict[str, Any] | None = None) -> SagaEvent:
562
+ """Start compensation process.
563
+
564
+ Args:
565
+ data: Optional compensation data.
566
+
567
+ Returns:
568
+ The compensation start event.
569
+ """
570
+ return self._transition(SagaEventType.COMPENSATION_STARTED, data=data)
571
+
572
+ def step_compensating(
573
+ self,
574
+ step_id: str,
575
+ data: dict[str, Any] | None = None,
576
+ ) -> SagaEvent:
577
+ """Mark a step as being compensated.
578
+
579
+ Args:
580
+ step_id: Step identifier.
581
+ data: Optional compensation data.
582
+
583
+ Returns:
584
+ The step compensating event.
585
+ """
586
+ return self._transition(
587
+ SagaEventType.STEP_COMPENSATING,
588
+ step_id=step_id,
589
+ data=data,
590
+ )
591
+
592
+ def step_compensated(
593
+ self,
594
+ step_id: str,
595
+ data: dict[str, Any] | None = None,
596
+ ) -> SagaEvent:
597
+ """Mark a step compensation as completed.
598
+
599
+ Args:
600
+ step_id: Step identifier.
601
+ data: Optional completion data.
602
+
603
+ Returns:
604
+ The step compensated event.
605
+ """
606
+ return self._transition(
607
+ SagaEventType.STEP_COMPENSATED,
608
+ step_id=step_id,
609
+ data=data,
610
+ )
611
+
612
+ def compensation_failed(
613
+ self,
614
+ step_id: str,
615
+ error: str,
616
+ data: dict[str, Any] | None = None,
617
+ ) -> SagaEvent:
618
+ """Mark compensation as failed.
619
+
620
+ Args:
621
+ step_id: Step identifier.
622
+ error: Error message.
623
+ data: Optional failure data.
624
+
625
+ Returns:
626
+ The compensation failure event.
627
+ """
628
+ return self._transition(
629
+ SagaEventType.COMPENSATION_FAILED,
630
+ step_id=step_id,
631
+ data=data,
632
+ error=error,
633
+ )
634
+
635
+ def compensation_complete(self, data: dict[str, Any] | None = None) -> SagaEvent:
636
+ """Mark all compensations as complete.
637
+
638
+ Args:
639
+ data: Optional completion data.
640
+
641
+ Returns:
642
+ The compensation completion event.
643
+ """
644
+ return self._transition(SagaEventType.COMPENSATION_COMPLETED, data=data)
645
+
646
+ def fail(self, error: str, data: dict[str, Any] | None = None) -> SagaEvent:
647
+ """Mark the saga as failed.
648
+
649
+ Args:
650
+ error: Error message.
651
+ data: Optional failure data.
652
+
653
+ Returns:
654
+ The failure event.
655
+ """
656
+ return self._transition(SagaEventType.SAGA_FAILED, data=data, error=error)
657
+
658
+ def abort(self, reason: str = "", data: dict[str, Any] | None = None) -> SagaEvent:
659
+ """Abort the saga.
660
+
661
+ Args:
662
+ reason: Abort reason.
663
+ data: Optional abort data.
664
+
665
+ Returns:
666
+ The abort event.
667
+ """
668
+ return self._transition(
669
+ SagaEventType.SAGA_ABORTED,
670
+ data=data,
671
+ error=reason or "Saga aborted",
672
+ )
673
+
674
+ def timeout(self, data: dict[str, Any] | None = None) -> SagaEvent:
675
+ """Mark the saga as timed out.
676
+
677
+ Args:
678
+ data: Optional timeout data.
679
+
680
+ Returns:
681
+ The timeout event.
682
+ """
683
+ return self._transition(
684
+ SagaEventType.SAGA_TIMED_OUT,
685
+ data=data,
686
+ error="Saga timed out",
687
+ )
688
+
689
+ def suspend(self, reason: str = "", data: dict[str, Any] | None = None) -> SagaEvent:
690
+ """Suspend the saga.
691
+
692
+ Args:
693
+ reason: Suspension reason.
694
+ data: Optional suspension data.
695
+
696
+ Returns:
697
+ The suspension event.
698
+ """
699
+ event_data = data or {}
700
+ event_data["reason"] = reason
701
+ return self._transition(SagaEventType.SAGA_SUSPENDED, data=event_data)
702
+
703
+ def resume(self, data: dict[str, Any] | None = None) -> SagaEvent:
704
+ """Resume a suspended saga.
705
+
706
+ Args:
707
+ data: Optional resume data.
708
+
709
+ Returns:
710
+ The resume event.
711
+ """
712
+ return self._transition(SagaEventType.SAGA_RESUMED, data=data)
713
+
714
+ # ==========================================================================
715
+ # Query methods
716
+ # ==========================================================================
717
+
718
+ def get_step_state(self, step_id: str) -> SagaState | None:
719
+ """Get the state of a specific step.
720
+
721
+ Args:
722
+ step_id: Step identifier.
723
+
724
+ Returns:
725
+ Step state or None if not tracked.
726
+ """
727
+ return self._step_states.get(step_id)
728
+
729
+ def get_completed_steps(self) -> list[str]:
730
+ """Get IDs of all completed steps."""
731
+ return [
732
+ step_id
733
+ for step_id, state in self._step_states.items()
734
+ if state == SagaState.STEP_COMPLETED
735
+ ]
736
+
737
+ def get_failed_steps(self) -> list[str]:
738
+ """Get IDs of all failed steps."""
739
+ return [
740
+ step_id
741
+ for step_id, state in self._step_states.items()
742
+ if state == SagaState.STEP_FAILED
743
+ ]
744
+
745
+ def get_compensated_steps(self) -> list[str]:
746
+ """Get IDs of all compensated steps."""
747
+ return [
748
+ step_id
749
+ for step_id, state in self._step_states.items()
750
+ if state == SagaState.STEP_COMPENSATED
751
+ ]
752
+
753
+ def to_dict(self) -> dict[str, Any]:
754
+ """Convert state machine to dictionary for serialization."""
755
+ return {
756
+ "saga_id": self._saga_id,
757
+ "state": self._state.value,
758
+ "current_step": self._current_step,
759
+ "step_states": {k: v.value for k, v in self._step_states.items()},
760
+ "event_count": len(self._events),
761
+ "metadata": self._metadata,
762
+ }
763
+
764
+ @classmethod
765
+ def from_events(cls, saga_id: str, events: list[SagaEvent]) -> "SagaStateMachine":
766
+ """Reconstruct state machine from events.
767
+
768
+ Args:
769
+ saga_id: Saga identifier.
770
+ events: List of events to replay.
771
+
772
+ Returns:
773
+ Reconstructed state machine.
774
+ """
775
+ machine = cls(saga_id)
776
+
777
+ for event in events:
778
+ if event.target_state:
779
+ machine._state = event.target_state
780
+ if event.step_id:
781
+ machine._current_step = event.step_id
782
+ machine._step_states[event.step_id] = (
783
+ event.target_state or machine._state
784
+ )
785
+ machine._events.append(event)
786
+
787
+ return machine
788
+
789
+
790
+ class InvalidTransitionError(Exception):
791
+ """Raised when an invalid state transition is attempted."""
792
+
793
+ pass