tellaro-query-language 0.2.2__py3-none-any.whl → 0.2.5__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.
- tellaro_query_language-0.2.5.dist-info/LICENSE +72 -0
- tellaro_query_language-0.2.5.dist-info/METADATA +806 -0
- {tellaro_query_language-0.2.2.dist-info → tellaro_query_language-0.2.5.dist-info}/RECORD +25 -22
- {tellaro_query_language-0.2.2.dist-info → tellaro_query_language-0.2.5.dist-info}/entry_points.txt +1 -0
- tql/__init__.py +1 -1
- tql/cache/base.py +79 -7
- tql/cache/memory.py +126 -18
- tql/cli.py +484 -0
- tql/core.py +261 -5
- tql/core_components/opensearch_operations.py +23 -4
- tql/evaluator.py +3 -1
- tql/evaluator_components/special_expressions.py +62 -10
- tql/evaluator_components/value_comparison.py +70 -12
- tql/exceptions.py +6 -4
- tql/field_type_inference.py +285 -0
- tql/mutator_analyzer.py +2 -2
- tql/mutators/geo.py +57 -20
- tql/opensearch_components/query_converter.py +1 -1
- tql/opensearch_stats.py +10 -7
- tql/parser.py +56 -21
- tql/post_processor.py +44 -11
- tql/scripts.py +19 -2
- tql/stats_evaluator.py +361 -7
- tql/streaming_file_processor.py +335 -0
- tellaro_query_language-0.2.2.dist-info/LICENSE +0 -21
- tellaro_query_language-0.2.2.dist-info/METADATA +0 -433
- {tellaro_query_language-0.2.2.dist-info → tellaro_query_language-0.2.5.dist-info}/WHEEL +0 -0
|
@@ -1,30 +1,32 @@
|
|
|
1
|
-
tql/__init__.py,sha256=
|
|
1
|
+
tql/__init__.py,sha256=eqti5Fmu8EjD-NbCwqb1UKGJQ0OpWJLREsVMqqn6Hs4,1260
|
|
2
2
|
tql/analyzer.py,sha256=Sfzj6f7YzqylT8HIL9hDbXdhl0lf8q8DNoafrxkD-F8,15456
|
|
3
3
|
tql/cache/__init__.py,sha256=GIzIEMZUZEYJj72sAhuVLEG-OJEKUG2srUWNM3Ix-T8,213
|
|
4
|
-
tql/cache/base.py,sha256=
|
|
5
|
-
tql/cache/memory.py,sha256=
|
|
4
|
+
tql/cache/base.py,sha256=CwLpobv4WR7WSz99JVWAHNn-XQTtqr38Yg5UiWNXPiA,3192
|
|
5
|
+
tql/cache/memory.py,sha256=4nKFvq8SQSzht4JjVgml4MiEFk5pJmTCH6tHO8vwnrI,5978
|
|
6
6
|
tql/cache/redis.py,sha256=ZU_IsVDvpSYpNvPfnZ4iulJDODpEGx3c4dkXLzPzPVc,2309
|
|
7
|
-
tql/
|
|
7
|
+
tql/cli.py,sha256=dxvYvq0TmLWS5vHAkhdgTUlJK42vORjH8ttNkjIcgqM,15257
|
|
8
|
+
tql/core.py,sha256=_OlFGTrvJ8cBz3OliRxSz-IbD6e1t_nYC5YZFVkOAfc,58413
|
|
8
9
|
tql/core_components/README.md,sha256=Rm7w4UHdQ0vPBEFybE5b62IOvSA5Nzq2GRvtBHOapmc,3068
|
|
9
10
|
tql/core_components/__init__.py,sha256=v8BBybPlqV7dkVY9mw1mblvqyAFJZ7Pf_bEc-jAL7FI,643
|
|
10
11
|
tql/core_components/file_operations.py,sha256=Jr0kkxz_OP2KHOAsIr7KMtYe_lbu8LuBUySt2LQbjJw,3925
|
|
11
|
-
tql/core_components/opensearch_operations.py,sha256=
|
|
12
|
+
tql/core_components/opensearch_operations.py,sha256=zgxGiDpXyPW0ZUX-StpZXxf84s8eLxSymAGM5UUJimk,55253
|
|
12
13
|
tql/core_components/stats_operations.py,sha256=aqTGAqIFvR6EkSbJEd0qft8Ldy8uiTrK2XI9o5bZUOs,8014
|
|
13
14
|
tql/core_components/validation_operations.py,sha256=_VPXh0HABBjsXF99jFT7B6-5QAPsADOCy6poinGrxeE,22454
|
|
14
|
-
tql/evaluator.py,sha256=
|
|
15
|
+
tql/evaluator.py,sha256=6BtC0njH_aR_lXiU6GU5vM5MRhQeSoxL7F95xh-2-ho,17903
|
|
15
16
|
tql/evaluator_components/README.md,sha256=c59yf2au34yPhrru7JWgGop_ORteB6w5vfMhsac8j3k,3882
|
|
16
17
|
tql/evaluator_components/__init__.py,sha256=DourRUSYXWPnCghBFj7W0YfMeymT3X8YTDCwnLIyP1c,535
|
|
17
18
|
tql/evaluator_components/field_access.py,sha256=BuXvL9jlv4H77neT70Vh7_qokmzs-d4EbSDA2FB1IT0,6435
|
|
18
|
-
tql/evaluator_components/special_expressions.py,sha256=
|
|
19
|
-
tql/evaluator_components/value_comparison.py,sha256=
|
|
20
|
-
tql/exceptions.py,sha256=
|
|
19
|
+
tql/evaluator_components/special_expressions.py,sha256=prhXnVRnFfmecgmuTz0fsefTA1clb2eyyYf-zPtzXGs,15703
|
|
20
|
+
tql/evaluator_components/value_comparison.py,sha256=a0Vo3BWyPxMtEgAKtUuaN0HN9Arc0A7BUVrxgZyH6_o,21200
|
|
21
|
+
tql/exceptions.py,sha256=GVssdBp9134Wyk1bWbcLQFU9U8yQKl5zzquTTrM22A0,5620
|
|
22
|
+
tql/field_type_inference.py,sha256=KOazjp8CK6s9vwOcFkQrdOwcazOwHqSIhYgX8hWCiDo,9700
|
|
21
23
|
tql/geoip_normalizer.py,sha256=tvie-5xevJEeLp2KmjoXDjYdND8AvyVE7lCO8qgUzGY,10486
|
|
22
|
-
tql/mutator_analyzer.py,sha256=
|
|
24
|
+
tql/mutator_analyzer.py,sha256=OWx3k5lK5aFHWU9Ez6DaIhenEZDxj9CbB0vM71xqUTw,55670
|
|
23
25
|
tql/mutators/__init__.py,sha256=eTK8sRw4KXXnTZTn5ETIqwcaIek5rSUIVyZsxTwNNHA,6966
|
|
24
26
|
tql/mutators/base.py,sha256=4Ze_x1sTO11OILXfcF2XN7ttyHcZ4gwn96UXFMMaC6M,2523
|
|
25
27
|
tql/mutators/dns.py,sha256=1IKgHolFLRMR4TOgK0AiLjz5vDtFiqO328mVF4Vzk3s,14428
|
|
26
28
|
tql/mutators/encoding.py,sha256=yt12BJrHAIJfBesP8VOSfVlvJqB1yOmEeT_8QDPvNN8,7985
|
|
27
|
-
tql/mutators/geo.py,sha256=
|
|
29
|
+
tql/mutators/geo.py,sha256=H-_5oDvuYaAG8Re17RkGjzCc6Z07YHd7Cr95g6JbnyE,16188
|
|
28
30
|
tql/mutators/list.py,sha256=949ZrKKhL4INkH2Od8bq7Ey80kFX_23PEfRKueG82cU,7084
|
|
29
31
|
tql/mutators/network.py,sha256=1lZpmKt1GoTfNxiXUmSXkTwJIzPQZnQEgU7ojpBSm3A,5458
|
|
30
32
|
tql/mutators/security.py,sha256=XyWuPxgpCi-igHKmkbP0_0V-evOc3FG2a1igY8rQRX4,9256
|
|
@@ -34,23 +36,24 @@ tql/opensearch_components/README.md,sha256=gt-qLmmach8Kh7-QwLZmoAxxIL79XIG1EDqJu
|
|
|
34
36
|
tql/opensearch_components/__init__.py,sha256=_zIZY8Fns7mkEcY6w2p9FNRBXtEmmPFFJEcFRfrVyXA,514
|
|
35
37
|
tql/opensearch_components/field_mapping.py,sha256=fj388cKVyDXLJKi8giSiGHL9zg4cFRzy0VJ6nIsppSo,18102
|
|
36
38
|
tql/opensearch_components/lucene_converter.py,sha256=OvYTZHNBktPGow1fsVm4TMlvxHSmWrnqo42lFZNxXTo,13175
|
|
37
|
-
tql/opensearch_components/query_converter.py,sha256=
|
|
39
|
+
tql/opensearch_components/query_converter.py,sha256=INjX6hd-1dlCdCn_dGSBnub2mpNyUBpHXhHA5WoBQX4,41985
|
|
38
40
|
tql/opensearch_mappings.py,sha256=sVLlQlE3eGD7iNNZ_m4F4j5GVzQAJhZyCqDKYRhLRh8,11531
|
|
39
|
-
tql/opensearch_stats.py,sha256=
|
|
40
|
-
tql/parser.py,sha256=
|
|
41
|
+
tql/opensearch_stats.py,sha256=sxJ4KziV-Yv1kvjo22souxjBQH3chmlm4lAgEhRBtyA,24530
|
|
42
|
+
tql/parser.py,sha256=y4LKYuNqE74Xx5UpHZBZE6PlVaRBiwr5i49NeMJW-jU,80383
|
|
41
43
|
tql/parser_components/README.md,sha256=lvQX72ckq2zyotGs8QIHHCIFqaA7bOHwkP44wU8Zoiw,2322
|
|
42
44
|
tql/parser_components/__init__.py,sha256=zBwHBMPJyHSBbaOojf6qTrJYjJg5A6tPUE8nHFdRiQs,521
|
|
43
45
|
tql/parser_components/ast_builder.py,sha256=erHoeKAMzobswoRIXB9xcsZbzQ5-2ZwaYfQgRWoUAa8,9653
|
|
44
46
|
tql/parser_components/error_analyzer.py,sha256=qlCD9vKyW73aeKQYI33P1OjIWSJ3LPd08wuN9cis2fU,4012
|
|
45
47
|
tql/parser_components/field_extractor.py,sha256=eUEkmiYWX2OexanFqhHeX8hcIkRlfIcgMB667e0HRYs,4629
|
|
46
48
|
tql/parser_components/grammar.py,sha256=h58RBshZHXgbP1EmNwmf7dny-fgVloNg-qN4Rivross,20599
|
|
47
|
-
tql/post_processor.py,sha256=
|
|
48
|
-
tql/scripts.py,sha256=
|
|
49
|
-
tql/stats_evaluator.py,sha256=
|
|
49
|
+
tql/post_processor.py,sha256=5w_rP0V-t3AC7iAFLnlDxUtawcDFovbhbRsoZxt9yP4,51787
|
|
50
|
+
tql/scripts.py,sha256=DUY0H5IoGs_CNdG_oxITvLiCNVsogb2RJqUs2xXOs24,4319
|
|
51
|
+
tql/stats_evaluator.py,sha256=2qnjeH5Qx14qpHDS_YJn9jRPeoPUfkeiYJabBagdfRs,36126
|
|
50
52
|
tql/stats_transformer.py,sha256=MT-4rDWZSySgn4Fuq9H0c-mvwFYLM6FqWpPv2rHX-rE,7588
|
|
53
|
+
tql/streaming_file_processor.py,sha256=cftWhYcvUo984P3ALf2CO3FoCQPJPe_2s2HLcXTp5UQ,12437
|
|
51
54
|
tql/validators.py,sha256=e9MlX-zQ_O3M8YP8vXyMjKU8iiJMTh6mMK0iv0_4gTY,3771
|
|
52
|
-
tellaro_query_language-0.2.
|
|
53
|
-
tellaro_query_language-0.2.
|
|
54
|
-
tellaro_query_language-0.2.
|
|
55
|
-
tellaro_query_language-0.2.
|
|
56
|
-
tellaro_query_language-0.2.
|
|
55
|
+
tellaro_query_language-0.2.5.dist-info/LICENSE,sha256=eWf8lkuXlVX_8WiDpUgQvzxc1cxCeVne_e6P-pVJpwM,3038
|
|
56
|
+
tellaro_query_language-0.2.5.dist-info/METADATA,sha256=HCTN5lDkKfutCPvcLYTQztHwW1G4qbo2LP8cYFRayZM,21857
|
|
57
|
+
tellaro_query_language-0.2.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
58
|
+
tellaro_query_language-0.2.5.dist-info/entry_points.txt,sha256=D0lbIGUYuDyfcYeqju1rWcMBFzft4sZtfIlw5uPNx5g,181
|
|
59
|
+
tellaro_query_language-0.2.5.dist-info/RECORD,,
|
tql/__init__.py
CHANGED
tql/cache/base.py
CHANGED
|
@@ -1,25 +1,97 @@
|
|
|
1
|
-
"""Base cache infrastructure.
|
|
1
|
+
"""Base cache infrastructure for TQL.
|
|
2
|
+
|
|
3
|
+
This module provides the base CacheManager class that defines the caching
|
|
4
|
+
interface used throughout TQL. Concrete implementations include LocalCacheManager
|
|
5
|
+
for in-memory caching and RedisCacheManager for distributed caching.
|
|
6
|
+
"""
|
|
2
7
|
|
|
3
8
|
from typing import Any, Dict, Optional
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
class CacheManager:
|
|
7
|
-
"""Base class for cache management.
|
|
12
|
+
"""Base class for cache management.
|
|
13
|
+
|
|
14
|
+
This class defines the interface for all cache implementations in TQL.
|
|
15
|
+
Subclasses should override these methods to provide actual caching functionality.
|
|
16
|
+
|
|
17
|
+
The base implementation provides no-op defaults that can be safely used when
|
|
18
|
+
caching is disabled or not needed.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
>>> cache = LocalCacheManager()
|
|
22
|
+
>>> cache.set("user:123", {"name": "Alice", "age": 30}, ttl=3600)
|
|
23
|
+
>>> user = cache.get("user:123")
|
|
24
|
+
>>> cache.delete("user:123")
|
|
25
|
+
"""
|
|
8
26
|
|
|
9
27
|
def get(self, key: str) -> Optional[Any]:
|
|
10
|
-
"""Retrieve value from cache.
|
|
28
|
+
"""Retrieve a value from the cache.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
key: The cache key to look up. Should be a string identifier.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
The cached value if it exists and hasn't expired, None otherwise.
|
|
35
|
+
|
|
36
|
+
Example:
|
|
37
|
+
>>> value = cache.get("my_key")
|
|
38
|
+
>>> if value is not None:
|
|
39
|
+
... print(f"Found: {value}")
|
|
40
|
+
"""
|
|
11
41
|
return None
|
|
12
42
|
|
|
13
43
|
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
|
|
14
|
-
"""Store value in cache.
|
|
44
|
+
"""Store a value in the cache.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
key: The cache key under which to store the value.
|
|
48
|
+
value: The value to cache. Can be any Python object.
|
|
49
|
+
ttl: Time-to-live in seconds. If None or 0, the value never expires.
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
>>> cache.set("config", {"debug": True}, ttl=300) # Cache for 5 minutes
|
|
53
|
+
>>> cache.set("permanent", {"version": "1.0"}) # Never expires
|
|
54
|
+
"""
|
|
15
55
|
|
|
16
56
|
def delete(self, key: str) -> None:
|
|
17
|
-
"""Remove value from cache.
|
|
57
|
+
"""Remove a value from the cache.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
key: The cache key to delete.
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
>>> cache.delete("expired_key")
|
|
64
|
+
"""
|
|
18
65
|
|
|
19
66
|
def clear_pattern(self, pattern: str) -> int: # pylint: disable=unused-argument
|
|
20
|
-
"""Clear all keys matching pattern.
|
|
67
|
+
"""Clear all keys matching a pattern.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
pattern: A pattern string to match keys. Format depends on implementation.
|
|
71
|
+
For Redis: supports wildcards like "user:*" or "session:?123"
|
|
72
|
+
For Local: basic string matching
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
The number of keys that were deleted.
|
|
76
|
+
|
|
77
|
+
Example:
|
|
78
|
+
>>> count = cache.clear_pattern("temp:*")
|
|
79
|
+
>>> print(f"Cleared {count} temporary keys")
|
|
80
|
+
"""
|
|
21
81
|
return 0
|
|
22
82
|
|
|
23
83
|
def get_stats(self) -> Dict[str, Any]:
|
|
24
|
-
"""Get cache statistics.
|
|
84
|
+
"""Get cache statistics and metrics.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Dictionary containing cache statistics such as:
|
|
88
|
+
- hit_rate: Cache hit rate percentage
|
|
89
|
+
- miss_rate: Cache miss rate percentage
|
|
90
|
+
- size: Number of items in cache
|
|
91
|
+
- memory_usage: Memory used by cache (if available)
|
|
92
|
+
|
|
93
|
+
Example:
|
|
94
|
+
>>> stats = cache.get_stats()
|
|
95
|
+
>>> print(f"Hit rate: {stats.get('hit_rate', 0)}%")
|
|
96
|
+
"""
|
|
25
97
|
return {}
|
tql/cache/memory.py
CHANGED
|
@@ -1,63 +1,171 @@
|
|
|
1
|
-
"""In-memory cache implementation.
|
|
1
|
+
"""In-memory cache implementation for TQL.
|
|
2
|
+
|
|
3
|
+
This module provides a simple in-memory cache with TTL (time-to-live) support
|
|
4
|
+
and basic LRU (Least Recently Used) eviction when the cache reaches its size limit.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
import time
|
|
4
|
-
from typing import Any, Dict, Optional
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
5
9
|
|
|
6
10
|
from .base import CacheManager
|
|
7
11
|
|
|
8
12
|
|
|
9
13
|
class LocalCacheManager(CacheManager):
|
|
10
|
-
"""Local in-memory cache
|
|
14
|
+
"""Local in-memory cache with TTL and LRU eviction.
|
|
15
|
+
|
|
16
|
+
This implementation provides thread-safe in-memory caching suitable for
|
|
17
|
+
single-process applications. For distributed caching across multiple
|
|
18
|
+
processes or servers, use RedisCacheManager instead.
|
|
19
|
+
|
|
20
|
+
Features:
|
|
21
|
+
- TTL-based expiration
|
|
22
|
+
- LRU eviction when cache is full
|
|
23
|
+
- Hit/miss statistics tracking
|
|
24
|
+
- Pattern-based key clearing
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
max_size: Maximum number of items to store (default: 10000)
|
|
28
|
+
default_ttl: Default time-to-live in seconds (default: 3600 = 1 hour)
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
>>> cache = LocalCacheManager(max_size=1000, default_ttl=600)
|
|
32
|
+
>>> cache.set("user:123", {"name": "Alice"}, ttl=300)
|
|
33
|
+
>>> user = cache.get("user:123")
|
|
34
|
+
>>> stats = cache.get_stats()
|
|
35
|
+
>>> print(f"Hit rate: {stats['hit_rate']:.2%}")
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
max_size: Maximum cache size
|
|
39
|
+
default_ttl: Default TTL for cached items
|
|
40
|
+
"""
|
|
11
41
|
|
|
12
42
|
def __init__(self, max_size: int = 10000, default_ttl: int = 3600):
|
|
43
|
+
"""Initialize the local cache.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
max_size: Maximum number of items to cache before eviction starts.
|
|
47
|
+
default_ttl: Default expiration time in seconds for cached items.
|
|
48
|
+
"""
|
|
13
49
|
self.max_size = max_size
|
|
14
50
|
self.default_ttl = default_ttl
|
|
15
|
-
self._cache: Dict[str,
|
|
51
|
+
self._cache: Dict[str, Any] = {}
|
|
52
|
+
self._expiry: Dict[str, float] = {}
|
|
16
53
|
self._hits = 0
|
|
17
54
|
self._misses = 0
|
|
18
55
|
|
|
19
56
|
def get(self, key: str) -> Optional[Any]:
|
|
20
|
-
"""Retrieve value from cache if not expired.
|
|
57
|
+
"""Retrieve value from cache if not expired.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
key: The cache key to retrieve.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
The cached value if present and not expired, None otherwise.
|
|
64
|
+
|
|
65
|
+
Note:
|
|
66
|
+
This method automatically removes expired keys when accessed.
|
|
67
|
+
Hit/miss statistics are updated on each call.
|
|
68
|
+
"""
|
|
21
69
|
if key in self._cache:
|
|
22
|
-
|
|
23
|
-
if expiry > time.time():
|
|
70
|
+
expiry = self._expiry.get(key, float("inf"))
|
|
71
|
+
if expiry == 0 or expiry > time.time():
|
|
24
72
|
self._hits += 1
|
|
25
|
-
return
|
|
73
|
+
return self._cache[key]
|
|
26
74
|
else:
|
|
27
|
-
# Expired
|
|
75
|
+
# Expired - clean up
|
|
28
76
|
del self._cache[key]
|
|
77
|
+
del self._expiry[key]
|
|
29
78
|
self._misses += 1
|
|
30
79
|
return None
|
|
31
80
|
|
|
32
81
|
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
|
|
33
|
-
"""Store value in cache with TTL.
|
|
34
|
-
|
|
35
|
-
|
|
82
|
+
"""Store value in cache with optional TTL.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
key: The cache key under which to store the value.
|
|
86
|
+
value: The value to cache (any Python object).
|
|
87
|
+
ttl: Time-to-live in seconds. If None, uses default_ttl.
|
|
88
|
+
If 0, the item never expires.
|
|
89
|
+
|
|
90
|
+
Note:
|
|
91
|
+
When the cache is full (reaches max_size), the oldest item
|
|
92
|
+
is evicted to make room for the new one (LRU eviction).
|
|
93
|
+
"""
|
|
94
|
+
if len(self._cache) >= self.max_size and key not in self._cache:
|
|
95
|
+
# Simple eviction: remove oldest (first in dict)
|
|
36
96
|
oldest_key = next(iter(self._cache))
|
|
37
97
|
del self._cache[oldest_key]
|
|
98
|
+
self._expiry.pop(oldest_key, None)
|
|
38
99
|
|
|
39
|
-
|
|
40
|
-
|
|
100
|
+
self._cache[key] = value
|
|
101
|
+
if ttl == 0:
|
|
102
|
+
# Never expires
|
|
103
|
+
self._expiry[key] = 0
|
|
104
|
+
else:
|
|
105
|
+
expiry_time = time.time() + (ttl if ttl is not None else self.default_ttl)
|
|
106
|
+
self._expiry[key] = expiry_time
|
|
41
107
|
|
|
42
108
|
def delete(self, key: str) -> None:
|
|
43
|
-
"""Remove value from cache.
|
|
109
|
+
"""Remove value from cache.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
key: The cache key to delete.
|
|
113
|
+
|
|
114
|
+
Note:
|
|
115
|
+
If the key doesn't exist, this method does nothing (no error raised).
|
|
116
|
+
"""
|
|
44
117
|
self._cache.pop(key, None)
|
|
118
|
+
self._expiry.pop(key, None)
|
|
45
119
|
|
|
46
120
|
def clear_pattern(self, pattern: str) -> int:
|
|
47
|
-
"""Clear all keys matching pattern.
|
|
121
|
+
"""Clear all keys matching a glob pattern.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
pattern: A glob pattern to match keys. Supports wildcards:
|
|
125
|
+
- '*' matches any sequence of characters
|
|
126
|
+
- '?' matches any single character
|
|
127
|
+
- '[seq]' matches any character in seq
|
|
128
|
+
- '[!seq]' matches any character not in seq
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
The number of keys that were deleted.
|
|
132
|
+
|
|
133
|
+
Example:
|
|
134
|
+
>>> cache.set("user:123", data1)
|
|
135
|
+
>>> cache.set("user:456", data2)
|
|
136
|
+
>>> cache.set("session:789", data3)
|
|
137
|
+
>>> count = cache.clear_pattern("user:*") # Deletes user:123 and user:456
|
|
138
|
+
>>> print(count) # 2
|
|
139
|
+
"""
|
|
48
140
|
import fnmatch
|
|
49
141
|
|
|
50
142
|
keys_to_delete = [k for k in self._cache.keys() if fnmatch.fnmatch(k, pattern)]
|
|
51
143
|
for key in keys_to_delete:
|
|
52
144
|
del self._cache[key]
|
|
145
|
+
self._expiry.pop(key, None)
|
|
53
146
|
return len(keys_to_delete)
|
|
54
147
|
|
|
55
148
|
def get_stats(self) -> Dict[str, Any]:
|
|
56
|
-
"""Get cache statistics.
|
|
149
|
+
"""Get cache performance statistics.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Dictionary containing:
|
|
153
|
+
- hits: Number of successful cache retrievals
|
|
154
|
+
- misses: Number of cache misses
|
|
155
|
+
- hit_rate: Ratio of hits to total requests (0.0 to 1.0)
|
|
156
|
+
- size: Current number of items in cache
|
|
157
|
+
- max_size: Maximum cache capacity
|
|
158
|
+
|
|
159
|
+
Example:
|
|
160
|
+
>>> stats = cache.get_stats()
|
|
161
|
+
>>> print(f"Cache is {stats['hit_rate']:.2%} effective")
|
|
162
|
+
>>> print(f"Using {stats['size']}/{stats['max_size']} slots")
|
|
163
|
+
"""
|
|
164
|
+
total_requests = self._hits + self._misses
|
|
57
165
|
return {
|
|
58
166
|
"hits": self._hits,
|
|
59
167
|
"misses": self._misses,
|
|
60
|
-
"hit_rate": self._hits /
|
|
168
|
+
"hit_rate": self._hits / total_requests if total_requests > 0 else 0.0,
|
|
61
169
|
"size": len(self._cache),
|
|
62
170
|
"max_size": self.max_size,
|
|
63
171
|
}
|