Commit 45120f27 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #25447: The lru_cache() wrapper objects now can be copied and pickled

(by returning the original object unchanged).
parent a7b83b43
import abc import abc
import collections import collections
import copy
from itertools import permutations from itertools import permutations
import pickle import pickle
from random import choice from random import choice
...@@ -1251,11 +1252,64 @@ class TestLRU: ...@@ -1251,11 +1252,64 @@ class TestLRU:
self.assertEqual(b.f.cache_info(), X.f.cache_info()) self.assertEqual(b.f.cache_info(), X.f.cache_info())
self.assertEqual(c.f.cache_info(), X.f.cache_info()) self.assertEqual(c.f.cache_info(), X.f.cache_info())
class TestLRUC(TestLRU, unittest.TestCase): def test_pickle(self):
module = c_functools cls = self.__class__
for f in cls.cached_func[0], cls.cached_meth, cls.cached_staticmeth:
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(proto=proto, func=f):
f_copy = pickle.loads(pickle.dumps(f, proto))
self.assertIs(f_copy, f)
def test_copy(self):
cls = self.__class__
for f in cls.cached_func[0], cls.cached_meth, cls.cached_staticmeth:
with self.subTest(func=f):
f_copy = copy.copy(f)
self.assertIs(f_copy, f)
def test_deepcopy(self):
cls = self.__class__
for f in cls.cached_func[0], cls.cached_meth, cls.cached_staticmeth:
with self.subTest(func=f):
f_copy = copy.deepcopy(f)
self.assertIs(f_copy, f)
@py_functools.lru_cache()
def py_cached_func(x, y):
return 3 * x + y
@c_functools.lru_cache()
def c_cached_func(x, y):
return 3 * x + y
class TestLRUPy(TestLRU, unittest.TestCase): class TestLRUPy(TestLRU, unittest.TestCase):
module = py_functools module = py_functools
cached_func = py_cached_func,
@module.lru_cache()
def cached_meth(self, x, y):
return 3 * x + y
@staticmethod
@module.lru_cache()
def cached_staticmeth(x, y):
return 3 * x + y
class TestLRUC(TestLRU, unittest.TestCase):
module = c_functools
cached_func = c_cached_func,
@module.lru_cache()
def cached_meth(self, x, y):
return 3 * x + y
@staticmethod
@module.lru_cache()
def cached_staticmeth(x, y):
return 3 * x + y
class TestSingleDispatch(unittest.TestCase): class TestSingleDispatch(unittest.TestCase):
......
...@@ -45,6 +45,9 @@ Core and Builtins ...@@ -45,6 +45,9 @@ Core and Builtins
Library Library
------- -------
- Issue #25447: The lru_cache() wrapper objects now can be copied and pickled
(by returning the original object unchanged).
- Issue #25390: typing: Don't crash on Union[str, Pattern]. - Issue #25390: typing: Don't crash on Union[str, Pattern].
- Issue #25441: asyncio: Raise error from drain() when socket is closed. - Issue #25441: asyncio: Raise error from drain() when socket is closed.
......
...@@ -1047,6 +1047,12 @@ lru_cache_cache_clear(lru_cache_object *self, PyObject *unused) ...@@ -1047,6 +1047,12 @@ lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject *
lru_cache_reduce(PyObject *self, PyObject *unused)
{
return PyObject_GetAttrString(self, "__qualname__");
}
static int static int
lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg) lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
{ {
...@@ -1097,6 +1103,7 @@ cache_info_type: namedtuple class with the fields:\n\ ...@@ -1097,6 +1103,7 @@ cache_info_type: namedtuple class with the fields:\n\
static PyMethodDef lru_cache_methods[] = { static PyMethodDef lru_cache_methods[] = {
{"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS}, {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
{"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS}, {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
{"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
{NULL} {NULL}
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment