Skip to content

Commit 81232fc

Browse files
authored
Merge pull request #119 from DavidCEllis/test-freethreaded
Add free-threaded build to tests on 3.15, add locks around statistic increases.
2 parents 87d38cc + d567807 commit 81232fc

3 files changed

Lines changed: 38 additions & 10 deletions

File tree

.github/workflows/auto_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
fail-fast: false
1717
matrix:
1818
os: [ubuntu-latest]
19-
python-version: ["3.15-dev", "3.14", "3.13", "3.12"]
19+
python-version: ["3.15-dev", "3.15t-dev", "3.14", "3.13", "3.12"]
2020

2121
steps:
2222
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

src/ducktools/classbuilder/methods.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,32 @@ def get_counter_field_names(argcount):
386386

387387
# Classes to handle cached methods
388388
class _CacheStats:
389-
__slots__ = ("hits", "misses", "skips")
389+
__slots__ = (
390+
"hits", "misses", "skips",
391+
"_hitlock", "_misslock", "_skiplock",
392+
)
390393

391394
def __init__(self):
392395
self.hits = 0
393396
self.misses = 0
394397
self.skips = 0
395398

399+
self._hitlock = _thread.allocate_lock()
400+
self._misslock = _thread.allocate_lock()
401+
self._skiplock = _thread.allocate_lock()
402+
403+
def add_hit(self):
404+
with self._hitlock:
405+
self.hits += 1
406+
407+
def add_miss(self):
408+
with self._misslock:
409+
self.misses += 1
410+
411+
def add_skip(self):
412+
with self._skiplock:
413+
self.skips += 1
414+
396415
@property
397416
def hit_percent(self):
398417
# If there are no cache hits, return 100%
@@ -437,17 +456,17 @@ def clear(self, new_cache=None):
437456
def __call__(self, *args, **kwargs):
438457
try:
439458
result = self._internal_cache[args]
440-
self._stats.hits += 1
459+
self._stats.add_hit()
441460
except KeyError:
442461
lock = self._lock_cache.setdefault(args, _thread.allocate_lock())
443462
with lock:
444463
try:
445464
result = self._internal_cache[args]
446-
self._stats.hits += 1
465+
self._stats.add_hit()
447466
except KeyError:
448467
result = self._func(*args, **kwargs)
449468
self._internal_cache[args] = result
450-
self._stats.misses += 1
469+
self._stats.add_miss()
451470

452471
return result
453472

@@ -482,7 +501,7 @@ def method_generator(cls, funcname):
482501
if args is None:
483502
# If the argument getter returns None
484503
# the method is not cacheable
485-
source_exec.stats.skips += 1 # Add one to skip count
504+
source_exec.stats.add_skip() # Add one to skip count
486505
return None
487506

488507
# The first argument should always be a tuple of fields

src/ducktools/classbuilder/methods.pyi

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
__lazy_modules__: list[str]
2424

25-
import threading
25+
import _thread
2626
import types
2727
import typing
2828

@@ -111,7 +111,7 @@ class _AttachedMethod:
111111
cls: type
112112

113113
_generated_method: types.FunctionType
114-
_lock: threading.Lock
114+
_lock: _thread.LockType
115115

116116
def __init__(
117117
self,
@@ -163,10 +163,19 @@ def get_init_parameters(cls: type) -> _FunctionParameterType: ...
163163
def get_counter_field_names(argcount: int) -> list[str]: ...
164164

165165
class _CacheStats:
166-
__slots__: tuple[str, str, str]
166+
__slots__: tuple[str, ...]
167167
hits: int
168168
misses: int
169169
skips: int
170+
171+
_hitlock: _thread.LockType
172+
_misslock: _thread.LockType
173+
_skiplock: _thread.LockType
174+
175+
def add_hit(self) -> None: ...
176+
def add_miss(self) -> None: ...
177+
def add_skip(self) -> None: ...
178+
170179
@property
171180
def hit_percent(self) -> float: ...
172181
def __init__(self) -> None: ...
@@ -177,7 +186,7 @@ class _SimpleCache:
177186
_func: Callable[..., types.FunctionType]
178187
_internal_cache: dict[tuple, types.FunctionType]
179188
_stats: _CacheStats
180-
_lock_cache: dict[tuple, threading.Lock]
189+
_lock_cache: dict[tuple, _thread.LockType]
181190
def __init__(
182191
self,
183192
func: types.FunctionType,

0 commit comments

Comments
 (0)