changeset: 98846:d3e048c7b65a parent: 98844:7163f35161c9 parent: 98845:73226f0d0f89 user: Serhiy Storchaka date: Sat Oct 24 09:50:19 2015 +0300 files: Misc/NEWS description: Issue #25447: The lru_cache() wrapper objects now can be copied and pickled (by returning the original object unchanged). diff -r 7163f35161c9 -r d3e048c7b65a Lib/test/test_functools.py --- a/Lib/test/test_functools.py Sat Oct 24 01:36:23 2015 -0500 +++ b/Lib/test/test_functools.py Sat Oct 24 09:50:19 2015 +0300 @@ -1,5 +1,6 @@ import abc import collections +import copy from itertools import permutations import pickle from random import choice @@ -1251,11 +1252,64 @@ self.assertEqual(b.f.cache_info(), X.f.cache_info()) self.assertEqual(c.f.cache_info(), X.f.cache_info()) -class TestLRUC(TestLRU, unittest.TestCase): - module = c_functools + def test_pickle(self): + 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): 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): diff -r 7163f35161c9 -r d3e048c7b65a Misc/NEWS --- a/Misc/NEWS Sat Oct 24 01:36:23 2015 -0500 +++ b/Misc/NEWS Sat Oct 24 09:50:19 2015 +0300 @@ -63,6 +63,9 @@ 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 #25441: asyncio: Raise error from drain() when socket is closed. diff -r 7163f35161c9 -r d3e048c7b65a Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c Sat Oct 24 01:36:23 2015 -0500 +++ b/Modules/_functoolsmodule.c Sat Oct 24 09:50:19 2015 +0300 @@ -1047,6 +1047,12 @@ Py_RETURN_NONE; } +static PyObject * +lru_cache_reduce(PyObject *self, PyObject *unused) +{ + return PyObject_GetAttrString(self, "__qualname__"); +} + static int lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg) { @@ -1097,6 +1103,7 @@ static PyMethodDef lru_cache_methods[] = { {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS}, {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS}, + {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS}, {NULL} };