thds.core 1.44.20250728214458__py3-none-any.whl → 1.44.20250730172116__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.
Potentially problematic release.
This version of thds.core might be problematic. Click here for more details.
- thds/core/cache.py +18 -18
- {thds_core-1.44.20250728214458.dist-info → thds_core-1.44.20250730172116.dist-info}/METADATA +1 -1
- {thds_core-1.44.20250728214458.dist-info → thds_core-1.44.20250730172116.dist-info}/RECORD +6 -6
- {thds_core-1.44.20250728214458.dist-info → thds_core-1.44.20250730172116.dist-info}/WHEEL +0 -0
- {thds_core-1.44.20250728214458.dist-info → thds_core-1.44.20250730172116.dist-info}/entry_points.txt +0 -0
- {thds_core-1.44.20250728214458.dist-info → thds_core-1.44.20250730172116.dist-info}/top_level.txt +0 -0
thds/core/cache.py
CHANGED
|
@@ -12,7 +12,7 @@ else: # pragma: no cover
|
|
|
12
12
|
from typing_extensions import ParamSpec
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
class
|
|
15
|
+
class HashedTuple(tuple):
|
|
16
16
|
"""A tuple that ensures that `hash` will be called no more than once
|
|
17
17
|
per element, since cache decorators will hash the key multiple
|
|
18
18
|
times on a cache miss. See also `_HashedSeq` in the standard
|
|
@@ -27,11 +27,11 @@ class _HashedTuple(tuple):
|
|
|
27
27
|
self.__hashvalue = hashvalue = hash(self)
|
|
28
28
|
return hashvalue
|
|
29
29
|
|
|
30
|
-
def __add__(self, other, add=tuple.__add__) -> "
|
|
31
|
-
return
|
|
30
|
+
def __add__(self, other, add=tuple.__add__) -> "HashedTuple":
|
|
31
|
+
return HashedTuple(add(self, other))
|
|
32
32
|
|
|
33
|
-
def __radd__(self, other, add=tuple.__add__) -> "
|
|
34
|
-
return
|
|
33
|
+
def __radd__(self, other, add=tuple.__add__) -> "HashedTuple":
|
|
34
|
+
return HashedTuple(add(other, self))
|
|
35
35
|
|
|
36
36
|
def __getstate__(self) -> ty.Dict:
|
|
37
37
|
return {}
|
|
@@ -39,23 +39,23 @@ class _HashedTuple(tuple):
|
|
|
39
39
|
|
|
40
40
|
# used for separating keyword arguments; we do not use an object
|
|
41
41
|
# instance here so identity is preserved when pickling/unpickling
|
|
42
|
-
_kwmark = (
|
|
42
|
+
_kwmark = (HashedTuple,)
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def hashkey(args: tuple, kwargs: ty.Mapping) ->
|
|
45
|
+
def hashkey(args: tuple, kwargs: ty.Mapping) -> HashedTuple:
|
|
46
46
|
"""Return a cache key for the specified hashable arguments."""
|
|
47
47
|
|
|
48
48
|
if kwargs:
|
|
49
|
-
return
|
|
49
|
+
return HashedTuple(args + sum(sorted(kwargs.items()), _kwmark))
|
|
50
50
|
else:
|
|
51
|
-
return
|
|
51
|
+
return HashedTuple(args)
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
# above keying code borrowed from `cachetools`: https://github.com/tkem/cachetools/tree/master
|
|
55
55
|
# I have added some type information
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
def make_bound_hashkey(func: ty.Callable) -> ty.Callable[...,
|
|
58
|
+
def make_bound_hashkey(func: ty.Callable) -> ty.Callable[..., HashedTuple]:
|
|
59
59
|
"""Makes a hashkey function that binds its `*args, **kwargs` to the function signature of `func`.
|
|
60
60
|
|
|
61
61
|
The resulting bound hashkey function makes cache keys that are robust to variations in how arguments are passed to
|
|
@@ -63,7 +63,7 @@ def make_bound_hashkey(func: ty.Callable) -> ty.Callable[..., _HashedTuple]:
|
|
|
63
63
|
"""
|
|
64
64
|
signature = inspect.signature(func)
|
|
65
65
|
|
|
66
|
-
def bound_hashkey(args: tuple, kwargs: ty.Mapping) ->
|
|
66
|
+
def bound_hashkey(args: tuple, kwargs: ty.Mapping) -> HashedTuple:
|
|
67
67
|
bound_arguments = signature.bind(*args, **kwargs)
|
|
68
68
|
bound_arguments.apply_defaults()
|
|
69
69
|
return hashkey(bound_arguments.args, bound_arguments.kwargs)
|
|
@@ -85,11 +85,11 @@ _R = ty.TypeVar("_R")
|
|
|
85
85
|
|
|
86
86
|
def _locking_factory(
|
|
87
87
|
cache_lock: proto.ContextManager,
|
|
88
|
-
make_func_lock: ty.Callable[[
|
|
88
|
+
make_func_lock: ty.Callable[[HashedTuple], proto.ContextManager],
|
|
89
89
|
) -> ty.Callable[[ty.Callable[_P, _R]], ty.Callable[_P, _R]]:
|
|
90
90
|
def decorator(func: ty.Callable[_P, _R]) -> ty.Callable[_P, _R]:
|
|
91
|
-
cache: ty.Dict[
|
|
92
|
-
keys_to_func_locks: ty.Dict[
|
|
91
|
+
cache: ty.Dict[HashedTuple, _R] = {}
|
|
92
|
+
keys_to_func_locks: ty.Dict[HashedTuple, proto.ContextManager] = {}
|
|
93
93
|
hits = misses = 0
|
|
94
94
|
bound_hashkey = make_bound_hashkey(func)
|
|
95
95
|
sentinel = ty.cast(_R, object()) # unique object used to signal cache misses
|
|
@@ -120,7 +120,7 @@ def _locking_factory(
|
|
|
120
120
|
result = func(*args, **kwargs)
|
|
121
121
|
cache[key] = result
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
keys_to_func_locks.pop(key, None) # this allows for the use of reentrant locks
|
|
124
124
|
return result
|
|
125
125
|
|
|
126
126
|
def cache_info() -> _CacheInfo:
|
|
@@ -154,7 +154,7 @@ def locking(
|
|
|
154
154
|
func: None = ...,
|
|
155
155
|
*,
|
|
156
156
|
cache_lock: ty.Optional[proto.ContextManager] = ...,
|
|
157
|
-
make_func_lock: ty.Optional[ty.Callable[[
|
|
157
|
+
make_func_lock: ty.Optional[ty.Callable[[HashedTuple], proto.ContextManager]] = ...,
|
|
158
158
|
) -> ty.Callable[[ty.Callable[_P, _R]], ty.Callable[_P, _R]]:
|
|
159
159
|
... # pragma: no cover
|
|
160
160
|
|
|
@@ -167,7 +167,7 @@ def locking(
|
|
|
167
167
|
func: ty.Optional[ty.Callable[_P, _R]] = None,
|
|
168
168
|
*,
|
|
169
169
|
cache_lock: ty.Optional[proto.ContextManager] = None,
|
|
170
|
-
make_func_lock: ty.Optional[ty.Callable[[
|
|
170
|
+
make_func_lock: ty.Optional[ty.Callable[[HashedTuple], proto.ContextManager]] = None,
|
|
171
171
|
):
|
|
172
172
|
"""A threadsafe, simple, unbounded cache.
|
|
173
173
|
|
|
@@ -189,7 +189,7 @@ def locking(
|
|
|
189
189
|
usage that is not worth the cost.
|
|
190
190
|
"""
|
|
191
191
|
|
|
192
|
-
def default_make_func_lock(_key:
|
|
192
|
+
def default_make_func_lock(_key: HashedTuple) -> threading.Lock:
|
|
193
193
|
return threading.Lock()
|
|
194
194
|
|
|
195
195
|
decorator = _locking_factory(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
thds/core/__init__.py,sha256=p5ZTz0yURvtiJlUspnI6aMb9nIekTkzU8sqr8HrnyiM,968
|
|
2
2
|
thds/core/ansi_esc.py,sha256=QZ3CptZbX4N_hyP2IgqfTbNt9tBPaqy7ReTMQIzGbrc,870
|
|
3
|
-
thds/core/cache.py,sha256=
|
|
3
|
+
thds/core/cache.py,sha256=VGotQHrwxotgWL91oisQbK0fIxvp_5okA4tDQmnc-y0,7188
|
|
4
4
|
thds/core/calgitver.py,sha256=6ioH5MGE65l_Dp924oD5CWrLyxKgmhtn46YwGxFpHfM,2497
|
|
5
5
|
thds/core/cm.py,sha256=WZB8eQU0DaBYj9s97nc3PuCtai9guovfyiQH68zhLzY,1086
|
|
6
6
|
thds/core/concurrency.py,sha256=NQunF_tJ_z8cfVyhzkTPlb-nZrgu-vIk9_3XffgscKQ,3520
|
|
@@ -73,8 +73,8 @@ thds/core/sqlite/structured.py,sha256=SvZ67KcVcVdmpR52JSd52vMTW2ALUXmlHEeD-VrzWV
|
|
|
73
73
|
thds/core/sqlite/types.py,sha256=oUkfoKRYNGDPZRk29s09rc9ha3SCk2SKr_K6WKebBFs,1308
|
|
74
74
|
thds/core/sqlite/upsert.py,sha256=BmKK6fsGVedt43iY-Lp7dnAu8aJ1e9CYlPVEQR2pMj4,5827
|
|
75
75
|
thds/core/sqlite/write.py,sha256=z0219vDkQDCnsV0WLvsj94keItr7H4j7Y_evbcoBrWU,3458
|
|
76
|
-
thds_core-1.44.
|
|
77
|
-
thds_core-1.44.
|
|
78
|
-
thds_core-1.44.
|
|
79
|
-
thds_core-1.44.
|
|
80
|
-
thds_core-1.44.
|
|
76
|
+
thds_core-1.44.20250730172116.dist-info/METADATA,sha256=Yv8xV6o0RXAO6pA6E831iY7JMQrNoZ_szLCmjZxWYss,2216
|
|
77
|
+
thds_core-1.44.20250730172116.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
78
|
+
thds_core-1.44.20250730172116.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
|
|
79
|
+
thds_core-1.44.20250730172116.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
|
|
80
|
+
thds_core-1.44.20250730172116.dist-info/RECORD,,
|
|
File without changes
|
{thds_core-1.44.20250728214458.dist-info → thds_core-1.44.20250730172116.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{thds_core-1.44.20250728214458.dist-info → thds_core-1.44.20250730172116.dist-info}/top_level.txt
RENAMED
|
File without changes
|