Skip to content

Commit 1253c3e

Browse files
authored
bpo-40504: Allow weakrefs to lru_cache objects (GH-19938)
1 parent c21c512 commit 1253c3e

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

Lib/test/test_functools.py

+31
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import unittest
1515
import unittest.mock
1616
import os
17+
import weakref
18+
import gc
1719
from weakref import proxy
1820
import contextlib
1921

@@ -1938,6 +1940,35 @@ def f():
19381940
return 1
19391941
self.assertEqual(f.cache_parameters(), {'maxsize': 1000, "typed": True})
19401942

1943+
def test_lru_cache_weakrefable(self):
1944+
@self.module.lru_cache
1945+
def test_function(x):
1946+
return x
1947+
1948+
class A:
1949+
@self.module.lru_cache
1950+
def test_method(self, x):
1951+
return (self, x)
1952+
1953+
@staticmethod
1954+
@self.module.lru_cache
1955+
def test_staticmethod(x):
1956+
return (self, x)
1957+
1958+
refs = [weakref.ref(test_function),
1959+
weakref.ref(A.test_method),
1960+
weakref.ref(A.test_staticmethod)]
1961+
1962+
for ref in refs:
1963+
self.assertIsNotNone(ref())
1964+
1965+
del A
1966+
del test_function
1967+
gc.collect()
1968+
1969+
for ref in refs:
1970+
self.assertIsNone(ref())
1971+
19411972

19421973
@py_functools.lru_cache()
19431974
def py_cached_func(x, y):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:func:`functools.lru_cache` objects can now be the targets of weakrefs.

Modules/_functoolsmodule.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,7 @@ typedef struct lru_cache_object {
783783
Py_ssize_t misses;
784784
PyObject *cache_info_type;
785785
PyObject *dict;
786+
PyObject *weakreflist;
786787
} lru_cache_object;
787788

788789
static PyTypeObject lru_cache_type;
@@ -1196,6 +1197,7 @@ lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
11961197
Py_INCREF(cache_info_type);
11971198
obj->cache_info_type = cache_info_type;
11981199
obj->dict = NULL;
1200+
obj->weakreflist = NULL;
11991201
return (PyObject *)obj;
12001202
}
12011203

@@ -1227,6 +1229,8 @@ lru_cache_dealloc(lru_cache_object *obj)
12271229
lru_list_elem *list;
12281230
/* bpo-31095: UnTrack is needed before calling any callbacks */
12291231
PyObject_GC_UnTrack(obj);
1232+
if (obj->weakreflist != NULL)
1233+
PyObject_ClearWeakRefs((PyObject*)obj);
12301234

12311235
list = lru_cache_unlink_list(obj);
12321236
Py_XDECREF(obj->cache);
@@ -1384,7 +1388,8 @@ static PyTypeObject lru_cache_type = {
13841388
(traverseproc)lru_cache_tp_traverse,/* tp_traverse */
13851389
(inquiry)lru_cache_tp_clear, /* tp_clear */
13861390
0, /* tp_richcompare */
1387-
0, /* tp_weaklistoffset */
1391+
offsetof(lru_cache_object, weakreflist),
1392+
/* tp_weaklistoffset */
13881393
0, /* tp_iter */
13891394
0, /* tp_iternext */
13901395
lru_cache_methods, /* tp_methods */

0 commit comments

Comments
 (0)