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,683 @@
1
+ """CLDR Plural Rules Implementation.
2
+
3
+ This module provides comprehensive CLDR-compliant plural rule handling,
4
+ supporting cardinal and ordinal pluralization for 100+ languages.
5
+
6
+ Features:
7
+ - Full CLDR plural category support (zero, one, two, few, many, other)
8
+ - Language-specific plural rules
9
+ - Ordinal number support (1st, 2nd, 3rd...)
10
+ - Extensible rule registration
11
+
12
+ Usage:
13
+ from truthound.validators.i18n.plural import (
14
+ CLDRPluralRules,
15
+ PluralCategory,
16
+ pluralize,
17
+ )
18
+
19
+ # Get plural category
20
+ rules = CLDRPluralRules()
21
+ category = rules.get_category(5, LocaleInfo.parse("ru"))
22
+ # -> PluralCategory.MANY
23
+
24
+ # Pluralize a message
25
+ message = pluralize(
26
+ count=3,
27
+ forms={
28
+ PluralCategory.ONE: "{count} file",
29
+ PluralCategory.OTHER: "{count} files",
30
+ },
31
+ locale="en",
32
+ )
33
+ # -> "3 files"
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import math
39
+ from dataclasses import dataclass
40
+ from typing import Callable
41
+
42
+ from truthound.validators.i18n.protocols import (
43
+ BasePluralRuleProvider,
44
+ LocaleInfo,
45
+ PluralCategory,
46
+ )
47
+
48
+
49
+ # Type for plural rule function
50
+ PluralRuleFunc = Callable[[float | int], PluralCategory]
51
+
52
+
53
+ @dataclass
54
+ class PluralOperands:
55
+ """CLDR plural operands for a number.
56
+
57
+ See: https://unicode.org/reports/tr35/tr35-numbers.html#Operands
58
+
59
+ Attributes:
60
+ n: Absolute value of the source number
61
+ i: Integer digits of n
62
+ v: Number of visible fraction digits with trailing zeros
63
+ w: Number of visible fraction digits without trailing zeros
64
+ f: Visible fraction digits with trailing zeros
65
+ t: Visible fraction digits without trailing zeros
66
+ c: Compact decimal exponent value (if using compact notation)
67
+ """
68
+ n: float # absolute value
69
+ i: int # integer digits
70
+ v: int # visible fraction digits (with trailing zeros)
71
+ w: int # visible fraction digits (without trailing zeros)
72
+ f: int # fraction digits as integer (with trailing zeros)
73
+ t: int # fraction digits as integer (without trailing zeros)
74
+ c: int = 0 # compact exponent
75
+
76
+ @classmethod
77
+ def from_number(cls, n: float | int, fraction_digits: int | None = None) -> "PluralOperands":
78
+ """Create operands from a number.
79
+
80
+ Args:
81
+ n: The number
82
+ fraction_digits: Explicit fraction digits (for formatted numbers)
83
+
84
+ Returns:
85
+ PluralOperands instance
86
+ """
87
+ abs_n = abs(n)
88
+ i = int(abs_n)
89
+
90
+ if isinstance(n, int):
91
+ return cls(n=float(abs_n), i=i, v=0, w=0, f=0, t=0)
92
+
93
+ # Get fractional part
94
+ str_n = str(abs_n)
95
+ if "." in str_n:
96
+ fraction_str = str_n.split(".")[1]
97
+ v = len(fraction_str) if fraction_digits is None else fraction_digits
98
+ f = int(fraction_str) if fraction_str else 0
99
+ # Remove trailing zeros for t and w
100
+ t_str = fraction_str.rstrip("0")
101
+ w = len(t_str)
102
+ t = int(t_str) if t_str else 0
103
+ else:
104
+ v = w = f = t = 0
105
+
106
+ return cls(n=float(abs_n), i=i, v=v, w=w, f=f, t=t)
107
+
108
+
109
+ class CLDRPluralRules(BasePluralRuleProvider):
110
+ """CLDR-compliant plural rule provider.
111
+
112
+ Implements plural rules for 100+ languages based on Unicode CLDR.
113
+
114
+ Example:
115
+ rules = CLDRPluralRules()
116
+
117
+ # Cardinal plurals
118
+ rules.get_category(1, LocaleInfo.parse("en")) # ONE
119
+ rules.get_category(2, LocaleInfo.parse("en")) # OTHER
120
+ rules.get_category(1, LocaleInfo.parse("ru")) # ONE
121
+ rules.get_category(2, LocaleInfo.parse("ru")) # FEW
122
+ rules.get_category(5, LocaleInfo.parse("ru")) # MANY
123
+
124
+ # Ordinal plurals
125
+ rules.get_category(1, LocaleInfo.parse("en"), ordinal=True) # ONE (1st)
126
+ rules.get_category(2, LocaleInfo.parse("en"), ordinal=True) # TWO (2nd)
127
+ rules.get_category(3, LocaleInfo.parse("en"), ordinal=True) # FEW (3rd)
128
+ rules.get_category(4, LocaleInfo.parse("en"), ordinal=True) # OTHER (4th)
129
+ """
130
+
131
+ def __init__(self) -> None:
132
+ self._cardinal_rules: dict[str, PluralRuleFunc] = {}
133
+ self._ordinal_rules: dict[str, PluralRuleFunc] = {}
134
+ self._register_default_rules()
135
+
136
+ def _register_default_rules(self) -> None:
137
+ """Register default CLDR plural rules."""
138
+ # ==========================================
139
+ # CARDINAL RULES
140
+ # ==========================================
141
+
142
+ # English, German, Dutch, Italian, Portuguese, Spanish
143
+ # One: i = 1 and v = 0
144
+ def english_cardinal(n: float | int) -> PluralCategory:
145
+ op = PluralOperands.from_number(n)
146
+ if op.i == 1 and op.v == 0:
147
+ return PluralCategory.ONE
148
+ return PluralCategory.OTHER
149
+
150
+ for lang in ["en", "de", "nl", "it", "pt", "es", "ca", "gl", "da", "no", "nb", "nn", "sv", "fi", "et", "hu", "tr", "id", "ms", "tl"]:
151
+ self._cardinal_rules[lang] = english_cardinal
152
+
153
+ # French, Brazilian Portuguese
154
+ # One: i = 0,1
155
+ def french_cardinal(n: float | int) -> PluralCategory:
156
+ op = PluralOperands.from_number(n)
157
+ if op.i in (0, 1):
158
+ return PluralCategory.ONE
159
+ return PluralCategory.OTHER
160
+
161
+ self._cardinal_rules["fr"] = french_cardinal
162
+ self._cardinal_rules["pt_BR"] = french_cardinal
163
+
164
+ # Russian, Ukrainian, Serbian, Croatian, Bosnian, Polish
165
+ # One: v = 0 and i % 10 = 1 and i % 100 != 11
166
+ # Few: v = 0 and i % 10 = 2..4 and i % 100 != 12..14
167
+ # Many: v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14
168
+ def slavic_cardinal(n: float | int) -> PluralCategory:
169
+ op = PluralOperands.from_number(n)
170
+ i10 = op.i % 10
171
+ i100 = op.i % 100
172
+
173
+ if op.v == 0 and i10 == 1 and i100 != 11:
174
+ return PluralCategory.ONE
175
+ if op.v == 0 and 2 <= i10 <= 4 and not (12 <= i100 <= 14):
176
+ return PluralCategory.FEW
177
+ if op.v == 0 and (i10 == 0 or 5 <= i10 <= 9 or 11 <= i100 <= 14):
178
+ return PluralCategory.MANY
179
+ return PluralCategory.OTHER
180
+
181
+ for lang in ["ru", "uk", "sr", "hr", "bs"]:
182
+ self._cardinal_rules[lang] = slavic_cardinal
183
+
184
+ # Polish (slightly different from other Slavic)
185
+ # One: i = 1 and v = 0
186
+ # Few: v = 0 and i % 10 = 2..4 and i % 100 != 12..14
187
+ # Many: v = 0 and i != 1 and i % 10 = 0..1 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 12..14
188
+ def polish_cardinal(n: float | int) -> PluralCategory:
189
+ op = PluralOperands.from_number(n)
190
+ i10 = op.i % 10
191
+ i100 = op.i % 100
192
+
193
+ if op.i == 1 and op.v == 0:
194
+ return PluralCategory.ONE
195
+ if op.v == 0 and 2 <= i10 <= 4 and not (12 <= i100 <= 14):
196
+ return PluralCategory.FEW
197
+ if op.v == 0 and (op.i != 1 and i10 in (0, 1) or 5 <= i10 <= 9 or 12 <= i100 <= 14):
198
+ return PluralCategory.MANY
199
+ return PluralCategory.OTHER
200
+
201
+ self._cardinal_rules["pl"] = polish_cardinal
202
+
203
+ # Arabic
204
+ # Zero: n = 0
205
+ # One: n = 1
206
+ # Two: n = 2
207
+ # Few: n % 100 = 3..10
208
+ # Many: n % 100 = 11..99
209
+ def arabic_cardinal(n: float | int) -> PluralCategory:
210
+ op = PluralOperands.from_number(n)
211
+ n100 = int(op.n) % 100
212
+
213
+ if op.n == 0:
214
+ return PluralCategory.ZERO
215
+ if op.n == 1:
216
+ return PluralCategory.ONE
217
+ if op.n == 2:
218
+ return PluralCategory.TWO
219
+ if 3 <= n100 <= 10:
220
+ return PluralCategory.FEW
221
+ if 11 <= n100 <= 99:
222
+ return PluralCategory.MANY
223
+ return PluralCategory.OTHER
224
+
225
+ self._cardinal_rules["ar"] = arabic_cardinal
226
+
227
+ # Hebrew
228
+ # One: i = 1 and v = 0
229
+ # Two: i = 2 and v = 0
230
+ # Many: v = 0 and not i = 0..10 and i % 10 = 0
231
+ def hebrew_cardinal(n: float | int) -> PluralCategory:
232
+ op = PluralOperands.from_number(n)
233
+
234
+ if op.i == 1 and op.v == 0:
235
+ return PluralCategory.ONE
236
+ if op.i == 2 and op.v == 0:
237
+ return PluralCategory.TWO
238
+ if op.v == 0 and not (0 <= op.i <= 10) and op.i % 10 == 0:
239
+ return PluralCategory.MANY
240
+ return PluralCategory.OTHER
241
+
242
+ self._cardinal_rules["he"] = hebrew_cardinal
243
+
244
+ # Japanese, Korean, Chinese, Vietnamese, Thai, Indonesian, Malay
245
+ # No plural distinction
246
+ def no_plural(n: float | int) -> PluralCategory:
247
+ return PluralCategory.OTHER
248
+
249
+ for lang in ["ja", "ko", "zh", "vi", "th"]:
250
+ self._cardinal_rules[lang] = no_plural
251
+
252
+ # Welsh
253
+ # Zero: n = 0
254
+ # One: n = 1
255
+ # Two: n = 2
256
+ # Few: n = 3
257
+ # Many: n = 6
258
+ def welsh_cardinal(n: float | int) -> PluralCategory:
259
+ if n == 0:
260
+ return PluralCategory.ZERO
261
+ if n == 1:
262
+ return PluralCategory.ONE
263
+ if n == 2:
264
+ return PluralCategory.TWO
265
+ if n == 3:
266
+ return PluralCategory.FEW
267
+ if n == 6:
268
+ return PluralCategory.MANY
269
+ return PluralCategory.OTHER
270
+
271
+ self._cardinal_rules["cy"] = welsh_cardinal
272
+
273
+ # Irish
274
+ # One: n = 1
275
+ # Two: n = 2
276
+ # Few: n = 3..6
277
+ # Many: n = 7..10
278
+ def irish_cardinal(n: float | int) -> PluralCategory:
279
+ if n == 1:
280
+ return PluralCategory.ONE
281
+ if n == 2:
282
+ return PluralCategory.TWO
283
+ if 3 <= n <= 6:
284
+ return PluralCategory.FEW
285
+ if 7 <= n <= 10:
286
+ return PluralCategory.MANY
287
+ return PluralCategory.OTHER
288
+
289
+ self._cardinal_rules["ga"] = irish_cardinal
290
+
291
+ # Latvian
292
+ # Zero: n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19
293
+ # One: n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1
294
+ def latvian_cardinal(n: float | int) -> PluralCategory:
295
+ op = PluralOperands.from_number(n)
296
+ n10 = int(op.n) % 10
297
+ n100 = int(op.n) % 100
298
+ f10 = op.f % 10
299
+ f100 = op.f % 100
300
+
301
+ if n10 == 0 or 11 <= n100 <= 19 or (op.v == 2 and 11 <= f100 <= 19):
302
+ return PluralCategory.ZERO
303
+ if (n10 == 1 and n100 != 11) or (op.v == 2 and f10 == 1 and f100 != 11) or (op.v != 2 and f10 == 1):
304
+ return PluralCategory.ONE
305
+ return PluralCategory.OTHER
306
+
307
+ self._cardinal_rules["lv"] = latvian_cardinal
308
+
309
+ # Lithuanian
310
+ # One: n % 10 = 1 and n % 100 != 11..19
311
+ # Few: n % 10 = 2..9 and n % 100 != 11..19
312
+ def lithuanian_cardinal(n: float | int) -> PluralCategory:
313
+ op = PluralOperands.from_number(n)
314
+ n10 = int(op.n) % 10
315
+ n100 = int(op.n) % 100
316
+
317
+ if n10 == 1 and not (11 <= n100 <= 19):
318
+ return PluralCategory.ONE
319
+ if 2 <= n10 <= 9 and not (11 <= n100 <= 19):
320
+ return PluralCategory.FEW
321
+ return PluralCategory.MANY if op.f != 0 else PluralCategory.OTHER
322
+
323
+ self._cardinal_rules["lt"] = lithuanian_cardinal
324
+
325
+ # Czech, Slovak
326
+ # One: i = 1 and v = 0
327
+ # Few: i = 2..4 and v = 0
328
+ # Many: v != 0
329
+ def czech_cardinal(n: float | int) -> PluralCategory:
330
+ op = PluralOperands.from_number(n)
331
+
332
+ if op.i == 1 and op.v == 0:
333
+ return PluralCategory.ONE
334
+ if 2 <= op.i <= 4 and op.v == 0:
335
+ return PluralCategory.FEW
336
+ if op.v != 0:
337
+ return PluralCategory.MANY
338
+ return PluralCategory.OTHER
339
+
340
+ self._cardinal_rules["cs"] = czech_cardinal
341
+ self._cardinal_rules["sk"] = czech_cardinal
342
+
343
+ # Romanian, Moldavian
344
+ # One: i = 1 and v = 0
345
+ # Few: v != 0 or n = 0 or n % 100 = 2..19
346
+ def romanian_cardinal(n: float | int) -> PluralCategory:
347
+ op = PluralOperands.from_number(n)
348
+ n100 = int(op.n) % 100
349
+
350
+ if op.i == 1 and op.v == 0:
351
+ return PluralCategory.ONE
352
+ if op.v != 0 or op.n == 0 or 2 <= n100 <= 19:
353
+ return PluralCategory.FEW
354
+ return PluralCategory.OTHER
355
+
356
+ self._cardinal_rules["ro"] = romanian_cardinal
357
+ self._cardinal_rules["mo"] = romanian_cardinal
358
+
359
+ # Slovenian
360
+ # One: v = 0 and i % 100 = 1
361
+ # Two: v = 0 and i % 100 = 2
362
+ # Few: v = 0 and i % 100 = 3..4 or v != 0
363
+ def slovenian_cardinal(n: float | int) -> PluralCategory:
364
+ op = PluralOperands.from_number(n)
365
+ i100 = op.i % 100
366
+
367
+ if op.v == 0 and i100 == 1:
368
+ return PluralCategory.ONE
369
+ if op.v == 0 and i100 == 2:
370
+ return PluralCategory.TWO
371
+ if op.v == 0 and 3 <= i100 <= 4 or op.v != 0:
372
+ return PluralCategory.FEW
373
+ return PluralCategory.OTHER
374
+
375
+ self._cardinal_rules["sl"] = slovenian_cardinal
376
+
377
+ # Maltese
378
+ # One: n = 1
379
+ # Few: n = 0 or n % 100 = 2..10
380
+ # Many: n % 100 = 11..19
381
+ def maltese_cardinal(n: float | int) -> PluralCategory:
382
+ op = PluralOperands.from_number(n)
383
+ n100 = int(op.n) % 100
384
+
385
+ if op.n == 1:
386
+ return PluralCategory.ONE
387
+ if op.n == 0 or 2 <= n100 <= 10:
388
+ return PluralCategory.FEW
389
+ if 11 <= n100 <= 19:
390
+ return PluralCategory.MANY
391
+ return PluralCategory.OTHER
392
+
393
+ self._cardinal_rules["mt"] = maltese_cardinal
394
+
395
+ # ==========================================
396
+ # ORDINAL RULES
397
+ # ==========================================
398
+
399
+ # English ordinals: 1st, 2nd, 3rd, 4th...
400
+ def english_ordinal(n: float | int) -> PluralCategory:
401
+ n10 = int(n) % 10
402
+ n100 = int(n) % 100
403
+
404
+ if n10 == 1 and n100 != 11:
405
+ return PluralCategory.ONE # 1st, 21st, 31st...
406
+ if n10 == 2 and n100 != 12:
407
+ return PluralCategory.TWO # 2nd, 22nd, 32nd...
408
+ if n10 == 3 and n100 != 13:
409
+ return PluralCategory.FEW # 3rd, 23rd, 33rd...
410
+ return PluralCategory.OTHER # 4th, 5th, 11th, 12th...
411
+
412
+ self._ordinal_rules["en"] = english_ordinal
413
+
414
+ # Italian ordinals
415
+ # Many: n = 11 or n = 8 or n = 80 or n = 800
416
+ def italian_ordinal(n: float | int) -> PluralCategory:
417
+ if n in (11, 8, 80, 800):
418
+ return PluralCategory.MANY
419
+ return PluralCategory.OTHER
420
+
421
+ self._ordinal_rules["it"] = italian_ordinal
422
+
423
+ # Swedish ordinals
424
+ # One: n % 10 = 1,2 and n % 100 != 11,12
425
+ def swedish_ordinal(n: float | int) -> PluralCategory:
426
+ n10 = int(n) % 10
427
+ n100 = int(n) % 100
428
+
429
+ if n10 in (1, 2) and n100 not in (11, 12):
430
+ return PluralCategory.ONE
431
+ return PluralCategory.OTHER
432
+
433
+ self._ordinal_rules["sv"] = swedish_ordinal
434
+
435
+ # Welsh ordinals
436
+ # Zero: n = 0,7,8,9
437
+ # One: n = 1
438
+ # Two: n = 2
439
+ # Few: n = 3,4
440
+ # Many: n = 5,6
441
+ def welsh_ordinal(n: float | int) -> PluralCategory:
442
+ if n in (0, 7, 8, 9):
443
+ return PluralCategory.ZERO
444
+ if n == 1:
445
+ return PluralCategory.ONE
446
+ if n == 2:
447
+ return PluralCategory.TWO
448
+ if n in (3, 4):
449
+ return PluralCategory.FEW
450
+ if n in (5, 6):
451
+ return PluralCategory.MANY
452
+ return PluralCategory.OTHER
453
+
454
+ self._ordinal_rules["cy"] = welsh_ordinal
455
+
456
+ # Catalan ordinals
457
+ # One: n = 1,3
458
+ # Two: n = 2
459
+ # Few: n = 4
460
+ def catalan_ordinal(n: float | int) -> PluralCategory:
461
+ if n in (1, 3):
462
+ return PluralCategory.ONE
463
+ if n == 2:
464
+ return PluralCategory.TWO
465
+ if n == 4:
466
+ return PluralCategory.FEW
467
+ return PluralCategory.OTHER
468
+
469
+ self._ordinal_rules["ca"] = catalan_ordinal
470
+
471
+ # Hungarian ordinals
472
+ # One: n = 1,5
473
+ def hungarian_ordinal(n: float | int) -> PluralCategory:
474
+ if n in (1, 5):
475
+ return PluralCategory.ONE
476
+ return PluralCategory.OTHER
477
+
478
+ self._ordinal_rules["hu"] = hungarian_ordinal
479
+
480
+ # Georgian ordinals
481
+ # One: i = 1
482
+ # Many: i = 0 or i % 100 = 2..20,40,60,80
483
+ def georgian_ordinal(n: float | int) -> PluralCategory:
484
+ i = int(n)
485
+ i100 = i % 100
486
+
487
+ if i == 1:
488
+ return PluralCategory.ONE
489
+ if i == 0 or 2 <= i100 <= 20 or i100 in (40, 60, 80):
490
+ return PluralCategory.MANY
491
+ return PluralCategory.OTHER
492
+
493
+ self._ordinal_rules["ka"] = georgian_ordinal
494
+
495
+ # Default ordinal (no distinction)
496
+ def default_ordinal(n: float | int) -> PluralCategory:
497
+ return PluralCategory.OTHER
498
+
499
+ # Apply default ordinal to languages without specific rules
500
+ for lang in ["ko", "ja", "zh", "vi", "th", "ar", "he", "fa"]:
501
+ self._ordinal_rules[lang] = default_ordinal
502
+
503
+ def register_cardinal_rule(self, language: str, rule: PluralRuleFunc) -> None:
504
+ """Register a custom cardinal plural rule.
505
+
506
+ Args:
507
+ language: ISO 639-1 language code
508
+ rule: Plural rule function
509
+ """
510
+ self._cardinal_rules[language] = rule
511
+
512
+ def register_ordinal_rule(self, language: str, rule: PluralRuleFunc) -> None:
513
+ """Register a custom ordinal plural rule.
514
+
515
+ Args:
516
+ language: ISO 639-1 language code
517
+ rule: Plural rule function
518
+ """
519
+ self._ordinal_rules[language] = rule
520
+
521
+ def get_category(
522
+ self,
523
+ count: float | int,
524
+ locale: LocaleInfo,
525
+ ordinal: bool = False,
526
+ ) -> PluralCategory:
527
+ """Get the plural category for a number.
528
+
529
+ Args:
530
+ count: The number to categorize
531
+ locale: Target locale
532
+ ordinal: If True, use ordinal rules
533
+
534
+ Returns:
535
+ Appropriate plural category
536
+ """
537
+ rules = self._ordinal_rules if ordinal else self._cardinal_rules
538
+
539
+ # Try exact language match first
540
+ if locale.language in rules:
541
+ return rules[locale.language](count)
542
+
543
+ # Try language with region
544
+ if locale.region:
545
+ key = f"{locale.language}_{locale.region}"
546
+ if key in rules:
547
+ return rules[key](count)
548
+
549
+ # Default: use OTHER
550
+ return PluralCategory.OTHER
551
+
552
+ def get_supported_languages(self, ordinal: bool = False) -> list[str]:
553
+ """Get list of supported language codes.
554
+
555
+ Args:
556
+ ordinal: If True, return ordinal-supported languages
557
+
558
+ Returns:
559
+ List of language codes
560
+ """
561
+ rules = self._ordinal_rules if ordinal else self._cardinal_rules
562
+ return list(rules.keys())
563
+
564
+
565
+ # Global instance
566
+ _plural_rules = CLDRPluralRules()
567
+
568
+
569
+ def get_plural_category(
570
+ count: float | int,
571
+ locale: str | LocaleInfo,
572
+ ordinal: bool = False,
573
+ ) -> PluralCategory:
574
+ """Get the plural category for a number.
575
+
576
+ Args:
577
+ count: The number to categorize
578
+ locale: Target locale (string or LocaleInfo)
579
+ ordinal: If True, use ordinal rules
580
+
581
+ Returns:
582
+ Appropriate plural category
583
+
584
+ Example:
585
+ get_plural_category(1, "en") # ONE
586
+ get_plural_category(2, "en") # OTHER
587
+ get_plural_category(5, "ru") # MANY
588
+ """
589
+ if isinstance(locale, str):
590
+ locale = LocaleInfo.parse(locale)
591
+
592
+ return _plural_rules.get_category(count, locale, ordinal)
593
+
594
+
595
+ def pluralize(
596
+ count: float | int,
597
+ forms: dict[PluralCategory | str, str],
598
+ locale: str | LocaleInfo = "en",
599
+ ordinal: bool = False,
600
+ **params,
601
+ ) -> str:
602
+ """Select and format a pluralized message.
603
+
604
+ Args:
605
+ count: Number for pluralization
606
+ forms: Dictionary mapping plural categories to message templates
607
+ locale: Target locale
608
+ ordinal: If True, use ordinal rules
609
+ **params: Additional format parameters
610
+
611
+ Returns:
612
+ Formatted message
613
+
614
+ Example:
615
+ # English example
616
+ pluralize(
617
+ count=3,
618
+ forms={
619
+ PluralCategory.ONE: "{count} file",
620
+ PluralCategory.OTHER: "{count} files",
621
+ },
622
+ locale="en",
623
+ )
624
+ # -> "3 files"
625
+
626
+ # Russian example
627
+ pluralize(
628
+ count=3,
629
+ forms={
630
+ PluralCategory.ONE: "{count} файл",
631
+ PluralCategory.FEW: "{count} файла",
632
+ PluralCategory.MANY: "{count} файлов",
633
+ PluralCategory.OTHER: "{count} файла",
634
+ },
635
+ locale="ru",
636
+ )
637
+ # -> "3 файла"
638
+
639
+ # Using string keys
640
+ pluralize(
641
+ count=1,
642
+ forms={
643
+ "one": "{count} item",
644
+ "other": "{count} items",
645
+ },
646
+ locale="en",
647
+ )
648
+ # -> "1 item"
649
+ """
650
+ if isinstance(locale, str):
651
+ locale = LocaleInfo.parse(locale)
652
+
653
+ category = _plural_rules.get_category(count, locale, ordinal)
654
+
655
+ # Normalize form keys to PluralCategory
656
+ normalized_forms: dict[PluralCategory, str] = {}
657
+ for key, value in forms.items():
658
+ if isinstance(key, str):
659
+ try:
660
+ cat = PluralCategory(key.lower())
661
+ except ValueError:
662
+ continue
663
+ else:
664
+ cat = key
665
+ normalized_forms[cat] = value
666
+
667
+ # Get template
668
+ template = _plural_rules.get_plural_form(count, normalized_forms, locale)
669
+
670
+ # Format with count and additional params
671
+ try:
672
+ return template.format(count=count, **params)
673
+ except KeyError:
674
+ return template
675
+
676
+
677
+ def get_plural_rules() -> CLDRPluralRules:
678
+ """Get the global plural rules instance.
679
+
680
+ Returns:
681
+ CLDRPluralRules instance
682
+ """
683
+ return _plural_rules