exonware-xwsystem 0.0.1.411__py3-none-any.whl → 0.1.0.3__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.
- exonware/__init__.py +2 -1
- exonware/conf.py +2 -2
- exonware/xwsystem/__init__.py +115 -43
- exonware/xwsystem/base.py +30 -0
- exonware/xwsystem/caching/__init__.py +39 -13
- exonware/xwsystem/caching/base.py +24 -6
- exonware/xwsystem/caching/bloom_cache.py +2 -2
- exonware/xwsystem/caching/cache_manager.py +2 -1
- exonware/xwsystem/caching/conditional.py +2 -2
- exonware/xwsystem/caching/contracts.py +85 -139
- exonware/xwsystem/caching/decorators.py +6 -19
- exonware/xwsystem/caching/defs.py +2 -1
- exonware/xwsystem/caching/disk_cache.py +2 -1
- exonware/xwsystem/caching/distributed.py +2 -1
- exonware/xwsystem/caching/errors.py +2 -1
- exonware/xwsystem/caching/events.py +110 -27
- exonware/xwsystem/caching/eviction_strategies.py +2 -2
- exonware/xwsystem/caching/external_caching_python.py +701 -0
- exonware/xwsystem/caching/facade.py +253 -0
- exonware/xwsystem/caching/factory.py +300 -0
- exonware/xwsystem/caching/fluent.py +14 -12
- exonware/xwsystem/caching/integrity.py +21 -6
- exonware/xwsystem/caching/lfu_cache.py +2 -1
- exonware/xwsystem/caching/lfu_optimized.py +18 -6
- exonware/xwsystem/caching/lru_cache.py +7 -4
- exonware/xwsystem/caching/memory_bounded.py +2 -2
- exonware/xwsystem/caching/metrics_exporter.py +2 -2
- exonware/xwsystem/caching/observable_cache.py +2 -2
- exonware/xwsystem/caching/pluggable_cache.py +2 -2
- exonware/xwsystem/caching/rate_limiter.py +2 -2
- exonware/xwsystem/caching/read_through.py +2 -2
- exonware/xwsystem/caching/secure_cache.py +81 -28
- exonware/xwsystem/caching/serializable.py +9 -7
- exonware/xwsystem/caching/stats.py +2 -2
- exonware/xwsystem/caching/tagging.py +2 -2
- exonware/xwsystem/caching/ttl_cache.py +4 -3
- exonware/xwsystem/caching/two_tier_cache.py +6 -3
- exonware/xwsystem/caching/utils.py +30 -12
- exonware/xwsystem/caching/validation.py +2 -2
- exonware/xwsystem/caching/warming.py +6 -3
- exonware/xwsystem/caching/write_behind.py +15 -6
- exonware/xwsystem/config/__init__.py +11 -17
- exonware/xwsystem/config/base.py +5 -5
- exonware/xwsystem/config/contracts.py +93 -153
- exonware/xwsystem/config/defaults.py +3 -2
- exonware/xwsystem/config/defs.py +3 -2
- exonware/xwsystem/config/errors.py +2 -5
- exonware/xwsystem/config/logging.py +12 -8
- exonware/xwsystem/config/logging_setup.py +3 -2
- exonware/xwsystem/config/performance.py +73 -391
- exonware/xwsystem/config/performance_modes.py +9 -8
- exonware/xwsystem/config/version_manager.py +1 -0
- exonware/xwsystem/config.py +27 -0
- exonware/xwsystem/console/__init__.py +53 -0
- exonware/xwsystem/console/base.py +133 -0
- exonware/xwsystem/console/cli/__init__.py +61 -0
- exonware/xwsystem/{cli → console/cli}/args.py +27 -24
- exonware/xwsystem/{cli → console/cli}/base.py +18 -87
- exonware/xwsystem/{cli → console/cli}/colors.py +15 -13
- exonware/xwsystem/console/cli/console.py +98 -0
- exonware/xwsystem/{cli → console/cli}/contracts.py +51 -69
- exonware/xwsystem/console/cli/defs.py +87 -0
- exonware/xwsystem/console/cli/encoding.py +69 -0
- exonware/xwsystem/{cli → console/cli}/errors.py +8 -3
- exonware/xwsystem/console/cli/event_logger.py +166 -0
- exonware/xwsystem/{cli → console/cli}/progress.py +25 -21
- exonware/xwsystem/{cli → console/cli}/prompts.py +3 -2
- exonware/xwsystem/{cli → console/cli}/tables.py +27 -24
- exonware/xwsystem/console/contracts.py +113 -0
- exonware/xwsystem/console/defs.py +154 -0
- exonware/xwsystem/console/errors.py +34 -0
- exonware/xwsystem/console/event_logger.py +385 -0
- exonware/xwsystem/console/writer.py +132 -0
- exonware/xwsystem/contracts.py +28 -0
- exonware/xwsystem/data_structures/__init__.py +23 -0
- exonware/xwsystem/data_structures/trie.py +34 -0
- exonware/xwsystem/data_structures/union_find.py +144 -0
- exonware/xwsystem/defs.py +17 -0
- exonware/xwsystem/errors.py +23 -0
- exonware/xwsystem/facade.py +62 -0
- exonware/xwsystem/http_client/__init__.py +22 -1
- exonware/xwsystem/http_client/advanced_client.py +8 -5
- exonware/xwsystem/http_client/base.py +3 -2
- exonware/xwsystem/http_client/client.py +7 -4
- exonware/xwsystem/http_client/contracts.py +42 -56
- exonware/xwsystem/http_client/defs.py +2 -1
- exonware/xwsystem/http_client/errors.py +2 -1
- exonware/xwsystem/http_client/facade.py +156 -0
- exonware/xwsystem/io/__init__.py +22 -3
- exonware/xwsystem/io/archive/__init__.py +8 -2
- exonware/xwsystem/io/archive/archive.py +1 -1
- exonware/xwsystem/io/archive/archive_files.py +4 -7
- exonware/xwsystem/io/archive/archivers.py +120 -10
- exonware/xwsystem/io/archive/base.py +4 -5
- exonware/xwsystem/io/archive/codec_integration.py +1 -2
- exonware/xwsystem/io/archive/compression.py +1 -2
- exonware/xwsystem/io/archive/facade.py +263 -0
- exonware/xwsystem/io/archive/formats/__init__.py +2 -3
- exonware/xwsystem/io/archive/formats/brotli_format.py +20 -7
- exonware/xwsystem/io/archive/formats/lz4_format.py +20 -7
- exonware/xwsystem/io/archive/formats/rar.py +11 -5
- exonware/xwsystem/io/archive/formats/sevenzip.py +12 -6
- exonware/xwsystem/io/archive/formats/squashfs_format.py +1 -2
- exonware/xwsystem/io/archive/formats/tar.py +52 -7
- exonware/xwsystem/io/archive/formats/wim_format.py +11 -5
- exonware/xwsystem/io/archive/formats/zip.py +1 -2
- exonware/xwsystem/io/archive/formats/zpaq_format.py +1 -2
- exonware/xwsystem/io/archive/formats/zstandard.py +20 -7
- exonware/xwsystem/io/base.py +119 -115
- exonware/xwsystem/io/codec/__init__.py +4 -2
- exonware/xwsystem/io/codec/base.py +19 -13
- exonware/xwsystem/io/codec/contracts.py +59 -2
- exonware/xwsystem/io/codec/registry.py +67 -21
- exonware/xwsystem/io/common/__init__.py +1 -1
- exonware/xwsystem/io/common/atomic.py +29 -16
- exonware/xwsystem/io/common/base.py +11 -10
- exonware/xwsystem/io/common/lock.py +6 -5
- exonware/xwsystem/io/common/path_manager.py +2 -1
- exonware/xwsystem/io/common/watcher.py +1 -2
- exonware/xwsystem/io/contracts.py +301 -433
- exonware/xwsystem/io/contracts_1.py +1180 -0
- exonware/xwsystem/io/data_operations.py +279 -14
- exonware/xwsystem/io/defs.py +4 -3
- exonware/xwsystem/io/errors.py +3 -2
- exonware/xwsystem/io/facade.py +87 -61
- exonware/xwsystem/io/file/__init__.py +1 -1
- exonware/xwsystem/io/file/base.py +8 -9
- exonware/xwsystem/io/file/conversion.py +2 -3
- exonware/xwsystem/io/file/file.py +61 -18
- exonware/xwsystem/io/file/paged_source.py +8 -8
- exonware/xwsystem/io/file/paging/__init__.py +1 -2
- exonware/xwsystem/io/file/paging/byte_paging.py +4 -5
- exonware/xwsystem/io/file/paging/line_paging.py +2 -3
- exonware/xwsystem/io/file/paging/record_paging.py +2 -3
- exonware/xwsystem/io/file/paging/registry.py +1 -2
- exonware/xwsystem/io/file/source.py +13 -17
- exonware/xwsystem/io/filesystem/__init__.py +1 -1
- exonware/xwsystem/io/filesystem/base.py +1 -2
- exonware/xwsystem/io/filesystem/local.py +3 -4
- exonware/xwsystem/io/folder/__init__.py +1 -1
- exonware/xwsystem/io/folder/base.py +1 -2
- exonware/xwsystem/io/folder/folder.py +16 -7
- exonware/xwsystem/io/indexing/__init__.py +14 -0
- exonware/xwsystem/io/indexing/facade.py +443 -0
- exonware/xwsystem/io/path_parser.py +98 -0
- exonware/xwsystem/io/serialization/__init__.py +21 -3
- exonware/xwsystem/io/serialization/auto_serializer.py +146 -20
- exonware/xwsystem/io/serialization/base.py +84 -34
- exonware/xwsystem/io/serialization/contracts.py +50 -73
- exonware/xwsystem/io/serialization/defs.py +2 -1
- exonware/xwsystem/io/serialization/errors.py +2 -1
- exonware/xwsystem/io/serialization/flyweight.py +154 -7
- exonware/xwsystem/io/serialization/format_detector.py +15 -14
- exonware/xwsystem/io/serialization/formats/__init__.py +8 -5
- exonware/xwsystem/io/serialization/formats/binary/bson.py +15 -6
- exonware/xwsystem/io/serialization/formats/binary/cbor.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/marshal.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/msgpack.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/pickle.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/plistlib.py +5 -5
- exonware/xwsystem/io/serialization/formats/database/dbm.py +7 -7
- exonware/xwsystem/io/serialization/formats/database/shelve.py +7 -7
- exonware/xwsystem/io/serialization/formats/database/sqlite3.py +7 -7
- exonware/xwsystem/io/serialization/formats/tabular/__init__.py +27 -0
- exonware/xwsystem/io/serialization/formats/tabular/base.py +89 -0
- exonware/xwsystem/io/serialization/formats/tabular/csv.py +319 -0
- exonware/xwsystem/io/serialization/formats/tabular/df.py +249 -0
- exonware/xwsystem/io/serialization/formats/tabular/excel.py +291 -0
- exonware/xwsystem/io/serialization/formats/tabular/googlesheets.py +374 -0
- exonware/xwsystem/io/serialization/formats/text/__init__.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/append_only_log.py +199 -0
- exonware/xwsystem/io/serialization/formats/text/configparser.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/csv.py +7 -5
- exonware/xwsystem/io/serialization/formats/text/formdata.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/json.py +65 -33
- exonware/xwsystem/io/serialization/formats/text/json5.py +8 -4
- exonware/xwsystem/io/serialization/formats/text/jsonlines.py +113 -25
- exonware/xwsystem/io/serialization/formats/text/multipart.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/toml.py +8 -6
- exonware/xwsystem/io/serialization/formats/text/xml.py +25 -20
- exonware/xwsystem/io/serialization/formats/text/yaml.py +8 -6
- exonware/xwsystem/io/serialization/parsers/__init__.py +16 -0
- exonware/xwsystem/io/serialization/parsers/base.py +60 -0
- exonware/xwsystem/io/serialization/parsers/hybrid_parser.py +62 -0
- exonware/xwsystem/io/serialization/parsers/msgspec_parser.py +48 -0
- exonware/xwsystem/io/serialization/parsers/orjson_direct_parser.py +54 -0
- exonware/xwsystem/io/serialization/parsers/orjson_parser.py +62 -0
- exonware/xwsystem/io/serialization/parsers/pysimdjson_parser.py +55 -0
- exonware/xwsystem/io/serialization/parsers/rapidjson_parser.py +53 -0
- exonware/xwsystem/io/serialization/parsers/registry.py +91 -0
- exonware/xwsystem/io/serialization/parsers/standard.py +44 -0
- exonware/xwsystem/io/serialization/parsers/ujson_parser.py +53 -0
- exonware/xwsystem/io/serialization/registry.py +4 -4
- exonware/xwsystem/io/serialization/serializer.py +168 -79
- exonware/xwsystem/io/serialization/universal_options.py +367 -0
- exonware/xwsystem/io/serialization/utils/__init__.py +1 -2
- exonware/xwsystem/io/serialization/utils/path_ops.py +5 -6
- exonware/xwsystem/io/source_reader.py +223 -0
- exonware/xwsystem/io/stream/__init__.py +1 -1
- exonware/xwsystem/io/stream/async_operations.py +61 -14
- exonware/xwsystem/io/stream/base.py +1 -2
- exonware/xwsystem/io/stream/codec_io.py +6 -7
- exonware/xwsystem/ipc/__init__.py +1 -0
- exonware/xwsystem/ipc/async_fabric.py +4 -4
- exonware/xwsystem/ipc/base.py +6 -5
- exonware/xwsystem/ipc/contracts.py +41 -66
- exonware/xwsystem/ipc/defs.py +2 -1
- exonware/xwsystem/ipc/errors.py +2 -1
- exonware/xwsystem/ipc/message_queue.py +5 -2
- exonware/xwsystem/ipc/pipes.py +70 -34
- exonware/xwsystem/ipc/process_manager.py +7 -5
- exonware/xwsystem/ipc/process_pool.py +6 -5
- exonware/xwsystem/ipc/shared_memory.py +64 -11
- exonware/xwsystem/monitoring/__init__.py +7 -0
- exonware/xwsystem/monitoring/base.py +11 -8
- exonware/xwsystem/monitoring/contracts.py +86 -144
- exonware/xwsystem/monitoring/defs.py +2 -1
- exonware/xwsystem/monitoring/error_recovery.py +16 -3
- exonware/xwsystem/monitoring/errors.py +2 -1
- exonware/xwsystem/monitoring/facade.py +183 -0
- exonware/xwsystem/monitoring/memory_monitor.py +1 -0
- exonware/xwsystem/monitoring/metrics.py +1 -0
- exonware/xwsystem/monitoring/performance_manager_generic.py +7 -7
- exonware/xwsystem/monitoring/performance_monitor.py +1 -0
- exonware/xwsystem/monitoring/performance_validator.py +1 -0
- exonware/xwsystem/monitoring/system_monitor.py +6 -5
- exonware/xwsystem/monitoring/tracing.py +18 -16
- exonware/xwsystem/monitoring/tracker.py +2 -1
- exonware/xwsystem/operations/__init__.py +5 -50
- exonware/xwsystem/operations/base.py +3 -44
- exonware/xwsystem/operations/contracts.py +25 -15
- exonware/xwsystem/operations/defs.py +1 -1
- exonware/xwsystem/operations/diff.py +5 -4
- exonware/xwsystem/operations/errors.py +1 -1
- exonware/xwsystem/operations/merge.py +6 -4
- exonware/xwsystem/operations/patch.py +5 -4
- exonware/xwsystem/patterns/__init__.py +1 -0
- exonware/xwsystem/patterns/base.py +2 -1
- exonware/xwsystem/patterns/context_manager.py +2 -1
- exonware/xwsystem/patterns/contracts.py +215 -256
- exonware/xwsystem/patterns/defs.py +2 -1
- exonware/xwsystem/patterns/dynamic_facade.py +1 -0
- exonware/xwsystem/patterns/errors.py +2 -4
- exonware/xwsystem/patterns/handler_factory.py +2 -3
- exonware/xwsystem/patterns/import_registry.py +1 -0
- exonware/xwsystem/patterns/object_pool.py +1 -0
- exonware/xwsystem/patterns/registry.py +4 -43
- exonware/xwsystem/plugins/__init__.py +2 -1
- exonware/xwsystem/plugins/base.py +6 -5
- exonware/xwsystem/plugins/contracts.py +94 -158
- exonware/xwsystem/plugins/defs.py +2 -1
- exonware/xwsystem/plugins/errors.py +2 -1
- exonware/xwsystem/py.typed +3 -0
- exonware/xwsystem/query/__init__.py +36 -0
- exonware/xwsystem/query/contracts.py +56 -0
- exonware/xwsystem/query/errors.py +22 -0
- exonware/xwsystem/query/registry.py +128 -0
- exonware/xwsystem/runtime/__init__.py +2 -1
- exonware/xwsystem/runtime/base.py +4 -3
- exonware/xwsystem/runtime/contracts.py +39 -60
- exonware/xwsystem/runtime/defs.py +2 -1
- exonware/xwsystem/runtime/env.py +11 -9
- exonware/xwsystem/runtime/errors.py +2 -1
- exonware/xwsystem/runtime/reflection.py +3 -2
- exonware/xwsystem/security/__init__.py +68 -11
- exonware/xwsystem/security/audit.py +167 -0
- exonware/xwsystem/security/base.py +121 -24
- exonware/xwsystem/security/contracts.py +91 -146
- exonware/xwsystem/security/crypto.py +17 -16
- exonware/xwsystem/security/defs.py +2 -1
- exonware/xwsystem/security/errors.py +2 -1
- exonware/xwsystem/security/facade.py +321 -0
- exonware/xwsystem/security/file_security.py +330 -0
- exonware/xwsystem/security/hazmat.py +11 -8
- exonware/xwsystem/security/monitor.py +372 -0
- exonware/xwsystem/security/path_validator.py +140 -18
- exonware/xwsystem/security/policy.py +357 -0
- exonware/xwsystem/security/resource_limits.py +1 -0
- exonware/xwsystem/security/validator.py +455 -0
- exonware/xwsystem/shared/__init__.py +14 -1
- exonware/xwsystem/shared/base.py +285 -2
- exonware/xwsystem/shared/contracts.py +415 -126
- exonware/xwsystem/shared/defs.py +2 -1
- exonware/xwsystem/shared/errors.py +2 -2
- exonware/xwsystem/shared/xwobject.py +316 -0
- exonware/xwsystem/structures/__init__.py +1 -0
- exonware/xwsystem/structures/base.py +3 -2
- exonware/xwsystem/structures/circular_detector.py +15 -14
- exonware/xwsystem/structures/contracts.py +53 -76
- exonware/xwsystem/structures/defs.py +2 -1
- exonware/xwsystem/structures/errors.py +2 -1
- exonware/xwsystem/structures/tree_walker.py +2 -1
- exonware/xwsystem/threading/__init__.py +21 -4
- exonware/xwsystem/threading/async_primitives.py +6 -5
- exonware/xwsystem/threading/base.py +3 -2
- exonware/xwsystem/threading/contracts.py +87 -143
- exonware/xwsystem/threading/defs.py +2 -1
- exonware/xwsystem/threading/errors.py +2 -1
- exonware/xwsystem/threading/facade.py +175 -0
- exonware/xwsystem/threading/locks.py +1 -0
- exonware/xwsystem/threading/safe_factory.py +1 -0
- exonware/xwsystem/utils/__init__.py +40 -0
- exonware/xwsystem/utils/base.py +22 -21
- exonware/xwsystem/utils/contracts.py +50 -73
- exonware/xwsystem/utils/dt/__init__.py +19 -3
- exonware/xwsystem/utils/dt/base.py +5 -4
- exonware/xwsystem/utils/dt/contracts.py +22 -29
- exonware/xwsystem/utils/dt/defs.py +2 -1
- exonware/xwsystem/utils/dt/errors.py +2 -5
- exonware/xwsystem/utils/dt/formatting.py +88 -2
- exonware/xwsystem/utils/dt/humanize.py +10 -9
- exonware/xwsystem/utils/dt/parsing.py +56 -5
- exonware/xwsystem/utils/dt/timezone_utils.py +2 -24
- exonware/xwsystem/utils/errors.py +2 -4
- exonware/xwsystem/utils/paths.py +1 -0
- exonware/xwsystem/utils/string.py +49 -0
- exonware/xwsystem/utils/test_runner.py +139 -480
- exonware/xwsystem/utils/utils_contracts.py +2 -1
- exonware/xwsystem/utils/web.py +110 -0
- exonware/xwsystem/validation/__init__.py +25 -1
- exonware/xwsystem/validation/base.py +6 -5
- exonware/xwsystem/validation/contracts.py +29 -41
- exonware/xwsystem/validation/data_validator.py +1 -0
- exonware/xwsystem/validation/declarative.py +11 -8
- exonware/xwsystem/validation/defs.py +2 -1
- exonware/xwsystem/validation/errors.py +2 -1
- exonware/xwsystem/validation/facade.py +198 -0
- exonware/xwsystem/validation/fluent_validator.py +22 -19
- exonware/xwsystem/validation/schema_discovery.py +210 -0
- exonware/xwsystem/validation/type_safety.py +2 -1
- exonware/xwsystem/version.py +4 -4
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/METADATA +71 -4
- exonware_xwsystem-0.1.0.3.dist-info/RECORD +337 -0
- exonware/xwsystem/caching/USAGE_GUIDE.md +0 -779
- exonware/xwsystem/cli/__init__.py +0 -43
- exonware/xwsystem/cli/console.py +0 -113
- exonware/xwsystem/cli/defs.py +0 -134
- exonware/xwsystem/conf.py +0 -44
- exonware/xwsystem/security/auth.py +0 -484
- exonware_xwsystem-0.0.1.411.dist-info/RECORD +0 -274
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/WHEEL +0 -0
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/caching/external_caching_python.py
|
|
2
|
+
"""
|
|
3
|
+
External Python caching library implementations.
|
|
4
|
+
|
|
5
|
+
Company: eXonware.com
|
|
6
|
+
Author: Eng. Muhammad AlShehri
|
|
7
|
+
Email: connect@exonware.com
|
|
8
|
+
Version: 0.1.0.3
|
|
9
|
+
Generation Date: 01-Nov-2025
|
|
10
|
+
|
|
11
|
+
Wrappers for external caching libraries:
|
|
12
|
+
- cachebox: Rust-based Python cache (fastest)
|
|
13
|
+
- functools.lru_cache: Standard library LRU (C implementation)
|
|
14
|
+
- cachetools: Flexible caching with TTL, LFU, RR policies
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import time
|
|
18
|
+
from typing import Any, Optional, Hashable
|
|
19
|
+
from functools import lru_cache as std_lru_cache
|
|
20
|
+
from collections import OrderedDict
|
|
21
|
+
|
|
22
|
+
from .base import ACache
|
|
23
|
+
from .contracts import ICache
|
|
24
|
+
|
|
25
|
+
# Optional dependencies: cachebox and cachetools
|
|
26
|
+
import importlib.util
|
|
27
|
+
|
|
28
|
+
# Check for cachebox
|
|
29
|
+
_cachebox_spec = importlib.util.find_spec('cachebox')
|
|
30
|
+
if _cachebox_spec is not None:
|
|
31
|
+
import cachebox
|
|
32
|
+
HAS_CACHEBOX = True
|
|
33
|
+
else:
|
|
34
|
+
HAS_CACHEBOX = False
|
|
35
|
+
cachebox = None
|
|
36
|
+
|
|
37
|
+
# Check for cachetools
|
|
38
|
+
_cachetools_spec = importlib.util.find_spec('cachetools')
|
|
39
|
+
if _cachetools_spec is not None:
|
|
40
|
+
import cachetools
|
|
41
|
+
from cachetools import (
|
|
42
|
+
LRUCache as CachetoolsLRU,
|
|
43
|
+
LFUCache as CachetoolsLFU,
|
|
44
|
+
TTLCache as CachetoolsTTL,
|
|
45
|
+
RRCache as CachetoolsRR,
|
|
46
|
+
)
|
|
47
|
+
HAS_CACHETOOLS = True
|
|
48
|
+
else:
|
|
49
|
+
HAS_CACHETOOLS = False
|
|
50
|
+
cachetools = None
|
|
51
|
+
CachetoolsLRU = None
|
|
52
|
+
CachetoolsLFU = None
|
|
53
|
+
CachetoolsTTL = None
|
|
54
|
+
CachetoolsRR = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ============================================================================
|
|
58
|
+
# CACHEBOX IMPLEMENTATION
|
|
59
|
+
# ============================================================================
|
|
60
|
+
|
|
61
|
+
class CacheboxCache(ACache):
|
|
62
|
+
"""
|
|
63
|
+
Cachebox wrapper - Rust-based high-performance cache.
|
|
64
|
+
|
|
65
|
+
This is a Python wrapper around Rust's caching primitives,
|
|
66
|
+
providing excellent performance for large datasets.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(self, capacity: int = 128, ttl: Optional[float] = None, **kwargs):
|
|
70
|
+
"""
|
|
71
|
+
Initialize Cachebox cache.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
capacity: Maximum cache size
|
|
75
|
+
ttl: Time to live in seconds (not directly supported by cachebox)
|
|
76
|
+
"""
|
|
77
|
+
if not HAS_CACHEBOX:
|
|
78
|
+
raise ImportError(
|
|
79
|
+
"cachebox not available. Install with: pip install cachebox"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
super().__init__(capacity=capacity, ttl=int(ttl) if ttl else None)
|
|
83
|
+
|
|
84
|
+
# cachebox uses maxsize parameter
|
|
85
|
+
self._cache = cachebox.Cache(maxsize=capacity)
|
|
86
|
+
self._hits = 0
|
|
87
|
+
self._misses = 0
|
|
88
|
+
self._evictions = 0
|
|
89
|
+
|
|
90
|
+
def get(self, key: Hashable, default: Any = None) -> Any:
|
|
91
|
+
"""Get value from cache."""
|
|
92
|
+
try:
|
|
93
|
+
value = self._cache.get(key, default)
|
|
94
|
+
if value is not default:
|
|
95
|
+
self._hits += 1
|
|
96
|
+
else:
|
|
97
|
+
self._misses += 1
|
|
98
|
+
return value
|
|
99
|
+
except Exception:
|
|
100
|
+
self._misses += 1
|
|
101
|
+
return default
|
|
102
|
+
|
|
103
|
+
def put(self, key: Hashable, value: Any) -> None:
|
|
104
|
+
"""Put value in cache."""
|
|
105
|
+
# Check if we need to evict (cachebox handles this automatically)
|
|
106
|
+
if len(self._cache) >= self.capacity and key not in self._cache:
|
|
107
|
+
self._evictions += 1
|
|
108
|
+
|
|
109
|
+
self._cache[key] = value
|
|
110
|
+
|
|
111
|
+
def delete(self, key: Hashable) -> bool:
|
|
112
|
+
"""Delete key from cache."""
|
|
113
|
+
try:
|
|
114
|
+
del self._cache[key]
|
|
115
|
+
return True
|
|
116
|
+
except KeyError:
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
def clear(self) -> None:
|
|
120
|
+
"""Clear cache."""
|
|
121
|
+
self._cache.clear()
|
|
122
|
+
self._hits = 0
|
|
123
|
+
self._misses = 0
|
|
124
|
+
self._evictions = 0
|
|
125
|
+
|
|
126
|
+
def size(self) -> int:
|
|
127
|
+
"""Get cache size."""
|
|
128
|
+
return len(self._cache)
|
|
129
|
+
|
|
130
|
+
def is_full(self) -> bool:
|
|
131
|
+
"""Check if cache is full."""
|
|
132
|
+
return len(self._cache) >= self.capacity
|
|
133
|
+
|
|
134
|
+
def evict(self) -> None:
|
|
135
|
+
"""Evict entries (handled automatically by cachebox)."""
|
|
136
|
+
# cachebox handles eviction automatically
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
def keys(self) -> list[Hashable]:
|
|
140
|
+
"""Get list of all cache keys."""
|
|
141
|
+
return list(self._cache.keys())
|
|
142
|
+
|
|
143
|
+
def values(self) -> list[Any]:
|
|
144
|
+
"""Get list of all cache values."""
|
|
145
|
+
return list(self._cache.values())
|
|
146
|
+
|
|
147
|
+
def items(self) -> list[tuple[Hashable, Any]]:
|
|
148
|
+
"""Get list of all key-value pairs."""
|
|
149
|
+
return list(self._cache.items())
|
|
150
|
+
|
|
151
|
+
def get_stats(self) -> dict[str, Any]:
|
|
152
|
+
"""Get cache statistics."""
|
|
153
|
+
total = self._hits + self._misses
|
|
154
|
+
hit_rate = (self._hits / total) if total > 0 else 0.0
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
"hits": self._hits,
|
|
158
|
+
"misses": self._misses,
|
|
159
|
+
"evictions": self._evictions,
|
|
160
|
+
"hit_rate": hit_rate,
|
|
161
|
+
"size": self.size(),
|
|
162
|
+
"capacity": self.capacity,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# ICache interface compatibility
|
|
166
|
+
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
|
|
167
|
+
"""Set value in cache (ICache interface)."""
|
|
168
|
+
self.put(key, value)
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
def exists(self, key: str) -> bool:
|
|
172
|
+
"""Check if key exists (ICache interface)."""
|
|
173
|
+
return key in self._cache
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ============================================================================
|
|
177
|
+
# FUNCTOOLS LRU_CACHE IMPLEMENTATION
|
|
178
|
+
# ============================================================================
|
|
179
|
+
|
|
180
|
+
class FunctoolsLRUCache(ACache):
|
|
181
|
+
"""
|
|
182
|
+
functools.lru_cache wrapper - Standard library LRU cache.
|
|
183
|
+
|
|
184
|
+
This is implemented in C (CPython core), making it extremely fast
|
|
185
|
+
for simple function memoization. However, it's a decorator, so we
|
|
186
|
+
implement a manual LRU cache that mimics its behavior.
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
def __init__(self, capacity: int = 128, ttl: Optional[float] = None, **kwargs):
|
|
190
|
+
"""
|
|
191
|
+
Initialize functools-style LRU cache.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
capacity: Maximum cache size
|
|
195
|
+
ttl: Time to live in seconds (not supported by functools)
|
|
196
|
+
"""
|
|
197
|
+
super().__init__(capacity=capacity, ttl=int(ttl) if ttl else None)
|
|
198
|
+
|
|
199
|
+
# Use OrderedDict for LRU behavior
|
|
200
|
+
self._cache: OrderedDict[Hashable, Any] = OrderedDict()
|
|
201
|
+
self._hits = 0
|
|
202
|
+
self._misses = 0
|
|
203
|
+
self._evictions = 0
|
|
204
|
+
|
|
205
|
+
def get(self, key: Hashable, default: Any = None) -> Any:
|
|
206
|
+
"""Get value from cache."""
|
|
207
|
+
if key in self._cache:
|
|
208
|
+
# Move to end (most recently used)
|
|
209
|
+
value = self._cache.pop(key)
|
|
210
|
+
self._cache[key] = value
|
|
211
|
+
self._hits += 1
|
|
212
|
+
return value
|
|
213
|
+
|
|
214
|
+
self._misses += 1
|
|
215
|
+
return default
|
|
216
|
+
|
|
217
|
+
def put(self, key: Hashable, value: Any) -> None:
|
|
218
|
+
"""Put value in cache."""
|
|
219
|
+
if key in self._cache:
|
|
220
|
+
# Update existing - move to end
|
|
221
|
+
self._cache.pop(key)
|
|
222
|
+
else:
|
|
223
|
+
# Ensure capacity is int (handle case where it might be string from config)
|
|
224
|
+
capacity = int(self.capacity) if isinstance(self.capacity, str) else self.capacity
|
|
225
|
+
if len(self._cache) >= capacity:
|
|
226
|
+
# Evict least recently used (first item)
|
|
227
|
+
if self._cache:
|
|
228
|
+
self._cache.popitem(last=False) # Remove first (oldest)
|
|
229
|
+
self._evictions += 1
|
|
230
|
+
|
|
231
|
+
self._cache[key] = value
|
|
232
|
+
|
|
233
|
+
def delete(self, key: Hashable) -> bool:
|
|
234
|
+
"""Delete key from cache."""
|
|
235
|
+
if key in self._cache:
|
|
236
|
+
del self._cache[key]
|
|
237
|
+
return True
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
def clear(self) -> None:
|
|
241
|
+
"""Clear cache."""
|
|
242
|
+
self._cache.clear()
|
|
243
|
+
self._hits = 0
|
|
244
|
+
self._misses = 0
|
|
245
|
+
self._evictions = 0
|
|
246
|
+
|
|
247
|
+
def size(self) -> int:
|
|
248
|
+
"""Get cache size."""
|
|
249
|
+
return len(self._cache)
|
|
250
|
+
|
|
251
|
+
def is_full(self) -> bool:
|
|
252
|
+
"""Check if cache is full."""
|
|
253
|
+
return len(self._cache) >= self.capacity
|
|
254
|
+
|
|
255
|
+
def evict(self) -> None:
|
|
256
|
+
"""Evict least recently used entry."""
|
|
257
|
+
if self._cache:
|
|
258
|
+
self._cache.popitem(last=False)
|
|
259
|
+
self._evictions += 1
|
|
260
|
+
|
|
261
|
+
def keys(self) -> list[Hashable]:
|
|
262
|
+
"""Get list of all cache keys."""
|
|
263
|
+
return list(self._cache.keys())
|
|
264
|
+
|
|
265
|
+
def values(self) -> list[Any]:
|
|
266
|
+
"""Get list of all cache values."""
|
|
267
|
+
return list(self._cache.values())
|
|
268
|
+
|
|
269
|
+
def items(self) -> list[tuple[Hashable, Any]]:
|
|
270
|
+
"""Get list of all key-value pairs."""
|
|
271
|
+
return list(self._cache.items())
|
|
272
|
+
|
|
273
|
+
def get_stats(self) -> dict[str, Any]:
|
|
274
|
+
"""Get cache statistics."""
|
|
275
|
+
total = self._hits + self._misses
|
|
276
|
+
hit_rate = (self._hits / total) if total > 0 else 0.0
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
"hits": self._hits,
|
|
280
|
+
"misses": self._misses,
|
|
281
|
+
"evictions": self._evictions,
|
|
282
|
+
"hit_rate": hit_rate,
|
|
283
|
+
"size": self.size(),
|
|
284
|
+
"capacity": self.capacity,
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# ICache interface compatibility
|
|
288
|
+
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
|
|
289
|
+
"""Set value in cache (ICache interface)."""
|
|
290
|
+
self.put(key, value)
|
|
291
|
+
return True
|
|
292
|
+
|
|
293
|
+
def exists(self, key: str) -> bool:
|
|
294
|
+
"""Check if key exists (ICache interface)."""
|
|
295
|
+
return key in self._cache
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# ============================================================================
|
|
299
|
+
# CACHETOOLS IMPLEMENTATIONS
|
|
300
|
+
# ============================================================================
|
|
301
|
+
|
|
302
|
+
class CachetoolsLRUCache(ACache):
|
|
303
|
+
"""Cachetools LRUCache wrapper."""
|
|
304
|
+
|
|
305
|
+
def __init__(self, capacity: int = 128, ttl: Optional[float] = None, **kwargs):
|
|
306
|
+
"""Initialize Cachetools LRU cache."""
|
|
307
|
+
if not HAS_CACHETOOLS:
|
|
308
|
+
raise ImportError(
|
|
309
|
+
"cachetools not available. Install with: pip install cachetools"
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
super().__init__(capacity=capacity, ttl=int(ttl) if ttl else None)
|
|
313
|
+
self._cache = CachetoolsLRU(maxsize=capacity)
|
|
314
|
+
self._hits = 0
|
|
315
|
+
self._misses = 0
|
|
316
|
+
self._evictions = 0
|
|
317
|
+
|
|
318
|
+
def get(self, key: Hashable, default: Any = None) -> Any:
|
|
319
|
+
"""Get value from cache."""
|
|
320
|
+
value = self._cache.get(key, default)
|
|
321
|
+
if value is not default:
|
|
322
|
+
self._hits += 1
|
|
323
|
+
else:
|
|
324
|
+
self._misses += 1
|
|
325
|
+
return value
|
|
326
|
+
|
|
327
|
+
def put(self, key: Hashable, value: Any) -> None:
|
|
328
|
+
"""Put value in cache."""
|
|
329
|
+
if len(self._cache) >= self.capacity and key not in self._cache:
|
|
330
|
+
self._evictions += 1
|
|
331
|
+
self._cache[key] = value
|
|
332
|
+
|
|
333
|
+
def delete(self, key: Hashable) -> bool:
|
|
334
|
+
"""Delete key from cache."""
|
|
335
|
+
try:
|
|
336
|
+
del self._cache[key]
|
|
337
|
+
return True
|
|
338
|
+
except KeyError:
|
|
339
|
+
return False
|
|
340
|
+
|
|
341
|
+
def clear(self) -> None:
|
|
342
|
+
"""Clear cache."""
|
|
343
|
+
self._cache.clear()
|
|
344
|
+
self._hits = 0
|
|
345
|
+
self._misses = 0
|
|
346
|
+
self._evictions = 0
|
|
347
|
+
|
|
348
|
+
def size(self) -> int:
|
|
349
|
+
"""Get cache size."""
|
|
350
|
+
return len(self._cache)
|
|
351
|
+
|
|
352
|
+
def is_full(self) -> bool:
|
|
353
|
+
"""Check if cache is full."""
|
|
354
|
+
return len(self._cache) >= self.capacity
|
|
355
|
+
|
|
356
|
+
def evict(self) -> None:
|
|
357
|
+
"""Evict entries (handled automatically)."""
|
|
358
|
+
pass
|
|
359
|
+
|
|
360
|
+
def keys(self) -> list[Hashable]:
|
|
361
|
+
"""Get list of all cache keys."""
|
|
362
|
+
return list(self._cache.keys())
|
|
363
|
+
|
|
364
|
+
def values(self) -> list[Any]:
|
|
365
|
+
"""Get list of all cache values."""
|
|
366
|
+
return list(self._cache.values())
|
|
367
|
+
|
|
368
|
+
def items(self) -> list[tuple[Hashable, Any]]:
|
|
369
|
+
"""Get list of all key-value pairs."""
|
|
370
|
+
return list(self._cache.items())
|
|
371
|
+
|
|
372
|
+
def get_stats(self) -> dict[str, Any]:
|
|
373
|
+
"""Get cache statistics."""
|
|
374
|
+
total = self._hits + self._misses
|
|
375
|
+
hit_rate = (self._hits / total) if total > 0 else 0.0
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
"hits": self._hits,
|
|
379
|
+
"misses": self._misses,
|
|
380
|
+
"evictions": self._evictions,
|
|
381
|
+
"hit_rate": hit_rate,
|
|
382
|
+
"size": self.size(),
|
|
383
|
+
"capacity": self.capacity,
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
# ICache interface compatibility
|
|
387
|
+
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
|
|
388
|
+
"""Set value in cache (ICache interface)."""
|
|
389
|
+
self.put(key, value)
|
|
390
|
+
return True
|
|
391
|
+
|
|
392
|
+
def exists(self, key: str) -> bool:
|
|
393
|
+
"""Check if key exists (ICache interface)."""
|
|
394
|
+
return key in self._cache
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class CachetoolsLFUCache(ACache):
|
|
398
|
+
"""Cachetools LFUCache wrapper."""
|
|
399
|
+
|
|
400
|
+
def __init__(self, capacity: int = 128, ttl: Optional[float] = None, **kwargs):
|
|
401
|
+
"""Initialize Cachetools LFU cache."""
|
|
402
|
+
if not HAS_CACHETOOLS:
|
|
403
|
+
raise ImportError(
|
|
404
|
+
"cachetools not available. Install with: pip install cachetools"
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
super().__init__(capacity=capacity, ttl=int(ttl) if ttl else None)
|
|
408
|
+
self._cache = CachetoolsLFU(maxsize=capacity)
|
|
409
|
+
self._hits = 0
|
|
410
|
+
self._misses = 0
|
|
411
|
+
self._evictions = 0
|
|
412
|
+
|
|
413
|
+
def get(self, key: Hashable, default: Any = None) -> Any:
|
|
414
|
+
"""Get value from cache."""
|
|
415
|
+
value = self._cache.get(key, default)
|
|
416
|
+
if value is not default:
|
|
417
|
+
self._hits += 1
|
|
418
|
+
else:
|
|
419
|
+
self._misses += 1
|
|
420
|
+
return value
|
|
421
|
+
|
|
422
|
+
def put(self, key: Hashable, value: Any) -> None:
|
|
423
|
+
"""Put value in cache."""
|
|
424
|
+
if len(self._cache) >= self.capacity and key not in self._cache:
|
|
425
|
+
self._evictions += 1
|
|
426
|
+
self._cache[key] = value
|
|
427
|
+
|
|
428
|
+
def delete(self, key: Hashable) -> bool:
|
|
429
|
+
"""Delete key from cache."""
|
|
430
|
+
try:
|
|
431
|
+
del self._cache[key]
|
|
432
|
+
return True
|
|
433
|
+
except KeyError:
|
|
434
|
+
return False
|
|
435
|
+
|
|
436
|
+
def clear(self) -> None:
|
|
437
|
+
"""Clear cache."""
|
|
438
|
+
self._cache.clear()
|
|
439
|
+
self._hits = 0
|
|
440
|
+
self._misses = 0
|
|
441
|
+
self._evictions = 0
|
|
442
|
+
|
|
443
|
+
def size(self) -> int:
|
|
444
|
+
"""Get cache size."""
|
|
445
|
+
return len(self._cache)
|
|
446
|
+
|
|
447
|
+
def is_full(self) -> bool:
|
|
448
|
+
"""Check if cache is full."""
|
|
449
|
+
return len(self._cache) >= self.capacity
|
|
450
|
+
|
|
451
|
+
def evict(self) -> None:
|
|
452
|
+
"""Evict entries (handled automatically)."""
|
|
453
|
+
pass
|
|
454
|
+
|
|
455
|
+
def keys(self) -> list[Hashable]:
|
|
456
|
+
"""Get list of all cache keys."""
|
|
457
|
+
return list(self._cache.keys())
|
|
458
|
+
|
|
459
|
+
def values(self) -> list[Any]:
|
|
460
|
+
"""Get list of all cache values."""
|
|
461
|
+
return list(self._cache.values())
|
|
462
|
+
|
|
463
|
+
def items(self) -> list[tuple[Hashable, Any]]:
|
|
464
|
+
"""Get list of all key-value pairs."""
|
|
465
|
+
return list(self._cache.items())
|
|
466
|
+
|
|
467
|
+
def get_stats(self) -> dict[str, Any]:
|
|
468
|
+
"""Get cache statistics."""
|
|
469
|
+
total = self._hits + self._misses
|
|
470
|
+
hit_rate = (self._hits / total) if total > 0 else 0.0
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
"hits": self._hits,
|
|
474
|
+
"misses": self._misses,
|
|
475
|
+
"evictions": self._evictions,
|
|
476
|
+
"hit_rate": hit_rate,
|
|
477
|
+
"size": self.size(),
|
|
478
|
+
"capacity": self.capacity,
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
# ICache interface compatibility
|
|
482
|
+
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
|
|
483
|
+
"""Set value in cache (ICache interface)."""
|
|
484
|
+
self.put(key, value)
|
|
485
|
+
return True
|
|
486
|
+
|
|
487
|
+
def exists(self, key: str) -> bool:
|
|
488
|
+
"""Check if key exists (ICache interface)."""
|
|
489
|
+
return key in self._cache
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class CachetoolsTTLCache(ACache):
|
|
493
|
+
"""Cachetools TTLCache wrapper."""
|
|
494
|
+
|
|
495
|
+
def __init__(self, capacity: int = 128, ttl: Optional[float] = None, **kwargs):
|
|
496
|
+
"""
|
|
497
|
+
Initialize Cachetools TTL cache.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
capacity: Maximum cache size
|
|
501
|
+
ttl: Time to live in seconds (default: 3600)
|
|
502
|
+
"""
|
|
503
|
+
if not HAS_CACHETOOLS:
|
|
504
|
+
raise ImportError(
|
|
505
|
+
"cachetools not available. Install with: pip install cachetools"
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
# Use provided ttl or default to 3600 seconds
|
|
509
|
+
ttl_value = float(ttl) if ttl else 3600.0
|
|
510
|
+
|
|
511
|
+
super().__init__(capacity=capacity, ttl=int(ttl_value))
|
|
512
|
+
self._cache = CachetoolsTTL(maxsize=capacity, ttl=ttl_value)
|
|
513
|
+
self._hits = 0
|
|
514
|
+
self._misses = 0
|
|
515
|
+
self._evictions = 0
|
|
516
|
+
|
|
517
|
+
def get(self, key: Hashable, default: Any = None) -> Any:
|
|
518
|
+
"""Get value from cache."""
|
|
519
|
+
value = self._cache.get(key, default)
|
|
520
|
+
if value is not default:
|
|
521
|
+
self._hits += 1
|
|
522
|
+
else:
|
|
523
|
+
self._misses += 1
|
|
524
|
+
return value
|
|
525
|
+
|
|
526
|
+
def put(self, key: Hashable, value: Any) -> None:
|
|
527
|
+
"""Put value in cache."""
|
|
528
|
+
if len(self._cache) >= self.capacity and key not in self._cache:
|
|
529
|
+
self._evictions += 1
|
|
530
|
+
self._cache[key] = value
|
|
531
|
+
|
|
532
|
+
def delete(self, key: Hashable) -> bool:
|
|
533
|
+
"""Delete key from cache."""
|
|
534
|
+
try:
|
|
535
|
+
del self._cache[key]
|
|
536
|
+
return True
|
|
537
|
+
except KeyError:
|
|
538
|
+
return False
|
|
539
|
+
|
|
540
|
+
def clear(self) -> None:
|
|
541
|
+
"""Clear cache."""
|
|
542
|
+
self._cache.clear()
|
|
543
|
+
self._hits = 0
|
|
544
|
+
self._misses = 0
|
|
545
|
+
self._evictions = 0
|
|
546
|
+
|
|
547
|
+
def size(self) -> int:
|
|
548
|
+
"""Get cache size."""
|
|
549
|
+
return len(self._cache)
|
|
550
|
+
|
|
551
|
+
def is_full(self) -> bool:
|
|
552
|
+
"""Check if cache is full."""
|
|
553
|
+
return len(self._cache) >= self.capacity
|
|
554
|
+
|
|
555
|
+
def evict(self) -> None:
|
|
556
|
+
"""Evict entries (handled automatically by TTL)."""
|
|
557
|
+
pass
|
|
558
|
+
|
|
559
|
+
def keys(self) -> list[Hashable]:
|
|
560
|
+
"""Get list of all cache keys."""
|
|
561
|
+
return list(self._cache.keys())
|
|
562
|
+
|
|
563
|
+
def values(self) -> list[Any]:
|
|
564
|
+
"""Get list of all cache values."""
|
|
565
|
+
return list(self._cache.values())
|
|
566
|
+
|
|
567
|
+
def items(self) -> list[tuple[Hashable, Any]]:
|
|
568
|
+
"""Get list of all key-value pairs."""
|
|
569
|
+
return list(self._cache.items())
|
|
570
|
+
|
|
571
|
+
def get_stats(self) -> dict[str, Any]:
|
|
572
|
+
"""Get cache statistics."""
|
|
573
|
+
total = self._hits + self._misses
|
|
574
|
+
hit_rate = (self._hits / total) if total > 0 else 0.0
|
|
575
|
+
|
|
576
|
+
return {
|
|
577
|
+
"hits": self._hits,
|
|
578
|
+
"misses": self._misses,
|
|
579
|
+
"evictions": self._evictions,
|
|
580
|
+
"hit_rate": hit_rate,
|
|
581
|
+
"size": self.size(),
|
|
582
|
+
"capacity": self.capacity,
|
|
583
|
+
"ttl": self.ttl,
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
# ICache interface compatibility
|
|
587
|
+
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
|
|
588
|
+
"""Set value in cache (ICache interface)."""
|
|
589
|
+
self.put(key, value)
|
|
590
|
+
return True
|
|
591
|
+
|
|
592
|
+
def exists(self, key: str) -> bool:
|
|
593
|
+
"""Check if key exists (ICache interface)."""
|
|
594
|
+
return key in self._cache
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
class CachetoolsRRCache(ACache):
|
|
598
|
+
"""Cachetools RRCache (Random Replacement) wrapper."""
|
|
599
|
+
|
|
600
|
+
def __init__(self, capacity: int = 128, ttl: Optional[float] = None, **kwargs):
|
|
601
|
+
"""Initialize Cachetools RR cache."""
|
|
602
|
+
if not HAS_CACHETOOLS:
|
|
603
|
+
raise ImportError(
|
|
604
|
+
"cachetools not available. Install with: pip install cachetools"
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
super().__init__(capacity=capacity, ttl=int(ttl) if ttl else None)
|
|
608
|
+
self._cache = CachetoolsRR(maxsize=capacity)
|
|
609
|
+
self._hits = 0
|
|
610
|
+
self._misses = 0
|
|
611
|
+
self._evictions = 0
|
|
612
|
+
|
|
613
|
+
def get(self, key: Hashable, default: Any = None) -> Any:
|
|
614
|
+
"""Get value from cache."""
|
|
615
|
+
value = self._cache.get(key, default)
|
|
616
|
+
if value is not default:
|
|
617
|
+
self._hits += 1
|
|
618
|
+
else:
|
|
619
|
+
self._misses += 1
|
|
620
|
+
return value
|
|
621
|
+
|
|
622
|
+
def put(self, key: Hashable, value: Any) -> None:
|
|
623
|
+
"""Put value in cache."""
|
|
624
|
+
if len(self._cache) >= self.capacity and key not in self._cache:
|
|
625
|
+
self._evictions += 1
|
|
626
|
+
self._cache[key] = value
|
|
627
|
+
|
|
628
|
+
def delete(self, key: Hashable) -> bool:
|
|
629
|
+
"""Delete key from cache."""
|
|
630
|
+
try:
|
|
631
|
+
del self._cache[key]
|
|
632
|
+
return True
|
|
633
|
+
except KeyError:
|
|
634
|
+
return False
|
|
635
|
+
|
|
636
|
+
def clear(self) -> None:
|
|
637
|
+
"""Clear cache."""
|
|
638
|
+
self._cache.clear()
|
|
639
|
+
self._hits = 0
|
|
640
|
+
self._misses = 0
|
|
641
|
+
self._evictions = 0
|
|
642
|
+
|
|
643
|
+
def size(self) -> int:
|
|
644
|
+
"""Get cache size."""
|
|
645
|
+
return len(self._cache)
|
|
646
|
+
|
|
647
|
+
def is_full(self) -> bool:
|
|
648
|
+
"""Check if cache is full."""
|
|
649
|
+
return len(self._cache) >= self.capacity
|
|
650
|
+
|
|
651
|
+
def evict(self) -> None:
|
|
652
|
+
"""Evict entries (handled automatically)."""
|
|
653
|
+
pass
|
|
654
|
+
|
|
655
|
+
def keys(self) -> list[Hashable]:
|
|
656
|
+
"""Get list of all cache keys."""
|
|
657
|
+
return list(self._cache.keys())
|
|
658
|
+
|
|
659
|
+
def values(self) -> list[Any]:
|
|
660
|
+
"""Get list of all cache values."""
|
|
661
|
+
return list(self._cache.values())
|
|
662
|
+
|
|
663
|
+
def items(self) -> list[tuple[Hashable, Any]]:
|
|
664
|
+
"""Get list of all key-value pairs."""
|
|
665
|
+
return list(self._cache.items())
|
|
666
|
+
|
|
667
|
+
def get_stats(self) -> dict[str, Any]:
|
|
668
|
+
"""Get cache statistics."""
|
|
669
|
+
total = self._hits + self._misses
|
|
670
|
+
hit_rate = (self._hits / total) if total > 0 else 0.0
|
|
671
|
+
|
|
672
|
+
return {
|
|
673
|
+
"hits": self._hits,
|
|
674
|
+
"misses": self._misses,
|
|
675
|
+
"evictions": self._evictions,
|
|
676
|
+
"hit_rate": hit_rate,
|
|
677
|
+
"size": self.size(),
|
|
678
|
+
"capacity": self.capacity,
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
# ICache interface compatibility
|
|
682
|
+
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
|
|
683
|
+
"""Set value in cache (ICache interface)."""
|
|
684
|
+
self.put(key, value)
|
|
685
|
+
return True
|
|
686
|
+
|
|
687
|
+
def exists(self, key: str) -> bool:
|
|
688
|
+
"""Check if key exists (ICache interface)."""
|
|
689
|
+
return key in self._cache
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
__all__ = [
|
|
693
|
+
'CacheboxCache',
|
|
694
|
+
'FunctoolsLRUCache',
|
|
695
|
+
'CachetoolsLRUCache',
|
|
696
|
+
'CachetoolsLFUCache',
|
|
697
|
+
'CachetoolsTTLCache',
|
|
698
|
+
'CachetoolsRRCache',
|
|
699
|
+
'HAS_CACHEBOX',
|
|
700
|
+
'HAS_CACHETOOLS',
|
|
701
|
+
]
|