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.
- truthound/__init__.py +162 -0
- truthound/adapters.py +100 -0
- truthound/api.py +365 -0
- truthound/audit/__init__.py +248 -0
- truthound/audit/core.py +967 -0
- truthound/audit/filters.py +620 -0
- truthound/audit/formatters.py +707 -0
- truthound/audit/logger.py +902 -0
- truthound/audit/middleware.py +571 -0
- truthound/audit/storage.py +1083 -0
- truthound/benchmark/__init__.py +123 -0
- truthound/benchmark/base.py +757 -0
- truthound/benchmark/comparison.py +635 -0
- truthound/benchmark/generators.py +706 -0
- truthound/benchmark/reporters.py +718 -0
- truthound/benchmark/runner.py +635 -0
- truthound/benchmark/scenarios.py +712 -0
- truthound/cache.py +252 -0
- truthound/checkpoint/__init__.py +136 -0
- truthound/checkpoint/actions/__init__.py +164 -0
- truthound/checkpoint/actions/base.py +324 -0
- truthound/checkpoint/actions/custom.py +234 -0
- truthound/checkpoint/actions/discord_notify.py +290 -0
- truthound/checkpoint/actions/email_notify.py +405 -0
- truthound/checkpoint/actions/github_action.py +406 -0
- truthound/checkpoint/actions/opsgenie.py +1499 -0
- truthound/checkpoint/actions/pagerduty.py +226 -0
- truthound/checkpoint/actions/slack_notify.py +233 -0
- truthound/checkpoint/actions/store_result.py +249 -0
- truthound/checkpoint/actions/teams_notify.py +1570 -0
- truthound/checkpoint/actions/telegram_notify.py +419 -0
- truthound/checkpoint/actions/update_docs.py +552 -0
- truthound/checkpoint/actions/webhook.py +293 -0
- truthound/checkpoint/analytics/__init__.py +147 -0
- truthound/checkpoint/analytics/aggregations/__init__.py +23 -0
- truthound/checkpoint/analytics/aggregations/rollup.py +481 -0
- truthound/checkpoint/analytics/aggregations/time_bucket.py +306 -0
- truthound/checkpoint/analytics/analyzers/__init__.py +17 -0
- truthound/checkpoint/analytics/analyzers/anomaly.py +386 -0
- truthound/checkpoint/analytics/analyzers/base.py +270 -0
- truthound/checkpoint/analytics/analyzers/forecast.py +421 -0
- truthound/checkpoint/analytics/analyzers/trend.py +314 -0
- truthound/checkpoint/analytics/models.py +292 -0
- truthound/checkpoint/analytics/protocols.py +549 -0
- truthound/checkpoint/analytics/service.py +718 -0
- truthound/checkpoint/analytics/stores/__init__.py +16 -0
- truthound/checkpoint/analytics/stores/base.py +306 -0
- truthound/checkpoint/analytics/stores/memory_store.py +353 -0
- truthound/checkpoint/analytics/stores/sqlite_store.py +557 -0
- truthound/checkpoint/analytics/stores/timescale_store.py +501 -0
- truthound/checkpoint/async_actions.py +794 -0
- truthound/checkpoint/async_base.py +708 -0
- truthound/checkpoint/async_checkpoint.py +617 -0
- truthound/checkpoint/async_runner.py +639 -0
- truthound/checkpoint/checkpoint.py +527 -0
- truthound/checkpoint/ci/__init__.py +61 -0
- truthound/checkpoint/ci/detector.py +355 -0
- truthound/checkpoint/ci/reporter.py +436 -0
- truthound/checkpoint/ci/templates.py +454 -0
- truthound/checkpoint/circuitbreaker/__init__.py +133 -0
- truthound/checkpoint/circuitbreaker/breaker.py +542 -0
- truthound/checkpoint/circuitbreaker/core.py +252 -0
- truthound/checkpoint/circuitbreaker/detection.py +459 -0
- truthound/checkpoint/circuitbreaker/middleware.py +389 -0
- truthound/checkpoint/circuitbreaker/registry.py +357 -0
- truthound/checkpoint/distributed/__init__.py +139 -0
- truthound/checkpoint/distributed/backends/__init__.py +35 -0
- truthound/checkpoint/distributed/backends/celery_backend.py +503 -0
- truthound/checkpoint/distributed/backends/kubernetes_backend.py +696 -0
- truthound/checkpoint/distributed/backends/local_backend.py +397 -0
- truthound/checkpoint/distributed/backends/ray_backend.py +625 -0
- truthound/checkpoint/distributed/base.py +774 -0
- truthound/checkpoint/distributed/orchestrator.py +765 -0
- truthound/checkpoint/distributed/protocols.py +842 -0
- truthound/checkpoint/distributed/registry.py +449 -0
- truthound/checkpoint/idempotency/__init__.py +120 -0
- truthound/checkpoint/idempotency/core.py +295 -0
- truthound/checkpoint/idempotency/fingerprint.py +454 -0
- truthound/checkpoint/idempotency/locking.py +604 -0
- truthound/checkpoint/idempotency/service.py +592 -0
- truthound/checkpoint/idempotency/stores.py +653 -0
- truthound/checkpoint/monitoring/__init__.py +134 -0
- truthound/checkpoint/monitoring/aggregators/__init__.py +15 -0
- truthound/checkpoint/monitoring/aggregators/base.py +372 -0
- truthound/checkpoint/monitoring/aggregators/realtime.py +300 -0
- truthound/checkpoint/monitoring/aggregators/window.py +493 -0
- truthound/checkpoint/monitoring/collectors/__init__.py +17 -0
- truthound/checkpoint/monitoring/collectors/base.py +257 -0
- truthound/checkpoint/monitoring/collectors/memory_collector.py +617 -0
- truthound/checkpoint/monitoring/collectors/prometheus_collector.py +451 -0
- truthound/checkpoint/monitoring/collectors/redis_collector.py +518 -0
- truthound/checkpoint/monitoring/events.py +410 -0
- truthound/checkpoint/monitoring/protocols.py +636 -0
- truthound/checkpoint/monitoring/service.py +578 -0
- truthound/checkpoint/monitoring/views/__init__.py +17 -0
- truthound/checkpoint/monitoring/views/base.py +172 -0
- truthound/checkpoint/monitoring/views/queue_view.py +220 -0
- truthound/checkpoint/monitoring/views/task_view.py +240 -0
- truthound/checkpoint/monitoring/views/worker_view.py +263 -0
- truthound/checkpoint/registry.py +337 -0
- truthound/checkpoint/runner.py +356 -0
- truthound/checkpoint/transaction/__init__.py +133 -0
- truthound/checkpoint/transaction/base.py +389 -0
- truthound/checkpoint/transaction/compensatable.py +537 -0
- truthound/checkpoint/transaction/coordinator.py +576 -0
- truthound/checkpoint/transaction/executor.py +622 -0
- truthound/checkpoint/transaction/idempotency.py +534 -0
- truthound/checkpoint/transaction/saga/__init__.py +143 -0
- truthound/checkpoint/transaction/saga/builder.py +584 -0
- truthound/checkpoint/transaction/saga/definition.py +515 -0
- truthound/checkpoint/transaction/saga/event_store.py +542 -0
- truthound/checkpoint/transaction/saga/patterns.py +833 -0
- truthound/checkpoint/transaction/saga/runner.py +718 -0
- truthound/checkpoint/transaction/saga/state_machine.py +793 -0
- truthound/checkpoint/transaction/saga/strategies.py +780 -0
- truthound/checkpoint/transaction/saga/testing.py +886 -0
- truthound/checkpoint/triggers/__init__.py +58 -0
- truthound/checkpoint/triggers/base.py +237 -0
- truthound/checkpoint/triggers/event.py +385 -0
- truthound/checkpoint/triggers/schedule.py +355 -0
- truthound/cli.py +2358 -0
- truthound/cli_modules/__init__.py +124 -0
- truthound/cli_modules/advanced/__init__.py +45 -0
- truthound/cli_modules/advanced/benchmark.py +343 -0
- truthound/cli_modules/advanced/docs.py +225 -0
- truthound/cli_modules/advanced/lineage.py +209 -0
- truthound/cli_modules/advanced/ml.py +320 -0
- truthound/cli_modules/advanced/realtime.py +196 -0
- truthound/cli_modules/checkpoint/__init__.py +46 -0
- truthound/cli_modules/checkpoint/init.py +114 -0
- truthound/cli_modules/checkpoint/list.py +71 -0
- truthound/cli_modules/checkpoint/run.py +159 -0
- truthound/cli_modules/checkpoint/validate.py +67 -0
- truthound/cli_modules/common/__init__.py +71 -0
- truthound/cli_modules/common/errors.py +414 -0
- truthound/cli_modules/common/options.py +419 -0
- truthound/cli_modules/common/output.py +507 -0
- truthound/cli_modules/common/protocol.py +552 -0
- truthound/cli_modules/core/__init__.py +48 -0
- truthound/cli_modules/core/check.py +123 -0
- truthound/cli_modules/core/compare.py +104 -0
- truthound/cli_modules/core/learn.py +57 -0
- truthound/cli_modules/core/mask.py +77 -0
- truthound/cli_modules/core/profile.py +65 -0
- truthound/cli_modules/core/scan.py +61 -0
- truthound/cli_modules/profiler/__init__.py +51 -0
- truthound/cli_modules/profiler/auto_profile.py +175 -0
- truthound/cli_modules/profiler/metadata.py +107 -0
- truthound/cli_modules/profiler/suite.py +283 -0
- truthound/cli_modules/registry.py +431 -0
- truthound/cli_modules/scaffolding/__init__.py +89 -0
- truthound/cli_modules/scaffolding/base.py +631 -0
- truthound/cli_modules/scaffolding/commands.py +545 -0
- truthound/cli_modules/scaffolding/plugins.py +1072 -0
- truthound/cli_modules/scaffolding/reporters.py +594 -0
- truthound/cli_modules/scaffolding/validators.py +1127 -0
- truthound/common/__init__.py +18 -0
- truthound/common/resilience/__init__.py +130 -0
- truthound/common/resilience/bulkhead.py +266 -0
- truthound/common/resilience/circuit_breaker.py +516 -0
- truthound/common/resilience/composite.py +332 -0
- truthound/common/resilience/config.py +292 -0
- truthound/common/resilience/protocols.py +217 -0
- truthound/common/resilience/rate_limiter.py +404 -0
- truthound/common/resilience/retry.py +341 -0
- truthound/datadocs/__init__.py +260 -0
- truthound/datadocs/base.py +571 -0
- truthound/datadocs/builder.py +761 -0
- truthound/datadocs/charts.py +764 -0
- truthound/datadocs/dashboard/__init__.py +63 -0
- truthound/datadocs/dashboard/app.py +576 -0
- truthound/datadocs/dashboard/components.py +584 -0
- truthound/datadocs/dashboard/state.py +240 -0
- truthound/datadocs/engine/__init__.py +46 -0
- truthound/datadocs/engine/context.py +376 -0
- truthound/datadocs/engine/pipeline.py +618 -0
- truthound/datadocs/engine/registry.py +469 -0
- truthound/datadocs/exporters/__init__.py +49 -0
- truthound/datadocs/exporters/base.py +198 -0
- truthound/datadocs/exporters/html.py +178 -0
- truthound/datadocs/exporters/json_exporter.py +253 -0
- truthound/datadocs/exporters/markdown.py +284 -0
- truthound/datadocs/exporters/pdf.py +392 -0
- truthound/datadocs/i18n/__init__.py +86 -0
- truthound/datadocs/i18n/catalog.py +960 -0
- truthound/datadocs/i18n/formatting.py +505 -0
- truthound/datadocs/i18n/loader.py +256 -0
- truthound/datadocs/i18n/plurals.py +378 -0
- truthound/datadocs/renderers/__init__.py +42 -0
- truthound/datadocs/renderers/base.py +401 -0
- truthound/datadocs/renderers/custom.py +342 -0
- truthound/datadocs/renderers/jinja.py +697 -0
- truthound/datadocs/sections.py +736 -0
- truthound/datadocs/styles.py +931 -0
- truthound/datadocs/themes/__init__.py +101 -0
- truthound/datadocs/themes/base.py +336 -0
- truthound/datadocs/themes/default.py +417 -0
- truthound/datadocs/themes/enterprise.py +419 -0
- truthound/datadocs/themes/loader.py +336 -0
- truthound/datadocs/themes.py +301 -0
- truthound/datadocs/transformers/__init__.py +57 -0
- truthound/datadocs/transformers/base.py +268 -0
- truthound/datadocs/transformers/enrichers.py +544 -0
- truthound/datadocs/transformers/filters.py +447 -0
- truthound/datadocs/transformers/i18n.py +468 -0
- truthound/datadocs/versioning/__init__.py +62 -0
- truthound/datadocs/versioning/diff.py +639 -0
- truthound/datadocs/versioning/storage.py +497 -0
- truthound/datadocs/versioning/version.py +358 -0
- truthound/datasources/__init__.py +223 -0
- truthound/datasources/_async_protocols.py +222 -0
- truthound/datasources/_protocols.py +159 -0
- truthound/datasources/adapters.py +428 -0
- truthound/datasources/async_base.py +599 -0
- truthound/datasources/async_factory.py +511 -0
- truthound/datasources/base.py +516 -0
- truthound/datasources/factory.py +433 -0
- truthound/datasources/nosql/__init__.py +47 -0
- truthound/datasources/nosql/base.py +487 -0
- truthound/datasources/nosql/elasticsearch.py +801 -0
- truthound/datasources/nosql/mongodb.py +636 -0
- truthound/datasources/pandas_optimized.py +582 -0
- truthound/datasources/pandas_source.py +216 -0
- truthound/datasources/polars_source.py +395 -0
- truthound/datasources/spark_source.py +479 -0
- truthound/datasources/sql/__init__.py +154 -0
- truthound/datasources/sql/base.py +710 -0
- truthound/datasources/sql/bigquery.py +410 -0
- truthound/datasources/sql/cloud_base.py +199 -0
- truthound/datasources/sql/databricks.py +471 -0
- truthound/datasources/sql/mysql.py +316 -0
- truthound/datasources/sql/oracle.py +427 -0
- truthound/datasources/sql/postgresql.py +321 -0
- truthound/datasources/sql/redshift.py +479 -0
- truthound/datasources/sql/snowflake.py +439 -0
- truthound/datasources/sql/sqlite.py +286 -0
- truthound/datasources/sql/sqlserver.py +437 -0
- truthound/datasources/streaming/__init__.py +47 -0
- truthound/datasources/streaming/base.py +350 -0
- truthound/datasources/streaming/kafka.py +670 -0
- truthound/decorators.py +98 -0
- truthound/docs/__init__.py +69 -0
- truthound/docs/extractor.py +971 -0
- truthound/docs/generator.py +601 -0
- truthound/docs/parser.py +1037 -0
- truthound/docs/renderer.py +999 -0
- truthound/drift/__init__.py +22 -0
- truthound/drift/compare.py +189 -0
- truthound/drift/detectors.py +464 -0
- truthound/drift/report.py +160 -0
- truthound/execution/__init__.py +65 -0
- truthound/execution/_protocols.py +324 -0
- truthound/execution/base.py +576 -0
- truthound/execution/distributed/__init__.py +179 -0
- truthound/execution/distributed/aggregations.py +731 -0
- truthound/execution/distributed/arrow_bridge.py +817 -0
- truthound/execution/distributed/base.py +550 -0
- truthound/execution/distributed/dask_engine.py +976 -0
- truthound/execution/distributed/mixins.py +766 -0
- truthound/execution/distributed/protocols.py +756 -0
- truthound/execution/distributed/ray_engine.py +1127 -0
- truthound/execution/distributed/registry.py +446 -0
- truthound/execution/distributed/spark_engine.py +1011 -0
- truthound/execution/distributed/validator_adapter.py +682 -0
- truthound/execution/pandas_engine.py +401 -0
- truthound/execution/polars_engine.py +497 -0
- truthound/execution/pushdown/__init__.py +230 -0
- truthound/execution/pushdown/ast.py +1550 -0
- truthound/execution/pushdown/builder.py +1550 -0
- truthound/execution/pushdown/dialects.py +1072 -0
- truthound/execution/pushdown/executor.py +829 -0
- truthound/execution/pushdown/optimizer.py +1041 -0
- truthound/execution/sql_engine.py +518 -0
- truthound/infrastructure/__init__.py +189 -0
- truthound/infrastructure/audit.py +1515 -0
- truthound/infrastructure/config.py +1133 -0
- truthound/infrastructure/encryption.py +1132 -0
- truthound/infrastructure/logging.py +1503 -0
- truthound/infrastructure/metrics.py +1220 -0
- truthound/lineage/__init__.py +89 -0
- truthound/lineage/base.py +746 -0
- truthound/lineage/impact_analysis.py +474 -0
- truthound/lineage/integrations/__init__.py +22 -0
- truthound/lineage/integrations/openlineage.py +548 -0
- truthound/lineage/tracker.py +512 -0
- truthound/lineage/visualization/__init__.py +33 -0
- truthound/lineage/visualization/protocols.py +145 -0
- truthound/lineage/visualization/renderers/__init__.py +20 -0
- truthound/lineage/visualization/renderers/cytoscape.py +329 -0
- truthound/lineage/visualization/renderers/d3.py +331 -0
- truthound/lineage/visualization/renderers/graphviz.py +276 -0
- truthound/lineage/visualization/renderers/mermaid.py +308 -0
- truthound/maskers.py +113 -0
- truthound/ml/__init__.py +124 -0
- truthound/ml/anomaly_models/__init__.py +31 -0
- truthound/ml/anomaly_models/ensemble.py +362 -0
- truthound/ml/anomaly_models/isolation_forest.py +444 -0
- truthound/ml/anomaly_models/statistical.py +392 -0
- truthound/ml/base.py +1178 -0
- truthound/ml/drift_detection/__init__.py +26 -0
- truthound/ml/drift_detection/concept.py +381 -0
- truthound/ml/drift_detection/distribution.py +361 -0
- truthound/ml/drift_detection/feature.py +442 -0
- truthound/ml/drift_detection/multivariate.py +495 -0
- truthound/ml/monitoring/__init__.py +88 -0
- truthound/ml/monitoring/alerting/__init__.py +33 -0
- truthound/ml/monitoring/alerting/handlers.py +427 -0
- truthound/ml/monitoring/alerting/rules.py +508 -0
- truthound/ml/monitoring/collectors/__init__.py +19 -0
- truthound/ml/monitoring/collectors/composite.py +105 -0
- truthound/ml/monitoring/collectors/drift.py +324 -0
- truthound/ml/monitoring/collectors/performance.py +179 -0
- truthound/ml/monitoring/collectors/quality.py +369 -0
- truthound/ml/monitoring/monitor.py +536 -0
- truthound/ml/monitoring/protocols.py +451 -0
- truthound/ml/monitoring/stores/__init__.py +15 -0
- truthound/ml/monitoring/stores/memory.py +201 -0
- truthound/ml/monitoring/stores/prometheus.py +296 -0
- truthound/ml/rule_learning/__init__.py +25 -0
- truthound/ml/rule_learning/constraint_miner.py +443 -0
- truthound/ml/rule_learning/pattern_learner.py +499 -0
- truthound/ml/rule_learning/profile_learner.py +462 -0
- truthound/multitenancy/__init__.py +326 -0
- truthound/multitenancy/core.py +852 -0
- truthound/multitenancy/integration.py +597 -0
- truthound/multitenancy/isolation.py +630 -0
- truthound/multitenancy/manager.py +770 -0
- truthound/multitenancy/middleware.py +765 -0
- truthound/multitenancy/quota.py +537 -0
- truthound/multitenancy/resolvers.py +603 -0
- truthound/multitenancy/storage.py +703 -0
- truthound/observability/__init__.py +307 -0
- truthound/observability/context.py +531 -0
- truthound/observability/instrumentation.py +611 -0
- truthound/observability/logging.py +887 -0
- truthound/observability/metrics.py +1157 -0
- truthound/observability/tracing/__init__.py +178 -0
- truthound/observability/tracing/baggage.py +310 -0
- truthound/observability/tracing/config.py +426 -0
- truthound/observability/tracing/exporter.py +787 -0
- truthound/observability/tracing/integration.py +1018 -0
- truthound/observability/tracing/otel/__init__.py +146 -0
- truthound/observability/tracing/otel/adapter.py +982 -0
- truthound/observability/tracing/otel/bridge.py +1177 -0
- truthound/observability/tracing/otel/compat.py +681 -0
- truthound/observability/tracing/otel/config.py +691 -0
- truthound/observability/tracing/otel/detection.py +327 -0
- truthound/observability/tracing/otel/protocols.py +426 -0
- truthound/observability/tracing/processor.py +561 -0
- truthound/observability/tracing/propagator.py +757 -0
- truthound/observability/tracing/provider.py +569 -0
- truthound/observability/tracing/resource.py +515 -0
- truthound/observability/tracing/sampler.py +487 -0
- truthound/observability/tracing/span.py +676 -0
- truthound/plugins/__init__.py +198 -0
- truthound/plugins/base.py +599 -0
- truthound/plugins/cli.py +680 -0
- truthound/plugins/dependencies/__init__.py +42 -0
- truthound/plugins/dependencies/graph.py +422 -0
- truthound/plugins/dependencies/resolver.py +417 -0
- truthound/plugins/discovery.py +379 -0
- truthound/plugins/docs/__init__.py +46 -0
- truthound/plugins/docs/extractor.py +444 -0
- truthound/plugins/docs/renderer.py +499 -0
- truthound/plugins/enterprise_manager.py +877 -0
- truthound/plugins/examples/__init__.py +19 -0
- truthound/plugins/examples/custom_validators.py +317 -0
- truthound/plugins/examples/slack_notifier.py +312 -0
- truthound/plugins/examples/xml_reporter.py +254 -0
- truthound/plugins/hooks.py +558 -0
- truthound/plugins/lifecycle/__init__.py +43 -0
- truthound/plugins/lifecycle/hot_reload.py +402 -0
- truthound/plugins/lifecycle/manager.py +371 -0
- truthound/plugins/manager.py +736 -0
- truthound/plugins/registry.py +338 -0
- truthound/plugins/security/__init__.py +93 -0
- truthound/plugins/security/exceptions.py +332 -0
- truthound/plugins/security/policies.py +348 -0
- truthound/plugins/security/protocols.py +643 -0
- truthound/plugins/security/sandbox/__init__.py +45 -0
- truthound/plugins/security/sandbox/context.py +158 -0
- truthound/plugins/security/sandbox/engines/__init__.py +19 -0
- truthound/plugins/security/sandbox/engines/container.py +379 -0
- truthound/plugins/security/sandbox/engines/noop.py +144 -0
- truthound/plugins/security/sandbox/engines/process.py +336 -0
- truthound/plugins/security/sandbox/factory.py +211 -0
- truthound/plugins/security/signing/__init__.py +57 -0
- truthound/plugins/security/signing/service.py +330 -0
- truthound/plugins/security/signing/trust_store.py +368 -0
- truthound/plugins/security/signing/verifier.py +459 -0
- truthound/plugins/versioning/__init__.py +41 -0
- truthound/plugins/versioning/constraints.py +297 -0
- truthound/plugins/versioning/resolver.py +329 -0
- truthound/profiler/__init__.py +1729 -0
- truthound/profiler/_lazy.py +452 -0
- truthound/profiler/ab_testing/__init__.py +80 -0
- truthound/profiler/ab_testing/analysis.py +449 -0
- truthound/profiler/ab_testing/base.py +257 -0
- truthound/profiler/ab_testing/experiment.py +395 -0
- truthound/profiler/ab_testing/tracking.py +368 -0
- truthound/profiler/auto_threshold.py +1170 -0
- truthound/profiler/base.py +579 -0
- truthound/profiler/cache_patterns.py +911 -0
- truthound/profiler/caching.py +1303 -0
- truthound/profiler/column_profiler.py +712 -0
- truthound/profiler/comparison.py +1007 -0
- truthound/profiler/custom_patterns.py +1170 -0
- truthound/profiler/dashboard/__init__.py +50 -0
- truthound/profiler/dashboard/app.py +476 -0
- truthound/profiler/dashboard/components.py +457 -0
- truthound/profiler/dashboard/config.py +72 -0
- truthound/profiler/distributed/__init__.py +83 -0
- truthound/profiler/distributed/base.py +281 -0
- truthound/profiler/distributed/dask_backend.py +498 -0
- truthound/profiler/distributed/local_backend.py +293 -0
- truthound/profiler/distributed/profiler.py +304 -0
- truthound/profiler/distributed/ray_backend.py +374 -0
- truthound/profiler/distributed/spark_backend.py +375 -0
- truthound/profiler/distributed.py +1366 -0
- truthound/profiler/enterprise_sampling.py +1065 -0
- truthound/profiler/errors.py +488 -0
- truthound/profiler/evolution/__init__.py +91 -0
- truthound/profiler/evolution/alerts.py +426 -0
- truthound/profiler/evolution/changes.py +206 -0
- truthound/profiler/evolution/compatibility.py +365 -0
- truthound/profiler/evolution/detector.py +372 -0
- truthound/profiler/evolution/protocols.py +121 -0
- truthound/profiler/generators/__init__.py +48 -0
- truthound/profiler/generators/base.py +384 -0
- truthound/profiler/generators/ml_rules.py +375 -0
- truthound/profiler/generators/pattern_rules.py +384 -0
- truthound/profiler/generators/schema_rules.py +267 -0
- truthound/profiler/generators/stats_rules.py +324 -0
- truthound/profiler/generators/suite_generator.py +857 -0
- truthound/profiler/i18n.py +1542 -0
- truthound/profiler/incremental.py +554 -0
- truthound/profiler/incremental_validation.py +1710 -0
- truthound/profiler/integration/__init__.py +73 -0
- truthound/profiler/integration/adapters.py +345 -0
- truthound/profiler/integration/context.py +371 -0
- truthound/profiler/integration/executor.py +527 -0
- truthound/profiler/integration/naming.py +75 -0
- truthound/profiler/integration/protocols.py +243 -0
- truthound/profiler/memory.py +1185 -0
- truthound/profiler/migration/__init__.py +60 -0
- truthound/profiler/migration/base.py +345 -0
- truthound/profiler/migration/manager.py +444 -0
- truthound/profiler/migration/v1_0_to_v1_1.py +484 -0
- truthound/profiler/ml/__init__.py +73 -0
- truthound/profiler/ml/base.py +244 -0
- truthound/profiler/ml/classifier.py +507 -0
- truthound/profiler/ml/feature_extraction.py +604 -0
- truthound/profiler/ml/pretrained.py +448 -0
- truthound/profiler/ml_inference.py +1276 -0
- truthound/profiler/native_patterns.py +815 -0
- truthound/profiler/observability.py +1184 -0
- truthound/profiler/process_timeout.py +1566 -0
- truthound/profiler/progress.py +568 -0
- truthound/profiler/progress_callbacks.py +1734 -0
- truthound/profiler/quality.py +1345 -0
- truthound/profiler/resilience.py +1180 -0
- truthound/profiler/sampled_matcher.py +794 -0
- truthound/profiler/sampling.py +1288 -0
- truthound/profiler/scheduling/__init__.py +82 -0
- truthound/profiler/scheduling/protocols.py +214 -0
- truthound/profiler/scheduling/scheduler.py +474 -0
- truthound/profiler/scheduling/storage.py +457 -0
- truthound/profiler/scheduling/triggers.py +449 -0
- truthound/profiler/schema.py +603 -0
- truthound/profiler/streaming.py +685 -0
- truthound/profiler/streaming_patterns.py +1354 -0
- truthound/profiler/suite_cli.py +625 -0
- truthound/profiler/suite_config.py +789 -0
- truthound/profiler/suite_export.py +1268 -0
- truthound/profiler/table_profiler.py +547 -0
- truthound/profiler/timeout.py +565 -0
- truthound/profiler/validation.py +1532 -0
- truthound/profiler/visualization/__init__.py +118 -0
- truthound/profiler/visualization/base.py +346 -0
- truthound/profiler/visualization/generator.py +1259 -0
- truthound/profiler/visualization/plotly_renderer.py +811 -0
- truthound/profiler/visualization/renderers.py +669 -0
- truthound/profiler/visualization/sections.py +540 -0
- truthound/profiler/visualization.py +2122 -0
- truthound/profiler/yaml_validation.py +1151 -0
- truthound/py.typed +0 -0
- truthound/ratelimit/__init__.py +248 -0
- truthound/ratelimit/algorithms.py +1108 -0
- truthound/ratelimit/core.py +573 -0
- truthound/ratelimit/integration.py +532 -0
- truthound/ratelimit/limiter.py +663 -0
- truthound/ratelimit/middleware.py +700 -0
- truthound/ratelimit/policy.py +792 -0
- truthound/ratelimit/storage.py +763 -0
- truthound/rbac/__init__.py +340 -0
- truthound/rbac/core.py +976 -0
- truthound/rbac/integration.py +760 -0
- truthound/rbac/manager.py +1052 -0
- truthound/rbac/middleware.py +842 -0
- truthound/rbac/policy.py +954 -0
- truthound/rbac/storage.py +878 -0
- truthound/realtime/__init__.py +141 -0
- truthound/realtime/adapters/__init__.py +43 -0
- truthound/realtime/adapters/base.py +533 -0
- truthound/realtime/adapters/kafka.py +487 -0
- truthound/realtime/adapters/kinesis.py +479 -0
- truthound/realtime/adapters/mock.py +243 -0
- truthound/realtime/base.py +553 -0
- truthound/realtime/factory.py +382 -0
- truthound/realtime/incremental.py +660 -0
- truthound/realtime/processing/__init__.py +67 -0
- truthound/realtime/processing/exactly_once.py +575 -0
- truthound/realtime/processing/state.py +547 -0
- truthound/realtime/processing/windows.py +647 -0
- truthound/realtime/protocols.py +569 -0
- truthound/realtime/streaming.py +605 -0
- truthound/realtime/testing/__init__.py +32 -0
- truthound/realtime/testing/containers.py +615 -0
- truthound/realtime/testing/fixtures.py +484 -0
- truthound/report.py +280 -0
- truthound/reporters/__init__.py +46 -0
- truthound/reporters/_protocols.py +30 -0
- truthound/reporters/base.py +324 -0
- truthound/reporters/ci/__init__.py +66 -0
- truthound/reporters/ci/azure.py +436 -0
- truthound/reporters/ci/base.py +509 -0
- truthound/reporters/ci/bitbucket.py +567 -0
- truthound/reporters/ci/circleci.py +547 -0
- truthound/reporters/ci/detection.py +364 -0
- truthound/reporters/ci/factory.py +182 -0
- truthound/reporters/ci/github.py +388 -0
- truthound/reporters/ci/gitlab.py +471 -0
- truthound/reporters/ci/jenkins.py +525 -0
- truthound/reporters/console_reporter.py +299 -0
- truthound/reporters/factory.py +211 -0
- truthound/reporters/html_reporter.py +524 -0
- truthound/reporters/json_reporter.py +256 -0
- truthound/reporters/markdown_reporter.py +280 -0
- truthound/reporters/sdk/__init__.py +174 -0
- truthound/reporters/sdk/builder.py +558 -0
- truthound/reporters/sdk/mixins.py +1150 -0
- truthound/reporters/sdk/schema.py +1493 -0
- truthound/reporters/sdk/templates.py +666 -0
- truthound/reporters/sdk/testing.py +968 -0
- truthound/scanners.py +170 -0
- truthound/scheduling/__init__.py +122 -0
- truthound/scheduling/cron.py +1136 -0
- truthound/scheduling/presets.py +212 -0
- truthound/schema.py +275 -0
- truthound/secrets/__init__.py +173 -0
- truthound/secrets/base.py +618 -0
- truthound/secrets/cloud.py +682 -0
- truthound/secrets/integration.py +507 -0
- truthound/secrets/manager.py +633 -0
- truthound/secrets/oidc/__init__.py +172 -0
- truthound/secrets/oidc/base.py +902 -0
- truthound/secrets/oidc/credential_provider.py +623 -0
- truthound/secrets/oidc/exchangers.py +1001 -0
- truthound/secrets/oidc/github/__init__.py +110 -0
- truthound/secrets/oidc/github/claims.py +718 -0
- truthound/secrets/oidc/github/enhanced_provider.py +693 -0
- truthound/secrets/oidc/github/trust_policy.py +742 -0
- truthound/secrets/oidc/github/verification.py +723 -0
- truthound/secrets/oidc/github/workflow.py +691 -0
- truthound/secrets/oidc/providers.py +825 -0
- truthound/secrets/providers.py +506 -0
- truthound/secrets/resolver.py +495 -0
- truthound/stores/__init__.py +177 -0
- truthound/stores/backends/__init__.py +18 -0
- truthound/stores/backends/_protocols.py +340 -0
- truthound/stores/backends/azure_blob.py +530 -0
- truthound/stores/backends/concurrent_filesystem.py +915 -0
- truthound/stores/backends/connection_pool.py +1365 -0
- truthound/stores/backends/database.py +743 -0
- truthound/stores/backends/filesystem.py +538 -0
- truthound/stores/backends/gcs.py +399 -0
- truthound/stores/backends/memory.py +354 -0
- truthound/stores/backends/s3.py +434 -0
- truthound/stores/backpressure/__init__.py +84 -0
- truthound/stores/backpressure/base.py +375 -0
- truthound/stores/backpressure/circuit_breaker.py +434 -0
- truthound/stores/backpressure/monitor.py +376 -0
- truthound/stores/backpressure/strategies.py +677 -0
- truthound/stores/base.py +551 -0
- truthound/stores/batching/__init__.py +65 -0
- truthound/stores/batching/base.py +305 -0
- truthound/stores/batching/buffer.py +370 -0
- truthound/stores/batching/store.py +248 -0
- truthound/stores/batching/writer.py +521 -0
- truthound/stores/caching/__init__.py +60 -0
- truthound/stores/caching/backends.py +684 -0
- truthound/stores/caching/base.py +356 -0
- truthound/stores/caching/store.py +305 -0
- truthound/stores/compression/__init__.py +193 -0
- truthound/stores/compression/adaptive.py +694 -0
- truthound/stores/compression/base.py +514 -0
- truthound/stores/compression/pipeline.py +868 -0
- truthound/stores/compression/providers.py +672 -0
- truthound/stores/compression/streaming.py +832 -0
- truthound/stores/concurrency/__init__.py +81 -0
- truthound/stores/concurrency/atomic.py +556 -0
- truthound/stores/concurrency/index.py +775 -0
- truthound/stores/concurrency/locks.py +576 -0
- truthound/stores/concurrency/manager.py +482 -0
- truthound/stores/encryption/__init__.py +297 -0
- truthound/stores/encryption/base.py +952 -0
- truthound/stores/encryption/keys.py +1191 -0
- truthound/stores/encryption/pipeline.py +903 -0
- truthound/stores/encryption/providers.py +953 -0
- truthound/stores/encryption/streaming.py +950 -0
- truthound/stores/expectations.py +227 -0
- truthound/stores/factory.py +246 -0
- truthound/stores/migration/__init__.py +75 -0
- truthound/stores/migration/base.py +480 -0
- truthound/stores/migration/manager.py +347 -0
- truthound/stores/migration/registry.py +382 -0
- truthound/stores/migration/store.py +559 -0
- truthound/stores/observability/__init__.py +106 -0
- truthound/stores/observability/audit.py +718 -0
- truthound/stores/observability/config.py +270 -0
- truthound/stores/observability/factory.py +208 -0
- truthound/stores/observability/metrics.py +636 -0
- truthound/stores/observability/protocols.py +410 -0
- truthound/stores/observability/store.py +570 -0
- truthound/stores/observability/tracing.py +784 -0
- truthound/stores/replication/__init__.py +76 -0
- truthound/stores/replication/base.py +260 -0
- truthound/stores/replication/monitor.py +269 -0
- truthound/stores/replication/store.py +439 -0
- truthound/stores/replication/syncer.py +391 -0
- truthound/stores/results.py +359 -0
- truthound/stores/retention/__init__.py +77 -0
- truthound/stores/retention/base.py +378 -0
- truthound/stores/retention/policies.py +621 -0
- truthound/stores/retention/scheduler.py +279 -0
- truthound/stores/retention/store.py +526 -0
- truthound/stores/streaming/__init__.py +138 -0
- truthound/stores/streaming/base.py +801 -0
- truthound/stores/streaming/database.py +984 -0
- truthound/stores/streaming/filesystem.py +719 -0
- truthound/stores/streaming/reader.py +629 -0
- truthound/stores/streaming/s3.py +843 -0
- truthound/stores/streaming/writer.py +790 -0
- truthound/stores/tiering/__init__.py +108 -0
- truthound/stores/tiering/base.py +462 -0
- truthound/stores/tiering/manager.py +249 -0
- truthound/stores/tiering/policies.py +692 -0
- truthound/stores/tiering/store.py +526 -0
- truthound/stores/versioning/__init__.py +56 -0
- truthound/stores/versioning/base.py +376 -0
- truthound/stores/versioning/store.py +660 -0
- truthound/stores/versioning/strategies.py +353 -0
- truthound/types.py +56 -0
- truthound/validators/__init__.py +774 -0
- truthound/validators/aggregate/__init__.py +27 -0
- truthound/validators/aggregate/central.py +116 -0
- truthound/validators/aggregate/extremes.py +116 -0
- truthound/validators/aggregate/spread.py +118 -0
- truthound/validators/aggregate/sum.py +64 -0
- truthound/validators/aggregate/type.py +78 -0
- truthound/validators/anomaly/__init__.py +93 -0
- truthound/validators/anomaly/base.py +431 -0
- truthound/validators/anomaly/ml_based.py +1190 -0
- truthound/validators/anomaly/multivariate.py +647 -0
- truthound/validators/anomaly/statistical.py +599 -0
- truthound/validators/base.py +1089 -0
- truthound/validators/business_rule/__init__.py +46 -0
- truthound/validators/business_rule/base.py +147 -0
- truthound/validators/business_rule/checksum.py +509 -0
- truthound/validators/business_rule/financial.py +526 -0
- truthound/validators/cache.py +733 -0
- truthound/validators/completeness/__init__.py +39 -0
- truthound/validators/completeness/conditional.py +73 -0
- truthound/validators/completeness/default.py +98 -0
- truthound/validators/completeness/empty.py +103 -0
- truthound/validators/completeness/nan.py +337 -0
- truthound/validators/completeness/null.py +152 -0
- truthound/validators/cross_table/__init__.py +17 -0
- truthound/validators/cross_table/aggregate.py +333 -0
- truthound/validators/cross_table/row_count.py +122 -0
- truthound/validators/datetime/__init__.py +29 -0
- truthound/validators/datetime/format.py +78 -0
- truthound/validators/datetime/freshness.py +269 -0
- truthound/validators/datetime/order.py +73 -0
- truthound/validators/datetime/parseable.py +185 -0
- truthound/validators/datetime/range.py +202 -0
- truthound/validators/datetime/timezone.py +69 -0
- truthound/validators/distribution/__init__.py +49 -0
- truthound/validators/distribution/distribution.py +128 -0
- truthound/validators/distribution/monotonic.py +119 -0
- truthound/validators/distribution/outlier.py +178 -0
- truthound/validators/distribution/quantile.py +80 -0
- truthound/validators/distribution/range.py +254 -0
- truthound/validators/distribution/set.py +125 -0
- truthound/validators/distribution/statistical.py +459 -0
- truthound/validators/drift/__init__.py +79 -0
- truthound/validators/drift/base.py +427 -0
- truthound/validators/drift/multi_feature.py +401 -0
- truthound/validators/drift/numeric.py +395 -0
- truthound/validators/drift/psi.py +446 -0
- truthound/validators/drift/statistical.py +510 -0
- truthound/validators/enterprise.py +1658 -0
- truthound/validators/geospatial/__init__.py +80 -0
- truthound/validators/geospatial/base.py +97 -0
- truthound/validators/geospatial/boundary.py +238 -0
- truthound/validators/geospatial/coordinate.py +351 -0
- truthound/validators/geospatial/distance.py +399 -0
- truthound/validators/geospatial/polygon.py +665 -0
- truthound/validators/i18n/__init__.py +308 -0
- truthound/validators/i18n/bidi.py +571 -0
- truthound/validators/i18n/catalogs.py +570 -0
- truthound/validators/i18n/dialects.py +763 -0
- truthound/validators/i18n/extended_catalogs.py +549 -0
- truthound/validators/i18n/formatting.py +1434 -0
- truthound/validators/i18n/loader.py +1020 -0
- truthound/validators/i18n/messages.py +521 -0
- truthound/validators/i18n/plural.py +683 -0
- truthound/validators/i18n/protocols.py +855 -0
- truthound/validators/i18n/tms.py +1162 -0
- truthound/validators/localization/__init__.py +53 -0
- truthound/validators/localization/base.py +122 -0
- truthound/validators/localization/chinese.py +362 -0
- truthound/validators/localization/japanese.py +275 -0
- truthound/validators/localization/korean.py +524 -0
- truthound/validators/memory/__init__.py +94 -0
- truthound/validators/memory/approximate_knn.py +506 -0
- truthound/validators/memory/base.py +547 -0
- truthound/validators/memory/sgd_online.py +719 -0
- truthound/validators/memory/streaming_ecdf.py +753 -0
- truthound/validators/ml_feature/__init__.py +54 -0
- truthound/validators/ml_feature/base.py +249 -0
- truthound/validators/ml_feature/correlation.py +299 -0
- truthound/validators/ml_feature/leakage.py +344 -0
- truthound/validators/ml_feature/null_impact.py +270 -0
- truthound/validators/ml_feature/scale.py +264 -0
- truthound/validators/multi_column/__init__.py +89 -0
- truthound/validators/multi_column/arithmetic.py +284 -0
- truthound/validators/multi_column/base.py +231 -0
- truthound/validators/multi_column/comparison.py +273 -0
- truthound/validators/multi_column/consistency.py +312 -0
- truthound/validators/multi_column/statistical.py +299 -0
- truthound/validators/optimization/__init__.py +164 -0
- truthound/validators/optimization/aggregation.py +563 -0
- truthound/validators/optimization/covariance.py +556 -0
- truthound/validators/optimization/geo.py +626 -0
- truthound/validators/optimization/graph.py +587 -0
- truthound/validators/optimization/orchestrator.py +970 -0
- truthound/validators/optimization/profiling.py +1312 -0
- truthound/validators/privacy/__init__.py +223 -0
- truthound/validators/privacy/base.py +635 -0
- truthound/validators/privacy/ccpa.py +670 -0
- truthound/validators/privacy/gdpr.py +728 -0
- truthound/validators/privacy/global_patterns.py +604 -0
- truthound/validators/privacy/plugins.py +867 -0
- truthound/validators/profiling/__init__.py +52 -0
- truthound/validators/profiling/base.py +175 -0
- truthound/validators/profiling/cardinality.py +312 -0
- truthound/validators/profiling/entropy.py +391 -0
- truthound/validators/profiling/frequency.py +455 -0
- truthound/validators/pushdown_support.py +660 -0
- truthound/validators/query/__init__.py +91 -0
- truthound/validators/query/aggregate.py +346 -0
- truthound/validators/query/base.py +246 -0
- truthound/validators/query/column.py +249 -0
- truthound/validators/query/expression.py +274 -0
- truthound/validators/query/result.py +323 -0
- truthound/validators/query/row_count.py +264 -0
- truthound/validators/referential/__init__.py +80 -0
- truthound/validators/referential/base.py +395 -0
- truthound/validators/referential/cascade.py +391 -0
- truthound/validators/referential/circular.py +563 -0
- truthound/validators/referential/foreign_key.py +624 -0
- truthound/validators/referential/orphan.py +485 -0
- truthound/validators/registry.py +112 -0
- truthound/validators/schema/__init__.py +41 -0
- truthound/validators/schema/column_count.py +142 -0
- truthound/validators/schema/column_exists.py +80 -0
- truthound/validators/schema/column_order.py +82 -0
- truthound/validators/schema/column_pair.py +85 -0
- truthound/validators/schema/column_pair_set.py +195 -0
- truthound/validators/schema/column_type.py +94 -0
- truthound/validators/schema/multi_column.py +53 -0
- truthound/validators/schema/multi_column_aggregate.py +175 -0
- truthound/validators/schema/referential.py +274 -0
- truthound/validators/schema/table_schema.py +91 -0
- truthound/validators/schema_validator.py +219 -0
- truthound/validators/sdk/__init__.py +250 -0
- truthound/validators/sdk/builder.py +680 -0
- truthound/validators/sdk/decorators.py +474 -0
- truthound/validators/sdk/enterprise/__init__.py +211 -0
- truthound/validators/sdk/enterprise/docs.py +725 -0
- truthound/validators/sdk/enterprise/fuzzing.py +659 -0
- truthound/validators/sdk/enterprise/licensing.py +709 -0
- truthound/validators/sdk/enterprise/manager.py +543 -0
- truthound/validators/sdk/enterprise/resources.py +628 -0
- truthound/validators/sdk/enterprise/sandbox.py +766 -0
- truthound/validators/sdk/enterprise/signing.py +603 -0
- truthound/validators/sdk/enterprise/templates.py +865 -0
- truthound/validators/sdk/enterprise/versioning.py +659 -0
- truthound/validators/sdk/templates.py +757 -0
- truthound/validators/sdk/testing.py +807 -0
- truthound/validators/security/__init__.py +181 -0
- truthound/validators/security/redos/__init__.py +182 -0
- truthound/validators/security/redos/core.py +861 -0
- truthound/validators/security/redos/cpu_monitor.py +593 -0
- truthound/validators/security/redos/cve_database.py +791 -0
- truthound/validators/security/redos/ml/__init__.py +155 -0
- truthound/validators/security/redos/ml/base.py +785 -0
- truthound/validators/security/redos/ml/datasets.py +618 -0
- truthound/validators/security/redos/ml/features.py +359 -0
- truthound/validators/security/redos/ml/models.py +1000 -0
- truthound/validators/security/redos/ml/predictor.py +507 -0
- truthound/validators/security/redos/ml/storage.py +632 -0
- truthound/validators/security/redos/ml/training.py +571 -0
- truthound/validators/security/redos/ml_analyzer.py +937 -0
- truthound/validators/security/redos/optimizer.py +674 -0
- truthound/validators/security/redos/profiler.py +682 -0
- truthound/validators/security/redos/re2_engine.py +709 -0
- truthound/validators/security/redos.py +886 -0
- truthound/validators/security/sql_security.py +1247 -0
- truthound/validators/streaming/__init__.py +126 -0
- truthound/validators/streaming/base.py +292 -0
- truthound/validators/streaming/completeness.py +210 -0
- truthound/validators/streaming/mixin.py +575 -0
- truthound/validators/streaming/range.py +308 -0
- truthound/validators/streaming/sources.py +846 -0
- truthound/validators/string/__init__.py +57 -0
- truthound/validators/string/casing.py +158 -0
- truthound/validators/string/charset.py +96 -0
- truthound/validators/string/format.py +501 -0
- truthound/validators/string/json.py +77 -0
- truthound/validators/string/json_schema.py +184 -0
- truthound/validators/string/length.py +104 -0
- truthound/validators/string/like_pattern.py +237 -0
- truthound/validators/string/regex.py +202 -0
- truthound/validators/string/regex_extended.py +435 -0
- truthound/validators/table/__init__.py +88 -0
- truthound/validators/table/base.py +78 -0
- truthound/validators/table/column_count.py +198 -0
- truthound/validators/table/freshness.py +362 -0
- truthound/validators/table/row_count.py +251 -0
- truthound/validators/table/schema.py +333 -0
- truthound/validators/table/size.py +285 -0
- truthound/validators/timeout/__init__.py +102 -0
- truthound/validators/timeout/advanced/__init__.py +247 -0
- truthound/validators/timeout/advanced/circuit_breaker.py +675 -0
- truthound/validators/timeout/advanced/prediction.py +773 -0
- truthound/validators/timeout/advanced/priority.py +618 -0
- truthound/validators/timeout/advanced/redis_backend.py +770 -0
- truthound/validators/timeout/advanced/retry.py +721 -0
- truthound/validators/timeout/advanced/sampling.py +788 -0
- truthound/validators/timeout/advanced/sla.py +661 -0
- truthound/validators/timeout/advanced/telemetry.py +804 -0
- truthound/validators/timeout/cascade.py +477 -0
- truthound/validators/timeout/deadline.py +657 -0
- truthound/validators/timeout/degradation.py +525 -0
- truthound/validators/timeout/distributed.py +597 -0
- truthound/validators/timeseries/__init__.py +89 -0
- truthound/validators/timeseries/base.py +326 -0
- truthound/validators/timeseries/completeness.py +617 -0
- truthound/validators/timeseries/gap.py +485 -0
- truthound/validators/timeseries/monotonic.py +310 -0
- truthound/validators/timeseries/seasonality.py +422 -0
- truthound/validators/timeseries/trend.py +510 -0
- truthound/validators/uniqueness/__init__.py +59 -0
- truthound/validators/uniqueness/approximate.py +475 -0
- truthound/validators/uniqueness/distinct_values.py +253 -0
- truthound/validators/uniqueness/duplicate.py +118 -0
- truthound/validators/uniqueness/primary_key.py +140 -0
- truthound/validators/uniqueness/unique.py +191 -0
- truthound/validators/uniqueness/within_record.py +599 -0
- truthound/validators/utils.py +756 -0
- truthound-1.0.8.dist-info/METADATA +474 -0
- truthound-1.0.8.dist-info/RECORD +877 -0
- truthound-1.0.8.dist-info/WHEEL +4 -0
- truthound-1.0.8.dist-info/entry_points.txt +2 -0
- truthound-1.0.8.dist-info/licenses/LICENSE +190 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"""Base classes and configuration for batch writing.
|
|
2
|
+
|
|
3
|
+
This module defines the data structures and configurations used
|
|
4
|
+
for batch write operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import Any, Generic, TypeVar
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BatchStatus(str, Enum):
|
|
17
|
+
"""Status of a batch operation."""
|
|
18
|
+
|
|
19
|
+
PENDING = "pending" # Batch not yet started
|
|
20
|
+
BUFFERING = "buffering" # Collecting items
|
|
21
|
+
FLUSHING = "flushing" # Writing to storage
|
|
22
|
+
COMPLETED = "completed" # Successfully written
|
|
23
|
+
FAILED = "failed" # Write failed
|
|
24
|
+
RETRYING = "retrying" # Retrying after failure
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class BatchConfig:
|
|
29
|
+
"""Configuration for batch writing.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
batch_size: Number of items per batch.
|
|
33
|
+
flush_interval_seconds: Auto-flush interval.
|
|
34
|
+
max_buffer_memory_mb: Maximum memory for buffer.
|
|
35
|
+
max_pending_batches: Maximum batches waiting to be written.
|
|
36
|
+
parallelism: Number of parallel write operations.
|
|
37
|
+
compression_enabled: Enable compression for batched data.
|
|
38
|
+
compression_level: Compression level (1-9).
|
|
39
|
+
retry_enabled: Enable automatic retry on failure.
|
|
40
|
+
max_retries: Maximum retry attempts.
|
|
41
|
+
retry_delay_seconds: Initial retry delay.
|
|
42
|
+
retry_backoff_multiplier: Delay multiplier for exponential backoff.
|
|
43
|
+
preserve_order: Preserve insertion order in batches.
|
|
44
|
+
enable_metrics: Collect batch metrics.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
batch_size: int = 1000
|
|
48
|
+
flush_interval_seconds: float = 5.0
|
|
49
|
+
max_buffer_memory_mb: int = 100
|
|
50
|
+
max_pending_batches: int = 10
|
|
51
|
+
parallelism: int = 4
|
|
52
|
+
compression_enabled: bool = True
|
|
53
|
+
compression_level: int = 6
|
|
54
|
+
retry_enabled: bool = True
|
|
55
|
+
max_retries: int = 3
|
|
56
|
+
retry_delay_seconds: float = 1.0
|
|
57
|
+
retry_backoff_multiplier: float = 2.0
|
|
58
|
+
preserve_order: bool = True
|
|
59
|
+
enable_metrics: bool = True
|
|
60
|
+
|
|
61
|
+
def validate(self) -> None:
|
|
62
|
+
"""Validate configuration values."""
|
|
63
|
+
if self.batch_size <= 0:
|
|
64
|
+
raise ValueError("batch_size must be positive")
|
|
65
|
+
if self.flush_interval_seconds < 0:
|
|
66
|
+
raise ValueError("flush_interval_seconds must be non-negative")
|
|
67
|
+
if self.max_buffer_memory_mb <= 0:
|
|
68
|
+
raise ValueError("max_buffer_memory_mb must be positive")
|
|
69
|
+
if self.max_pending_batches <= 0:
|
|
70
|
+
raise ValueError("max_pending_batches must be positive")
|
|
71
|
+
if self.parallelism <= 0:
|
|
72
|
+
raise ValueError("parallelism must be positive")
|
|
73
|
+
if not 1 <= self.compression_level <= 9:
|
|
74
|
+
raise ValueError("compression_level must be between 1 and 9")
|
|
75
|
+
if self.max_retries < 0:
|
|
76
|
+
raise ValueError("max_retries must be non-negative")
|
|
77
|
+
if self.retry_delay_seconds < 0:
|
|
78
|
+
raise ValueError("retry_delay_seconds must be non-negative")
|
|
79
|
+
if self.retry_backoff_multiplier < 1:
|
|
80
|
+
raise ValueError("retry_backoff_multiplier must be >= 1")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass
|
|
84
|
+
class BatchMetrics:
|
|
85
|
+
"""Metrics for batch write operations.
|
|
86
|
+
|
|
87
|
+
Attributes:
|
|
88
|
+
total_items: Total items added to batches.
|
|
89
|
+
batches_created: Number of batches created.
|
|
90
|
+
batches_written: Number of batches successfully written.
|
|
91
|
+
batches_failed: Number of batches that failed.
|
|
92
|
+
items_written: Total items successfully written.
|
|
93
|
+
items_failed: Total items that failed to write.
|
|
94
|
+
bytes_written: Total bytes written.
|
|
95
|
+
bytes_compressed: Total bytes after compression.
|
|
96
|
+
flush_count: Number of flush operations.
|
|
97
|
+
retry_count: Number of retry attempts.
|
|
98
|
+
total_write_time_ms: Total time spent writing.
|
|
99
|
+
average_batch_size: Average items per batch.
|
|
100
|
+
average_write_time_ms: Average time per batch write.
|
|
101
|
+
peak_buffer_size: Peak buffer size in items.
|
|
102
|
+
peak_memory_usage_mb: Peak memory usage.
|
|
103
|
+
start_time: When batch operations started.
|
|
104
|
+
last_flush_time: Last flush time.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
total_items: int = 0
|
|
108
|
+
batches_created: int = 0
|
|
109
|
+
batches_written: int = 0
|
|
110
|
+
batches_failed: int = 0
|
|
111
|
+
items_written: int = 0
|
|
112
|
+
items_failed: int = 0
|
|
113
|
+
bytes_written: int = 0
|
|
114
|
+
bytes_compressed: int = 0
|
|
115
|
+
flush_count: int = 0
|
|
116
|
+
retry_count: int = 0
|
|
117
|
+
total_write_time_ms: float = 0.0
|
|
118
|
+
average_batch_size: float = 0.0
|
|
119
|
+
average_write_time_ms: float = 0.0
|
|
120
|
+
peak_buffer_size: int = 0
|
|
121
|
+
peak_memory_usage_mb: float = 0.0
|
|
122
|
+
start_time: datetime = field(default_factory=datetime.now)
|
|
123
|
+
last_flush_time: datetime | None = None
|
|
124
|
+
|
|
125
|
+
def record_item_added(self, buffer_size: int) -> None:
|
|
126
|
+
"""Record an item added to buffer."""
|
|
127
|
+
self.total_items += 1
|
|
128
|
+
if buffer_size > self.peak_buffer_size:
|
|
129
|
+
self.peak_buffer_size = buffer_size
|
|
130
|
+
|
|
131
|
+
def record_batch_created(self, size: int) -> None:
|
|
132
|
+
"""Record a batch created."""
|
|
133
|
+
self.batches_created += 1
|
|
134
|
+
|
|
135
|
+
def record_batch_written(self, size: int, bytes_written: int, time_ms: float) -> None:
|
|
136
|
+
"""Record a successful batch write."""
|
|
137
|
+
self.batches_written += 1
|
|
138
|
+
self.items_written += size
|
|
139
|
+
self.bytes_written += bytes_written
|
|
140
|
+
self.total_write_time_ms += time_ms
|
|
141
|
+
self._update_averages()
|
|
142
|
+
|
|
143
|
+
def record_batch_failed(self, size: int) -> None:
|
|
144
|
+
"""Record a failed batch."""
|
|
145
|
+
self.batches_failed += 1
|
|
146
|
+
self.items_failed += size
|
|
147
|
+
|
|
148
|
+
def record_retry(self) -> None:
|
|
149
|
+
"""Record a retry attempt."""
|
|
150
|
+
self.retry_count += 1
|
|
151
|
+
|
|
152
|
+
def record_flush(self) -> None:
|
|
153
|
+
"""Record a flush operation."""
|
|
154
|
+
self.flush_count += 1
|
|
155
|
+
self.last_flush_time = datetime.now()
|
|
156
|
+
|
|
157
|
+
def record_compression(self, original_size: int, compressed_size: int) -> None:
|
|
158
|
+
"""Record compression metrics."""
|
|
159
|
+
self.bytes_compressed += compressed_size
|
|
160
|
+
|
|
161
|
+
def record_memory_usage(self, usage_mb: float) -> None:
|
|
162
|
+
"""Record memory usage."""
|
|
163
|
+
if usage_mb > self.peak_memory_usage_mb:
|
|
164
|
+
self.peak_memory_usage_mb = usage_mb
|
|
165
|
+
|
|
166
|
+
def _update_averages(self) -> None:
|
|
167
|
+
"""Update average metrics."""
|
|
168
|
+
if self.batches_written > 0:
|
|
169
|
+
self.average_batch_size = self.items_written / self.batches_written
|
|
170
|
+
self.average_write_time_ms = self.total_write_time_ms / self.batches_written
|
|
171
|
+
|
|
172
|
+
def get_compression_ratio(self) -> float:
|
|
173
|
+
"""Get compression ratio (0-1, lower is better compression)."""
|
|
174
|
+
if self.bytes_written == 0:
|
|
175
|
+
return 1.0
|
|
176
|
+
return self.bytes_compressed / self.bytes_written
|
|
177
|
+
|
|
178
|
+
def get_throughput(self) -> float:
|
|
179
|
+
"""Get items per second throughput."""
|
|
180
|
+
if self.total_write_time_ms == 0:
|
|
181
|
+
return 0.0
|
|
182
|
+
return (self.items_written / self.total_write_time_ms) * 1000
|
|
183
|
+
|
|
184
|
+
def to_dict(self) -> dict[str, Any]:
|
|
185
|
+
"""Convert to dictionary."""
|
|
186
|
+
return {
|
|
187
|
+
"total_items": self.total_items,
|
|
188
|
+
"batches_created": self.batches_created,
|
|
189
|
+
"batches_written": self.batches_written,
|
|
190
|
+
"batches_failed": self.batches_failed,
|
|
191
|
+
"items_written": self.items_written,
|
|
192
|
+
"items_failed": self.items_failed,
|
|
193
|
+
"bytes_written": self.bytes_written,
|
|
194
|
+
"bytes_compressed": self.bytes_compressed,
|
|
195
|
+
"flush_count": self.flush_count,
|
|
196
|
+
"retry_count": self.retry_count,
|
|
197
|
+
"total_write_time_ms": self.total_write_time_ms,
|
|
198
|
+
"average_batch_size": self.average_batch_size,
|
|
199
|
+
"average_write_time_ms": self.average_write_time_ms,
|
|
200
|
+
"peak_buffer_size": self.peak_buffer_size,
|
|
201
|
+
"peak_memory_usage_mb": self.peak_memory_usage_mb,
|
|
202
|
+
"compression_ratio": self.get_compression_ratio(),
|
|
203
|
+
"throughput_items_per_sec": self.get_throughput(),
|
|
204
|
+
"start_time": self.start_time.isoformat(),
|
|
205
|
+
"last_flush_time": (
|
|
206
|
+
self.last_flush_time.isoformat() if self.last_flush_time else None
|
|
207
|
+
),
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
T = TypeVar("T")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@dataclass
|
|
215
|
+
class Batch(Generic[T]):
|
|
216
|
+
"""A batch of items to be written.
|
|
217
|
+
|
|
218
|
+
Attributes:
|
|
219
|
+
batch_id: Unique identifier for the batch.
|
|
220
|
+
items: Items in the batch.
|
|
221
|
+
status: Current batch status.
|
|
222
|
+
created_at: When the batch was created.
|
|
223
|
+
size_bytes: Estimated size in bytes.
|
|
224
|
+
retry_count: Number of retry attempts.
|
|
225
|
+
error: Last error if failed.
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
batch_id: str
|
|
229
|
+
items: list[T]
|
|
230
|
+
status: BatchStatus = BatchStatus.PENDING
|
|
231
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
232
|
+
size_bytes: int = 0
|
|
233
|
+
retry_count: int = 0
|
|
234
|
+
error: str | None = None
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def size(self) -> int:
|
|
238
|
+
"""Get number of items in batch."""
|
|
239
|
+
return len(self.items)
|
|
240
|
+
|
|
241
|
+
def mark_flushing(self) -> None:
|
|
242
|
+
"""Mark batch as flushing."""
|
|
243
|
+
self.status = BatchStatus.FLUSHING
|
|
244
|
+
|
|
245
|
+
def mark_completed(self) -> None:
|
|
246
|
+
"""Mark batch as completed."""
|
|
247
|
+
self.status = BatchStatus.COMPLETED
|
|
248
|
+
|
|
249
|
+
def mark_failed(self, error: str) -> None:
|
|
250
|
+
"""Mark batch as failed."""
|
|
251
|
+
self.status = BatchStatus.FAILED
|
|
252
|
+
self.error = error
|
|
253
|
+
|
|
254
|
+
def mark_retrying(self) -> None:
|
|
255
|
+
"""Mark batch for retry."""
|
|
256
|
+
self.status = BatchStatus.RETRYING
|
|
257
|
+
self.retry_count += 1
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
@dataclass
|
|
261
|
+
class BatchState:
|
|
262
|
+
"""Current state of batch operations.
|
|
263
|
+
|
|
264
|
+
Attributes:
|
|
265
|
+
is_active: Whether batch writing is active.
|
|
266
|
+
pending_batches: Number of batches pending write.
|
|
267
|
+
current_buffer_size: Current items in buffer.
|
|
268
|
+
last_flush: Last flush timestamp.
|
|
269
|
+
is_flushing: Whether currently flushing.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
is_active: bool = False
|
|
273
|
+
pending_batches: int = 0
|
|
274
|
+
current_buffer_size: int = 0
|
|
275
|
+
last_flush: datetime | None = None
|
|
276
|
+
is_flushing: bool = False
|
|
277
|
+
|
|
278
|
+
def start(self) -> None:
|
|
279
|
+
"""Mark as started."""
|
|
280
|
+
self.is_active = True
|
|
281
|
+
|
|
282
|
+
def stop(self) -> None:
|
|
283
|
+
"""Mark as stopped."""
|
|
284
|
+
self.is_active = False
|
|
285
|
+
|
|
286
|
+
def begin_flush(self) -> None:
|
|
287
|
+
"""Mark flush as started."""
|
|
288
|
+
self.is_flushing = True
|
|
289
|
+
|
|
290
|
+
def end_flush(self) -> None:
|
|
291
|
+
"""Mark flush as completed."""
|
|
292
|
+
self.is_flushing = False
|
|
293
|
+
self.last_flush = datetime.now()
|
|
294
|
+
|
|
295
|
+
def add_pending(self) -> None:
|
|
296
|
+
"""Increment pending batches."""
|
|
297
|
+
self.pending_batches += 1
|
|
298
|
+
|
|
299
|
+
def remove_pending(self) -> None:
|
|
300
|
+
"""Decrement pending batches."""
|
|
301
|
+
self.pending_batches = max(0, self.pending_batches - 1)
|
|
302
|
+
|
|
303
|
+
def update_buffer_size(self, size: int) -> None:
|
|
304
|
+
"""Update current buffer size."""
|
|
305
|
+
self.current_buffer_size = size
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"""Buffer implementations for batch writing.
|
|
2
|
+
|
|
3
|
+
This module provides buffer implementations for collecting items
|
|
4
|
+
before batching, with support for memory management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import threading
|
|
11
|
+
from collections import deque
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from typing import Any, Generic, Iterator, TypeVar
|
|
14
|
+
|
|
15
|
+
T = TypeVar("T")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class BufferConfig:
|
|
20
|
+
"""Configuration for buffer.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
max_size: Maximum number of items.
|
|
24
|
+
max_memory_mb: Maximum memory usage in MB.
|
|
25
|
+
enable_memory_tracking: Track memory usage.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
max_size: int = 10000
|
|
29
|
+
max_memory_mb: float = 100.0
|
|
30
|
+
enable_memory_tracking: bool = True
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class BatchBuffer(Generic[T]):
|
|
34
|
+
"""Thread-safe buffer for collecting items before batching.
|
|
35
|
+
|
|
36
|
+
Provides a simple FIFO buffer with configurable size limits.
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> buffer = BatchBuffer[dict](max_size=1000)
|
|
40
|
+
>>> buffer.add({"key": "value"})
|
|
41
|
+
>>> batch = buffer.drain(100)
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, max_size: int = 10000) -> None:
|
|
45
|
+
"""Initialize buffer.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
max_size: Maximum number of items in buffer.
|
|
49
|
+
"""
|
|
50
|
+
self._max_size = max_size
|
|
51
|
+
self._items: deque[T] = deque()
|
|
52
|
+
self._lock = threading.Lock()
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def size(self) -> int:
|
|
56
|
+
"""Get current number of items."""
|
|
57
|
+
with self._lock:
|
|
58
|
+
return len(self._items)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def is_empty(self) -> bool:
|
|
62
|
+
"""Check if buffer is empty."""
|
|
63
|
+
return self.size == 0
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def is_full(self) -> bool:
|
|
67
|
+
"""Check if buffer is at capacity."""
|
|
68
|
+
return self.size >= self._max_size
|
|
69
|
+
|
|
70
|
+
def add(self, item: T) -> bool:
|
|
71
|
+
"""Add an item to the buffer.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
item: Item to add.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
True if added, False if buffer full.
|
|
78
|
+
"""
|
|
79
|
+
with self._lock:
|
|
80
|
+
if len(self._items) >= self._max_size:
|
|
81
|
+
return False
|
|
82
|
+
self._items.append(item)
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
def add_many(self, items: list[T]) -> int:
|
|
86
|
+
"""Add multiple items to the buffer.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
items: Items to add.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Number of items actually added.
|
|
93
|
+
"""
|
|
94
|
+
with self._lock:
|
|
95
|
+
space_available = self._max_size - len(self._items)
|
|
96
|
+
items_to_add = items[:space_available]
|
|
97
|
+
self._items.extend(items_to_add)
|
|
98
|
+
return len(items_to_add)
|
|
99
|
+
|
|
100
|
+
def drain(self, count: int) -> list[T]:
|
|
101
|
+
"""Remove and return items from buffer.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
count: Maximum number of items to drain.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
List of drained items.
|
|
108
|
+
"""
|
|
109
|
+
with self._lock:
|
|
110
|
+
result = []
|
|
111
|
+
for _ in range(min(count, len(self._items))):
|
|
112
|
+
result.append(self._items.popleft())
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
def drain_all(self) -> list[T]:
|
|
116
|
+
"""Remove and return all items from buffer."""
|
|
117
|
+
with self._lock:
|
|
118
|
+
items = list(self._items)
|
|
119
|
+
self._items.clear()
|
|
120
|
+
return items
|
|
121
|
+
|
|
122
|
+
def peek(self, count: int) -> list[T]:
|
|
123
|
+
"""View items without removing.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
count: Number of items to peek.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
List of items (copies).
|
|
130
|
+
"""
|
|
131
|
+
with self._lock:
|
|
132
|
+
return list(self._items)[:count]
|
|
133
|
+
|
|
134
|
+
def clear(self) -> int:
|
|
135
|
+
"""Clear all items from buffer.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Number of items cleared.
|
|
139
|
+
"""
|
|
140
|
+
with self._lock:
|
|
141
|
+
count = len(self._items)
|
|
142
|
+
self._items.clear()
|
|
143
|
+
return count
|
|
144
|
+
|
|
145
|
+
def __len__(self) -> int:
|
|
146
|
+
"""Get number of items."""
|
|
147
|
+
return self.size
|
|
148
|
+
|
|
149
|
+
def __iter__(self) -> Iterator[T]:
|
|
150
|
+
"""Iterate over items (drains buffer)."""
|
|
151
|
+
while not self.is_empty:
|
|
152
|
+
items = self.drain(100)
|
|
153
|
+
yield from items
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class MemoryAwareBuffer(Generic[T]):
|
|
157
|
+
"""Buffer with memory usage tracking and limits.
|
|
158
|
+
|
|
159
|
+
Tracks approximate memory usage of items and enforces
|
|
160
|
+
memory limits in addition to count limits.
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
>>> buffer = MemoryAwareBuffer[dict](max_size=10000, max_memory_mb=50.0)
|
|
164
|
+
>>> buffer.add({"key": "value"})
|
|
165
|
+
>>> print(f"Memory usage: {buffer.memory_usage_mb:.2f} MB")
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def __init__(
|
|
169
|
+
self,
|
|
170
|
+
max_size: int = 10000,
|
|
171
|
+
max_memory_mb: float = 100.0,
|
|
172
|
+
size_estimator: callable | None = None,
|
|
173
|
+
) -> None:
|
|
174
|
+
"""Initialize memory-aware buffer.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
max_size: Maximum number of items.
|
|
178
|
+
max_memory_mb: Maximum memory usage in MB.
|
|
179
|
+
size_estimator: Optional function to estimate item size.
|
|
180
|
+
"""
|
|
181
|
+
self._max_size = max_size
|
|
182
|
+
self._max_memory_bytes = int(max_memory_mb * 1024 * 1024)
|
|
183
|
+
self._size_estimator = size_estimator or self._default_size_estimator
|
|
184
|
+
self._items: deque[tuple[T, int]] = deque() # (item, size_bytes)
|
|
185
|
+
self._current_memory_bytes = 0
|
|
186
|
+
self._lock = threading.Lock()
|
|
187
|
+
|
|
188
|
+
@staticmethod
|
|
189
|
+
def _default_size_estimator(item: Any) -> int:
|
|
190
|
+
"""Estimate size of an item in bytes."""
|
|
191
|
+
return sys.getsizeof(item)
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def size(self) -> int:
|
|
195
|
+
"""Get current number of items."""
|
|
196
|
+
with self._lock:
|
|
197
|
+
return len(self._items)
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def memory_usage_bytes(self) -> int:
|
|
201
|
+
"""Get current memory usage in bytes."""
|
|
202
|
+
with self._lock:
|
|
203
|
+
return self._current_memory_bytes
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def memory_usage_mb(self) -> float:
|
|
207
|
+
"""Get current memory usage in MB."""
|
|
208
|
+
return self.memory_usage_bytes / (1024 * 1024)
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def is_empty(self) -> bool:
|
|
212
|
+
"""Check if buffer is empty."""
|
|
213
|
+
return self.size == 0
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def is_full(self) -> bool:
|
|
217
|
+
"""Check if buffer is at capacity."""
|
|
218
|
+
with self._lock:
|
|
219
|
+
return (
|
|
220
|
+
len(self._items) >= self._max_size
|
|
221
|
+
or self._current_memory_bytes >= self._max_memory_bytes
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def memory_pressure(self) -> float:
|
|
226
|
+
"""Get memory pressure as percentage (0-100)."""
|
|
227
|
+
with self._lock:
|
|
228
|
+
return (self._current_memory_bytes / self._max_memory_bytes) * 100
|
|
229
|
+
|
|
230
|
+
def can_add(self, item: T) -> bool:
|
|
231
|
+
"""Check if an item can be added without exceeding limits."""
|
|
232
|
+
if self.is_full:
|
|
233
|
+
return False
|
|
234
|
+
|
|
235
|
+
size = self._size_estimator(item)
|
|
236
|
+
with self._lock:
|
|
237
|
+
return (
|
|
238
|
+
self._current_memory_bytes + size <= self._max_memory_bytes
|
|
239
|
+
and len(self._items) < self._max_size
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
def add(self, item: T) -> bool:
|
|
243
|
+
"""Add an item to the buffer.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
item: Item to add.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
True if added, False if would exceed limits.
|
|
250
|
+
"""
|
|
251
|
+
size = self._size_estimator(item)
|
|
252
|
+
|
|
253
|
+
with self._lock:
|
|
254
|
+
if len(self._items) >= self._max_size:
|
|
255
|
+
return False
|
|
256
|
+
if self._current_memory_bytes + size > self._max_memory_bytes:
|
|
257
|
+
return False
|
|
258
|
+
|
|
259
|
+
self._items.append((item, size))
|
|
260
|
+
self._current_memory_bytes += size
|
|
261
|
+
return True
|
|
262
|
+
|
|
263
|
+
def add_many(self, items: list[T]) -> int:
|
|
264
|
+
"""Add multiple items to the buffer.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
items: Items to add.
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
Number of items actually added.
|
|
271
|
+
"""
|
|
272
|
+
added = 0
|
|
273
|
+
for item in items:
|
|
274
|
+
if self.add(item):
|
|
275
|
+
added += 1
|
|
276
|
+
else:
|
|
277
|
+
break
|
|
278
|
+
return added
|
|
279
|
+
|
|
280
|
+
def drain(self, count: int) -> list[T]:
|
|
281
|
+
"""Remove and return items from buffer.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
count: Maximum number of items to drain.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
List of drained items.
|
|
288
|
+
"""
|
|
289
|
+
with self._lock:
|
|
290
|
+
result = []
|
|
291
|
+
for _ in range(min(count, len(self._items))):
|
|
292
|
+
item, size = self._items.popleft()
|
|
293
|
+
self._current_memory_bytes -= size
|
|
294
|
+
result.append(item)
|
|
295
|
+
return result
|
|
296
|
+
|
|
297
|
+
def drain_all(self) -> list[T]:
|
|
298
|
+
"""Remove and return all items from buffer."""
|
|
299
|
+
with self._lock:
|
|
300
|
+
items = [item for item, _ in self._items]
|
|
301
|
+
self._items.clear()
|
|
302
|
+
self._current_memory_bytes = 0
|
|
303
|
+
return items
|
|
304
|
+
|
|
305
|
+
def drain_bytes(self, max_bytes: int) -> list[T]:
|
|
306
|
+
"""Drain items up to a byte limit.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
max_bytes: Maximum bytes to drain.
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
List of drained items.
|
|
313
|
+
"""
|
|
314
|
+
with self._lock:
|
|
315
|
+
result = []
|
|
316
|
+
total_bytes = 0
|
|
317
|
+
|
|
318
|
+
while self._items and total_bytes < max_bytes:
|
|
319
|
+
item, size = self._items[0]
|
|
320
|
+
if total_bytes + size > max_bytes and result:
|
|
321
|
+
break
|
|
322
|
+
self._items.popleft()
|
|
323
|
+
self._current_memory_bytes -= size
|
|
324
|
+
total_bytes += size
|
|
325
|
+
result.append(item)
|
|
326
|
+
|
|
327
|
+
return result
|
|
328
|
+
|
|
329
|
+
def peek(self, count: int) -> list[T]:
|
|
330
|
+
"""View items without removing."""
|
|
331
|
+
with self._lock:
|
|
332
|
+
return [item for item, _ in list(self._items)[:count]]
|
|
333
|
+
|
|
334
|
+
def clear(self) -> int:
|
|
335
|
+
"""Clear all items from buffer."""
|
|
336
|
+
with self._lock:
|
|
337
|
+
count = len(self._items)
|
|
338
|
+
self._items.clear()
|
|
339
|
+
self._current_memory_bytes = 0
|
|
340
|
+
return count
|
|
341
|
+
|
|
342
|
+
def get_stats(self) -> dict[str, Any]:
|
|
343
|
+
"""Get buffer statistics."""
|
|
344
|
+
with self._lock:
|
|
345
|
+
is_full = (
|
|
346
|
+
len(self._items) >= self._max_size
|
|
347
|
+
or self._current_memory_bytes >= self._max_memory_bytes
|
|
348
|
+
)
|
|
349
|
+
return {
|
|
350
|
+
"size": len(self._items),
|
|
351
|
+
"max_size": self._max_size,
|
|
352
|
+
"memory_bytes": self._current_memory_bytes,
|
|
353
|
+
"max_memory_bytes": self._max_memory_bytes,
|
|
354
|
+
"memory_usage_percent": (
|
|
355
|
+
self._current_memory_bytes / self._max_memory_bytes * 100
|
|
356
|
+
if self._max_memory_bytes > 0
|
|
357
|
+
else 0
|
|
358
|
+
),
|
|
359
|
+
"is_full": is_full,
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
def __len__(self) -> int:
|
|
363
|
+
"""Get number of items."""
|
|
364
|
+
return self.size
|
|
365
|
+
|
|
366
|
+
def __iter__(self) -> Iterator[T]:
|
|
367
|
+
"""Iterate over items (drains buffer)."""
|
|
368
|
+
while not self.is_empty:
|
|
369
|
+
items = self.drain(100)
|
|
370
|
+
yield from items
|