17db96d56Sopenharmony_ciimport abc 27db96d56Sopenharmony_ciimport builtins 37db96d56Sopenharmony_ciimport collections 47db96d56Sopenharmony_ciimport collections.abc 57db96d56Sopenharmony_ciimport copy 67db96d56Sopenharmony_cifrom itertools import permutations 77db96d56Sopenharmony_ciimport pickle 87db96d56Sopenharmony_cifrom random import choice 97db96d56Sopenharmony_ciimport sys 107db96d56Sopenharmony_cifrom test import support 117db96d56Sopenharmony_ciimport threading 127db96d56Sopenharmony_ciimport time 137db96d56Sopenharmony_ciimport typing 147db96d56Sopenharmony_ciimport unittest 157db96d56Sopenharmony_ciimport unittest.mock 167db96d56Sopenharmony_ciimport os 177db96d56Sopenharmony_ciimport weakref 187db96d56Sopenharmony_ciimport gc 197db96d56Sopenharmony_cifrom weakref import proxy 207db96d56Sopenharmony_ciimport contextlib 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_cifrom test.support import import_helper 237db96d56Sopenharmony_cifrom test.support import threading_helper 247db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_ok 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ciimport functools 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_cipy_functools = import_helper.import_fresh_module('functools', 297db96d56Sopenharmony_ci blocked=['_functools']) 307db96d56Sopenharmony_cic_functools = import_helper.import_fresh_module('functools') 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_cidecimal = import_helper.import_fresh_module('decimal', fresh=['_decimal']) 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci@contextlib.contextmanager 357db96d56Sopenharmony_cidef replaced_module(name, replacement): 367db96d56Sopenharmony_ci original_module = sys.modules[name] 377db96d56Sopenharmony_ci sys.modules[name] = replacement 387db96d56Sopenharmony_ci try: 397db96d56Sopenharmony_ci yield 407db96d56Sopenharmony_ci finally: 417db96d56Sopenharmony_ci sys.modules[name] = original_module 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_cidef capture(*args, **kw): 447db96d56Sopenharmony_ci """capture all positional and keyword arguments""" 457db96d56Sopenharmony_ci return args, kw 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_cidef signature(part): 497db96d56Sopenharmony_ci """ return the signature of a partial object """ 507db96d56Sopenharmony_ci return (part.func, part.args, part.keywords, part.__dict__) 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ciclass MyTuple(tuple): 537db96d56Sopenharmony_ci pass 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ciclass BadTuple(tuple): 567db96d56Sopenharmony_ci def __add__(self, other): 577db96d56Sopenharmony_ci return list(self) + list(other) 587db96d56Sopenharmony_ci 597db96d56Sopenharmony_ciclass MyDict(dict): 607db96d56Sopenharmony_ci pass 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ciclass TestPartial: 647db96d56Sopenharmony_ci 657db96d56Sopenharmony_ci def test_basic_examples(self): 667db96d56Sopenharmony_ci p = self.partial(capture, 1, 2, a=10, b=20) 677db96d56Sopenharmony_ci self.assertTrue(callable(p)) 687db96d56Sopenharmony_ci self.assertEqual(p(3, 4, b=30, c=40), 697db96d56Sopenharmony_ci ((1, 2, 3, 4), dict(a=10, b=30, c=40))) 707db96d56Sopenharmony_ci p = self.partial(map, lambda x: x*10) 717db96d56Sopenharmony_ci self.assertEqual(list(p([1,2,3,4])), [10, 20, 30, 40]) 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_ci def test_attributes(self): 747db96d56Sopenharmony_ci p = self.partial(capture, 1, 2, a=10, b=20) 757db96d56Sopenharmony_ci # attributes should be readable 767db96d56Sopenharmony_ci self.assertEqual(p.func, capture) 777db96d56Sopenharmony_ci self.assertEqual(p.args, (1, 2)) 787db96d56Sopenharmony_ci self.assertEqual(p.keywords, dict(a=10, b=20)) 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ci def test_argument_checking(self): 817db96d56Sopenharmony_ci self.assertRaises(TypeError, self.partial) # need at least a func arg 827db96d56Sopenharmony_ci try: 837db96d56Sopenharmony_ci self.partial(2)() 847db96d56Sopenharmony_ci except TypeError: 857db96d56Sopenharmony_ci pass 867db96d56Sopenharmony_ci else: 877db96d56Sopenharmony_ci self.fail('First arg not checked for callability') 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ci def test_protection_of_callers_dict_argument(self): 907db96d56Sopenharmony_ci # a caller's dictionary should not be altered by partial 917db96d56Sopenharmony_ci def func(a=10, b=20): 927db96d56Sopenharmony_ci return a 937db96d56Sopenharmony_ci d = {'a':3} 947db96d56Sopenharmony_ci p = self.partial(func, a=5) 957db96d56Sopenharmony_ci self.assertEqual(p(**d), 3) 967db96d56Sopenharmony_ci self.assertEqual(d, {'a':3}) 977db96d56Sopenharmony_ci p(b=7) 987db96d56Sopenharmony_ci self.assertEqual(d, {'a':3}) 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci def test_kwargs_copy(self): 1017db96d56Sopenharmony_ci # Issue #29532: Altering a kwarg dictionary passed to a constructor 1027db96d56Sopenharmony_ci # should not affect a partial object after creation 1037db96d56Sopenharmony_ci d = {'a': 3} 1047db96d56Sopenharmony_ci p = self.partial(capture, **d) 1057db96d56Sopenharmony_ci self.assertEqual(p(), ((), {'a': 3})) 1067db96d56Sopenharmony_ci d['a'] = 5 1077db96d56Sopenharmony_ci self.assertEqual(p(), ((), {'a': 3})) 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci def test_arg_combinations(self): 1107db96d56Sopenharmony_ci # exercise special code paths for zero args in either partial 1117db96d56Sopenharmony_ci # object or the caller 1127db96d56Sopenharmony_ci p = self.partial(capture) 1137db96d56Sopenharmony_ci self.assertEqual(p(), ((), {})) 1147db96d56Sopenharmony_ci self.assertEqual(p(1,2), ((1,2), {})) 1157db96d56Sopenharmony_ci p = self.partial(capture, 1, 2) 1167db96d56Sopenharmony_ci self.assertEqual(p(), ((1,2), {})) 1177db96d56Sopenharmony_ci self.assertEqual(p(3,4), ((1,2,3,4), {})) 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_ci def test_kw_combinations(self): 1207db96d56Sopenharmony_ci # exercise special code paths for no keyword args in 1217db96d56Sopenharmony_ci # either the partial object or the caller 1227db96d56Sopenharmony_ci p = self.partial(capture) 1237db96d56Sopenharmony_ci self.assertEqual(p.keywords, {}) 1247db96d56Sopenharmony_ci self.assertEqual(p(), ((), {})) 1257db96d56Sopenharmony_ci self.assertEqual(p(a=1), ((), {'a':1})) 1267db96d56Sopenharmony_ci p = self.partial(capture, a=1) 1277db96d56Sopenharmony_ci self.assertEqual(p.keywords, {'a':1}) 1287db96d56Sopenharmony_ci self.assertEqual(p(), ((), {'a':1})) 1297db96d56Sopenharmony_ci self.assertEqual(p(b=2), ((), {'a':1, 'b':2})) 1307db96d56Sopenharmony_ci # keyword args in the call override those in the partial object 1317db96d56Sopenharmony_ci self.assertEqual(p(a=3, b=2), ((), {'a':3, 'b':2})) 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci def test_positional(self): 1347db96d56Sopenharmony_ci # make sure positional arguments are captured correctly 1357db96d56Sopenharmony_ci for args in [(), (0,), (0,1), (0,1,2), (0,1,2,3)]: 1367db96d56Sopenharmony_ci p = self.partial(capture, *args) 1377db96d56Sopenharmony_ci expected = args + ('x',) 1387db96d56Sopenharmony_ci got, empty = p('x') 1397db96d56Sopenharmony_ci self.assertTrue(expected == got and empty == {}) 1407db96d56Sopenharmony_ci 1417db96d56Sopenharmony_ci def test_keyword(self): 1427db96d56Sopenharmony_ci # make sure keyword arguments are captured correctly 1437db96d56Sopenharmony_ci for a in ['a', 0, None, 3.5]: 1447db96d56Sopenharmony_ci p = self.partial(capture, a=a) 1457db96d56Sopenharmony_ci expected = {'a':a,'x':None} 1467db96d56Sopenharmony_ci empty, got = p(x=None) 1477db96d56Sopenharmony_ci self.assertTrue(expected == got and empty == ()) 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci def test_no_side_effects(self): 1507db96d56Sopenharmony_ci # make sure there are no side effects that affect subsequent calls 1517db96d56Sopenharmony_ci p = self.partial(capture, 0, a=1) 1527db96d56Sopenharmony_ci args1, kw1 = p(1, b=2) 1537db96d56Sopenharmony_ci self.assertTrue(args1 == (0,1) and kw1 == {'a':1,'b':2}) 1547db96d56Sopenharmony_ci args2, kw2 = p() 1557db96d56Sopenharmony_ci self.assertTrue(args2 == (0,) and kw2 == {'a':1}) 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci def test_error_propagation(self): 1587db96d56Sopenharmony_ci def f(x, y): 1597db96d56Sopenharmony_ci x / y 1607db96d56Sopenharmony_ci self.assertRaises(ZeroDivisionError, self.partial(f, 1, 0)) 1617db96d56Sopenharmony_ci self.assertRaises(ZeroDivisionError, self.partial(f, 1), 0) 1627db96d56Sopenharmony_ci self.assertRaises(ZeroDivisionError, self.partial(f), 1, 0) 1637db96d56Sopenharmony_ci self.assertRaises(ZeroDivisionError, self.partial(f, y=0), 1) 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci def test_weakref(self): 1667db96d56Sopenharmony_ci f = self.partial(int, base=16) 1677db96d56Sopenharmony_ci p = proxy(f) 1687db96d56Sopenharmony_ci self.assertEqual(f.func, p.func) 1697db96d56Sopenharmony_ci f = None 1707db96d56Sopenharmony_ci support.gc_collect() # For PyPy or other GCs. 1717db96d56Sopenharmony_ci self.assertRaises(ReferenceError, getattr, p, 'func') 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci def test_with_bound_and_unbound_methods(self): 1747db96d56Sopenharmony_ci data = list(map(str, range(10))) 1757db96d56Sopenharmony_ci join = self.partial(str.join, '') 1767db96d56Sopenharmony_ci self.assertEqual(join(data), '0123456789') 1777db96d56Sopenharmony_ci join = self.partial(''.join) 1787db96d56Sopenharmony_ci self.assertEqual(join(data), '0123456789') 1797db96d56Sopenharmony_ci 1807db96d56Sopenharmony_ci def test_nested_optimization(self): 1817db96d56Sopenharmony_ci partial = self.partial 1827db96d56Sopenharmony_ci inner = partial(signature, 'asdf') 1837db96d56Sopenharmony_ci nested = partial(inner, bar=True) 1847db96d56Sopenharmony_ci flat = partial(signature, 'asdf', bar=True) 1857db96d56Sopenharmony_ci self.assertEqual(signature(nested), signature(flat)) 1867db96d56Sopenharmony_ci 1877db96d56Sopenharmony_ci def test_nested_partial_with_attribute(self): 1887db96d56Sopenharmony_ci # see issue 25137 1897db96d56Sopenharmony_ci partial = self.partial 1907db96d56Sopenharmony_ci 1917db96d56Sopenharmony_ci def foo(bar): 1927db96d56Sopenharmony_ci return bar 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ci p = partial(foo, 'first') 1957db96d56Sopenharmony_ci p2 = partial(p, 'second') 1967db96d56Sopenharmony_ci p2.new_attr = 'spam' 1977db96d56Sopenharmony_ci self.assertEqual(p2.new_attr, 'spam') 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci def test_repr(self): 2007db96d56Sopenharmony_ci args = (object(), object()) 2017db96d56Sopenharmony_ci args_repr = ', '.join(repr(a) for a in args) 2027db96d56Sopenharmony_ci kwargs = {'a': object(), 'b': object()} 2037db96d56Sopenharmony_ci kwargs_reprs = ['a={a!r}, b={b!r}'.format_map(kwargs), 2047db96d56Sopenharmony_ci 'b={b!r}, a={a!r}'.format_map(kwargs)] 2057db96d56Sopenharmony_ci if self.partial in (c_functools.partial, py_functools.partial): 2067db96d56Sopenharmony_ci name = 'functools.partial' 2077db96d56Sopenharmony_ci else: 2087db96d56Sopenharmony_ci name = self.partial.__name__ 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci f = self.partial(capture) 2117db96d56Sopenharmony_ci self.assertEqual(f'{name}({capture!r})', repr(f)) 2127db96d56Sopenharmony_ci 2137db96d56Sopenharmony_ci f = self.partial(capture, *args) 2147db96d56Sopenharmony_ci self.assertEqual(f'{name}({capture!r}, {args_repr})', repr(f)) 2157db96d56Sopenharmony_ci 2167db96d56Sopenharmony_ci f = self.partial(capture, **kwargs) 2177db96d56Sopenharmony_ci self.assertIn(repr(f), 2187db96d56Sopenharmony_ci [f'{name}({capture!r}, {kwargs_repr})' 2197db96d56Sopenharmony_ci for kwargs_repr in kwargs_reprs]) 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci f = self.partial(capture, *args, **kwargs) 2227db96d56Sopenharmony_ci self.assertIn(repr(f), 2237db96d56Sopenharmony_ci [f'{name}({capture!r}, {args_repr}, {kwargs_repr})' 2247db96d56Sopenharmony_ci for kwargs_repr in kwargs_reprs]) 2257db96d56Sopenharmony_ci 2267db96d56Sopenharmony_ci def test_recursive_repr(self): 2277db96d56Sopenharmony_ci if self.partial in (c_functools.partial, py_functools.partial): 2287db96d56Sopenharmony_ci name = 'functools.partial' 2297db96d56Sopenharmony_ci else: 2307db96d56Sopenharmony_ci name = self.partial.__name__ 2317db96d56Sopenharmony_ci 2327db96d56Sopenharmony_ci f = self.partial(capture) 2337db96d56Sopenharmony_ci f.__setstate__((f, (), {}, {})) 2347db96d56Sopenharmony_ci try: 2357db96d56Sopenharmony_ci self.assertEqual(repr(f), '%s(...)' % (name,)) 2367db96d56Sopenharmony_ci finally: 2377db96d56Sopenharmony_ci f.__setstate__((capture, (), {}, {})) 2387db96d56Sopenharmony_ci 2397db96d56Sopenharmony_ci f = self.partial(capture) 2407db96d56Sopenharmony_ci f.__setstate__((capture, (f,), {}, {})) 2417db96d56Sopenharmony_ci try: 2427db96d56Sopenharmony_ci self.assertEqual(repr(f), '%s(%r, ...)' % (name, capture,)) 2437db96d56Sopenharmony_ci finally: 2447db96d56Sopenharmony_ci f.__setstate__((capture, (), {}, {})) 2457db96d56Sopenharmony_ci 2467db96d56Sopenharmony_ci f = self.partial(capture) 2477db96d56Sopenharmony_ci f.__setstate__((capture, (), {'a': f}, {})) 2487db96d56Sopenharmony_ci try: 2497db96d56Sopenharmony_ci self.assertEqual(repr(f), '%s(%r, a=...)' % (name, capture,)) 2507db96d56Sopenharmony_ci finally: 2517db96d56Sopenharmony_ci f.__setstate__((capture, (), {}, {})) 2527db96d56Sopenharmony_ci 2537db96d56Sopenharmony_ci def test_pickle(self): 2547db96d56Sopenharmony_ci with self.AllowPickle(): 2557db96d56Sopenharmony_ci f = self.partial(signature, ['asdf'], bar=[True]) 2567db96d56Sopenharmony_ci f.attr = [] 2577db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 2587db96d56Sopenharmony_ci f_copy = pickle.loads(pickle.dumps(f, proto)) 2597db96d56Sopenharmony_ci self.assertEqual(signature(f_copy), signature(f)) 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci def test_copy(self): 2627db96d56Sopenharmony_ci f = self.partial(signature, ['asdf'], bar=[True]) 2637db96d56Sopenharmony_ci f.attr = [] 2647db96d56Sopenharmony_ci f_copy = copy.copy(f) 2657db96d56Sopenharmony_ci self.assertEqual(signature(f_copy), signature(f)) 2667db96d56Sopenharmony_ci self.assertIs(f_copy.attr, f.attr) 2677db96d56Sopenharmony_ci self.assertIs(f_copy.args, f.args) 2687db96d56Sopenharmony_ci self.assertIs(f_copy.keywords, f.keywords) 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_ci def test_deepcopy(self): 2717db96d56Sopenharmony_ci f = self.partial(signature, ['asdf'], bar=[True]) 2727db96d56Sopenharmony_ci f.attr = [] 2737db96d56Sopenharmony_ci f_copy = copy.deepcopy(f) 2747db96d56Sopenharmony_ci self.assertEqual(signature(f_copy), signature(f)) 2757db96d56Sopenharmony_ci self.assertIsNot(f_copy.attr, f.attr) 2767db96d56Sopenharmony_ci self.assertIsNot(f_copy.args, f.args) 2777db96d56Sopenharmony_ci self.assertIsNot(f_copy.args[0], f.args[0]) 2787db96d56Sopenharmony_ci self.assertIsNot(f_copy.keywords, f.keywords) 2797db96d56Sopenharmony_ci self.assertIsNot(f_copy.keywords['bar'], f.keywords['bar']) 2807db96d56Sopenharmony_ci 2817db96d56Sopenharmony_ci def test_setstate(self): 2827db96d56Sopenharmony_ci f = self.partial(signature) 2837db96d56Sopenharmony_ci f.__setstate__((capture, (1,), dict(a=10), dict(attr=[]))) 2847db96d56Sopenharmony_ci 2857db96d56Sopenharmony_ci self.assertEqual(signature(f), 2867db96d56Sopenharmony_ci (capture, (1,), dict(a=10), dict(attr=[]))) 2877db96d56Sopenharmony_ci self.assertEqual(f(2, b=20), ((1, 2), {'a': 10, 'b': 20})) 2887db96d56Sopenharmony_ci 2897db96d56Sopenharmony_ci f.__setstate__((capture, (1,), dict(a=10), None)) 2907db96d56Sopenharmony_ci 2917db96d56Sopenharmony_ci self.assertEqual(signature(f), (capture, (1,), dict(a=10), {})) 2927db96d56Sopenharmony_ci self.assertEqual(f(2, b=20), ((1, 2), {'a': 10, 'b': 20})) 2937db96d56Sopenharmony_ci 2947db96d56Sopenharmony_ci f.__setstate__((capture, (1,), None, None)) 2957db96d56Sopenharmony_ci #self.assertEqual(signature(f), (capture, (1,), {}, {})) 2967db96d56Sopenharmony_ci self.assertEqual(f(2, b=20), ((1, 2), {'b': 20})) 2977db96d56Sopenharmony_ci self.assertEqual(f(2), ((1, 2), {})) 2987db96d56Sopenharmony_ci self.assertEqual(f(), ((1,), {})) 2997db96d56Sopenharmony_ci 3007db96d56Sopenharmony_ci f.__setstate__((capture, (), {}, None)) 3017db96d56Sopenharmony_ci self.assertEqual(signature(f), (capture, (), {}, {})) 3027db96d56Sopenharmony_ci self.assertEqual(f(2, b=20), ((2,), {'b': 20})) 3037db96d56Sopenharmony_ci self.assertEqual(f(2), ((2,), {})) 3047db96d56Sopenharmony_ci self.assertEqual(f(), ((), {})) 3057db96d56Sopenharmony_ci 3067db96d56Sopenharmony_ci def test_setstate_errors(self): 3077db96d56Sopenharmony_ci f = self.partial(signature) 3087db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, (capture, (), {})) 3097db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, {}, None)) 3107db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, [capture, (), {}, None]) 3117db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, (None, (), {}, None)) 3127db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, (capture, None, {}, None)) 3137db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, (capture, [], {}, None)) 3147db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, (capture, (), [], None)) 3157db96d56Sopenharmony_ci 3167db96d56Sopenharmony_ci def test_setstate_subclasses(self): 3177db96d56Sopenharmony_ci f = self.partial(signature) 3187db96d56Sopenharmony_ci f.__setstate__((capture, MyTuple((1,)), MyDict(a=10), None)) 3197db96d56Sopenharmony_ci s = signature(f) 3207db96d56Sopenharmony_ci self.assertEqual(s, (capture, (1,), dict(a=10), {})) 3217db96d56Sopenharmony_ci self.assertIs(type(s[1]), tuple) 3227db96d56Sopenharmony_ci self.assertIs(type(s[2]), dict) 3237db96d56Sopenharmony_ci r = f() 3247db96d56Sopenharmony_ci self.assertEqual(r, ((1,), {'a': 10})) 3257db96d56Sopenharmony_ci self.assertIs(type(r[0]), tuple) 3267db96d56Sopenharmony_ci self.assertIs(type(r[1]), dict) 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci f.__setstate__((capture, BadTuple((1,)), {}, None)) 3297db96d56Sopenharmony_ci s = signature(f) 3307db96d56Sopenharmony_ci self.assertEqual(s, (capture, (1,), {}, {})) 3317db96d56Sopenharmony_ci self.assertIs(type(s[1]), tuple) 3327db96d56Sopenharmony_ci r = f(2) 3337db96d56Sopenharmony_ci self.assertEqual(r, ((1, 2), {})) 3347db96d56Sopenharmony_ci self.assertIs(type(r[0]), tuple) 3357db96d56Sopenharmony_ci 3367db96d56Sopenharmony_ci def test_recursive_pickle(self): 3377db96d56Sopenharmony_ci with self.AllowPickle(): 3387db96d56Sopenharmony_ci f = self.partial(capture) 3397db96d56Sopenharmony_ci f.__setstate__((f, (), {}, {})) 3407db96d56Sopenharmony_ci try: 3417db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 3427db96d56Sopenharmony_ci with self.assertRaises(RecursionError): 3437db96d56Sopenharmony_ci pickle.dumps(f, proto) 3447db96d56Sopenharmony_ci finally: 3457db96d56Sopenharmony_ci f.__setstate__((capture, (), {}, {})) 3467db96d56Sopenharmony_ci 3477db96d56Sopenharmony_ci f = self.partial(capture) 3487db96d56Sopenharmony_ci f.__setstate__((capture, (f,), {}, {})) 3497db96d56Sopenharmony_ci try: 3507db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 3517db96d56Sopenharmony_ci f_copy = pickle.loads(pickle.dumps(f, proto)) 3527db96d56Sopenharmony_ci try: 3537db96d56Sopenharmony_ci self.assertIs(f_copy.args[0], f_copy) 3547db96d56Sopenharmony_ci finally: 3557db96d56Sopenharmony_ci f_copy.__setstate__((capture, (), {}, {})) 3567db96d56Sopenharmony_ci finally: 3577db96d56Sopenharmony_ci f.__setstate__((capture, (), {}, {})) 3587db96d56Sopenharmony_ci 3597db96d56Sopenharmony_ci f = self.partial(capture) 3607db96d56Sopenharmony_ci f.__setstate__((capture, (), {'a': f}, {})) 3617db96d56Sopenharmony_ci try: 3627db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 3637db96d56Sopenharmony_ci f_copy = pickle.loads(pickle.dumps(f, proto)) 3647db96d56Sopenharmony_ci try: 3657db96d56Sopenharmony_ci self.assertIs(f_copy.keywords['a'], f_copy) 3667db96d56Sopenharmony_ci finally: 3677db96d56Sopenharmony_ci f_copy.__setstate__((capture, (), {}, {})) 3687db96d56Sopenharmony_ci finally: 3697db96d56Sopenharmony_ci f.__setstate__((capture, (), {}, {})) 3707db96d56Sopenharmony_ci 3717db96d56Sopenharmony_ci # Issue 6083: Reference counting bug 3727db96d56Sopenharmony_ci def test_setstate_refcount(self): 3737db96d56Sopenharmony_ci class BadSequence: 3747db96d56Sopenharmony_ci def __len__(self): 3757db96d56Sopenharmony_ci return 4 3767db96d56Sopenharmony_ci def __getitem__(self, key): 3777db96d56Sopenharmony_ci if key == 0: 3787db96d56Sopenharmony_ci return max 3797db96d56Sopenharmony_ci elif key == 1: 3807db96d56Sopenharmony_ci return tuple(range(1000000)) 3817db96d56Sopenharmony_ci elif key in (2, 3): 3827db96d56Sopenharmony_ci return {} 3837db96d56Sopenharmony_ci raise IndexError 3847db96d56Sopenharmony_ci 3857db96d56Sopenharmony_ci f = self.partial(object) 3867db96d56Sopenharmony_ci self.assertRaises(TypeError, f.__setstate__, BadSequence()) 3877db96d56Sopenharmony_ci 3887db96d56Sopenharmony_ci@unittest.skipUnless(c_functools, 'requires the C _functools module') 3897db96d56Sopenharmony_ciclass TestPartialC(TestPartial, unittest.TestCase): 3907db96d56Sopenharmony_ci if c_functools: 3917db96d56Sopenharmony_ci partial = c_functools.partial 3927db96d56Sopenharmony_ci 3937db96d56Sopenharmony_ci class AllowPickle: 3947db96d56Sopenharmony_ci def __enter__(self): 3957db96d56Sopenharmony_ci return self 3967db96d56Sopenharmony_ci def __exit__(self, type, value, tb): 3977db96d56Sopenharmony_ci return False 3987db96d56Sopenharmony_ci 3997db96d56Sopenharmony_ci def test_attributes_unwritable(self): 4007db96d56Sopenharmony_ci # attributes should not be writable 4017db96d56Sopenharmony_ci p = self.partial(capture, 1, 2, a=10, b=20) 4027db96d56Sopenharmony_ci self.assertRaises(AttributeError, setattr, p, 'func', map) 4037db96d56Sopenharmony_ci self.assertRaises(AttributeError, setattr, p, 'args', (1, 2)) 4047db96d56Sopenharmony_ci self.assertRaises(AttributeError, setattr, p, 'keywords', dict(a=1, b=2)) 4057db96d56Sopenharmony_ci 4067db96d56Sopenharmony_ci p = self.partial(hex) 4077db96d56Sopenharmony_ci try: 4087db96d56Sopenharmony_ci del p.__dict__ 4097db96d56Sopenharmony_ci except TypeError: 4107db96d56Sopenharmony_ci pass 4117db96d56Sopenharmony_ci else: 4127db96d56Sopenharmony_ci self.fail('partial object allowed __dict__ to be deleted') 4137db96d56Sopenharmony_ci 4147db96d56Sopenharmony_ci def test_manually_adding_non_string_keyword(self): 4157db96d56Sopenharmony_ci p = self.partial(capture) 4167db96d56Sopenharmony_ci # Adding a non-string/unicode keyword to partial kwargs 4177db96d56Sopenharmony_ci p.keywords[1234] = 'value' 4187db96d56Sopenharmony_ci r = repr(p) 4197db96d56Sopenharmony_ci self.assertIn('1234', r) 4207db96d56Sopenharmony_ci self.assertIn("'value'", r) 4217db96d56Sopenharmony_ci with self.assertRaises(TypeError): 4227db96d56Sopenharmony_ci p() 4237db96d56Sopenharmony_ci 4247db96d56Sopenharmony_ci def test_keystr_replaces_value(self): 4257db96d56Sopenharmony_ci p = self.partial(capture) 4267db96d56Sopenharmony_ci 4277db96d56Sopenharmony_ci class MutatesYourDict(object): 4287db96d56Sopenharmony_ci def __str__(self): 4297db96d56Sopenharmony_ci p.keywords[self] = ['sth2'] 4307db96d56Sopenharmony_ci return 'astr' 4317db96d56Sopenharmony_ci 4327db96d56Sopenharmony_ci # Replacing the value during key formatting should keep the original 4337db96d56Sopenharmony_ci # value alive (at least long enough). 4347db96d56Sopenharmony_ci p.keywords[MutatesYourDict()] = ['sth'] 4357db96d56Sopenharmony_ci r = repr(p) 4367db96d56Sopenharmony_ci self.assertIn('astr', r) 4377db96d56Sopenharmony_ci self.assertIn("['sth']", r) 4387db96d56Sopenharmony_ci 4397db96d56Sopenharmony_ci 4407db96d56Sopenharmony_ciclass TestPartialPy(TestPartial, unittest.TestCase): 4417db96d56Sopenharmony_ci partial = py_functools.partial 4427db96d56Sopenharmony_ci 4437db96d56Sopenharmony_ci class AllowPickle: 4447db96d56Sopenharmony_ci def __init__(self): 4457db96d56Sopenharmony_ci self._cm = replaced_module("functools", py_functools) 4467db96d56Sopenharmony_ci def __enter__(self): 4477db96d56Sopenharmony_ci return self._cm.__enter__() 4487db96d56Sopenharmony_ci def __exit__(self, type, value, tb): 4497db96d56Sopenharmony_ci return self._cm.__exit__(type, value, tb) 4507db96d56Sopenharmony_ci 4517db96d56Sopenharmony_ciif c_functools: 4527db96d56Sopenharmony_ci class CPartialSubclass(c_functools.partial): 4537db96d56Sopenharmony_ci pass 4547db96d56Sopenharmony_ci 4557db96d56Sopenharmony_ciclass PyPartialSubclass(py_functools.partial): 4567db96d56Sopenharmony_ci pass 4577db96d56Sopenharmony_ci 4587db96d56Sopenharmony_ci@unittest.skipUnless(c_functools, 'requires the C _functools module') 4597db96d56Sopenharmony_ciclass TestPartialCSubclass(TestPartialC): 4607db96d56Sopenharmony_ci if c_functools: 4617db96d56Sopenharmony_ci partial = CPartialSubclass 4627db96d56Sopenharmony_ci 4637db96d56Sopenharmony_ci # partial subclasses are not optimized for nested calls 4647db96d56Sopenharmony_ci test_nested_optimization = None 4657db96d56Sopenharmony_ci 4667db96d56Sopenharmony_ciclass TestPartialPySubclass(TestPartialPy): 4677db96d56Sopenharmony_ci partial = PyPartialSubclass 4687db96d56Sopenharmony_ci 4697db96d56Sopenharmony_ciclass TestPartialMethod(unittest.TestCase): 4707db96d56Sopenharmony_ci 4717db96d56Sopenharmony_ci class A(object): 4727db96d56Sopenharmony_ci nothing = functools.partialmethod(capture) 4737db96d56Sopenharmony_ci positional = functools.partialmethod(capture, 1) 4747db96d56Sopenharmony_ci keywords = functools.partialmethod(capture, a=2) 4757db96d56Sopenharmony_ci both = functools.partialmethod(capture, 3, b=4) 4767db96d56Sopenharmony_ci spec_keywords = functools.partialmethod(capture, self=1, func=2) 4777db96d56Sopenharmony_ci 4787db96d56Sopenharmony_ci nested = functools.partialmethod(positional, 5) 4797db96d56Sopenharmony_ci 4807db96d56Sopenharmony_ci over_partial = functools.partialmethod(functools.partial(capture, c=6), 7) 4817db96d56Sopenharmony_ci 4827db96d56Sopenharmony_ci static = functools.partialmethod(staticmethod(capture), 8) 4837db96d56Sopenharmony_ci cls = functools.partialmethod(classmethod(capture), d=9) 4847db96d56Sopenharmony_ci 4857db96d56Sopenharmony_ci a = A() 4867db96d56Sopenharmony_ci 4877db96d56Sopenharmony_ci def test_arg_combinations(self): 4887db96d56Sopenharmony_ci self.assertEqual(self.a.nothing(), ((self.a,), {})) 4897db96d56Sopenharmony_ci self.assertEqual(self.a.nothing(5), ((self.a, 5), {})) 4907db96d56Sopenharmony_ci self.assertEqual(self.a.nothing(c=6), ((self.a,), {'c': 6})) 4917db96d56Sopenharmony_ci self.assertEqual(self.a.nothing(5, c=6), ((self.a, 5), {'c': 6})) 4927db96d56Sopenharmony_ci 4937db96d56Sopenharmony_ci self.assertEqual(self.a.positional(), ((self.a, 1), {})) 4947db96d56Sopenharmony_ci self.assertEqual(self.a.positional(5), ((self.a, 1, 5), {})) 4957db96d56Sopenharmony_ci self.assertEqual(self.a.positional(c=6), ((self.a, 1), {'c': 6})) 4967db96d56Sopenharmony_ci self.assertEqual(self.a.positional(5, c=6), ((self.a, 1, 5), {'c': 6})) 4977db96d56Sopenharmony_ci 4987db96d56Sopenharmony_ci self.assertEqual(self.a.keywords(), ((self.a,), {'a': 2})) 4997db96d56Sopenharmony_ci self.assertEqual(self.a.keywords(5), ((self.a, 5), {'a': 2})) 5007db96d56Sopenharmony_ci self.assertEqual(self.a.keywords(c=6), ((self.a,), {'a': 2, 'c': 6})) 5017db96d56Sopenharmony_ci self.assertEqual(self.a.keywords(5, c=6), ((self.a, 5), {'a': 2, 'c': 6})) 5027db96d56Sopenharmony_ci 5037db96d56Sopenharmony_ci self.assertEqual(self.a.both(), ((self.a, 3), {'b': 4})) 5047db96d56Sopenharmony_ci self.assertEqual(self.a.both(5), ((self.a, 3, 5), {'b': 4})) 5057db96d56Sopenharmony_ci self.assertEqual(self.a.both(c=6), ((self.a, 3), {'b': 4, 'c': 6})) 5067db96d56Sopenharmony_ci self.assertEqual(self.a.both(5, c=6), ((self.a, 3, 5), {'b': 4, 'c': 6})) 5077db96d56Sopenharmony_ci 5087db96d56Sopenharmony_ci self.assertEqual(self.A.both(self.a, 5, c=6), ((self.a, 3, 5), {'b': 4, 'c': 6})) 5097db96d56Sopenharmony_ci 5107db96d56Sopenharmony_ci self.assertEqual(self.a.spec_keywords(), ((self.a,), {'self': 1, 'func': 2})) 5117db96d56Sopenharmony_ci 5127db96d56Sopenharmony_ci def test_nested(self): 5137db96d56Sopenharmony_ci self.assertEqual(self.a.nested(), ((self.a, 1, 5), {})) 5147db96d56Sopenharmony_ci self.assertEqual(self.a.nested(6), ((self.a, 1, 5, 6), {})) 5157db96d56Sopenharmony_ci self.assertEqual(self.a.nested(d=7), ((self.a, 1, 5), {'d': 7})) 5167db96d56Sopenharmony_ci self.assertEqual(self.a.nested(6, d=7), ((self.a, 1, 5, 6), {'d': 7})) 5177db96d56Sopenharmony_ci 5187db96d56Sopenharmony_ci self.assertEqual(self.A.nested(self.a, 6, d=7), ((self.a, 1, 5, 6), {'d': 7})) 5197db96d56Sopenharmony_ci 5207db96d56Sopenharmony_ci def test_over_partial(self): 5217db96d56Sopenharmony_ci self.assertEqual(self.a.over_partial(), ((self.a, 7), {'c': 6})) 5227db96d56Sopenharmony_ci self.assertEqual(self.a.over_partial(5), ((self.a, 7, 5), {'c': 6})) 5237db96d56Sopenharmony_ci self.assertEqual(self.a.over_partial(d=8), ((self.a, 7), {'c': 6, 'd': 8})) 5247db96d56Sopenharmony_ci self.assertEqual(self.a.over_partial(5, d=8), ((self.a, 7, 5), {'c': 6, 'd': 8})) 5257db96d56Sopenharmony_ci 5267db96d56Sopenharmony_ci self.assertEqual(self.A.over_partial(self.a, 5, d=8), ((self.a, 7, 5), {'c': 6, 'd': 8})) 5277db96d56Sopenharmony_ci 5287db96d56Sopenharmony_ci def test_bound_method_introspection(self): 5297db96d56Sopenharmony_ci obj = self.a 5307db96d56Sopenharmony_ci self.assertIs(obj.both.__self__, obj) 5317db96d56Sopenharmony_ci self.assertIs(obj.nested.__self__, obj) 5327db96d56Sopenharmony_ci self.assertIs(obj.over_partial.__self__, obj) 5337db96d56Sopenharmony_ci self.assertIs(obj.cls.__self__, self.A) 5347db96d56Sopenharmony_ci self.assertIs(self.A.cls.__self__, self.A) 5357db96d56Sopenharmony_ci 5367db96d56Sopenharmony_ci def test_unbound_method_retrieval(self): 5377db96d56Sopenharmony_ci obj = self.A 5387db96d56Sopenharmony_ci self.assertFalse(hasattr(obj.both, "__self__")) 5397db96d56Sopenharmony_ci self.assertFalse(hasattr(obj.nested, "__self__")) 5407db96d56Sopenharmony_ci self.assertFalse(hasattr(obj.over_partial, "__self__")) 5417db96d56Sopenharmony_ci self.assertFalse(hasattr(obj.static, "__self__")) 5427db96d56Sopenharmony_ci self.assertFalse(hasattr(self.a.static, "__self__")) 5437db96d56Sopenharmony_ci 5447db96d56Sopenharmony_ci def test_descriptors(self): 5457db96d56Sopenharmony_ci for obj in [self.A, self.a]: 5467db96d56Sopenharmony_ci with self.subTest(obj=obj): 5477db96d56Sopenharmony_ci self.assertEqual(obj.static(), ((8,), {})) 5487db96d56Sopenharmony_ci self.assertEqual(obj.static(5), ((8, 5), {})) 5497db96d56Sopenharmony_ci self.assertEqual(obj.static(d=8), ((8,), {'d': 8})) 5507db96d56Sopenharmony_ci self.assertEqual(obj.static(5, d=8), ((8, 5), {'d': 8})) 5517db96d56Sopenharmony_ci 5527db96d56Sopenharmony_ci self.assertEqual(obj.cls(), ((self.A,), {'d': 9})) 5537db96d56Sopenharmony_ci self.assertEqual(obj.cls(5), ((self.A, 5), {'d': 9})) 5547db96d56Sopenharmony_ci self.assertEqual(obj.cls(c=8), ((self.A,), {'c': 8, 'd': 9})) 5557db96d56Sopenharmony_ci self.assertEqual(obj.cls(5, c=8), ((self.A, 5), {'c': 8, 'd': 9})) 5567db96d56Sopenharmony_ci 5577db96d56Sopenharmony_ci def test_overriding_keywords(self): 5587db96d56Sopenharmony_ci self.assertEqual(self.a.keywords(a=3), ((self.a,), {'a': 3})) 5597db96d56Sopenharmony_ci self.assertEqual(self.A.keywords(self.a, a=3), ((self.a,), {'a': 3})) 5607db96d56Sopenharmony_ci 5617db96d56Sopenharmony_ci def test_invalid_args(self): 5627db96d56Sopenharmony_ci with self.assertRaises(TypeError): 5637db96d56Sopenharmony_ci class B(object): 5647db96d56Sopenharmony_ci method = functools.partialmethod(None, 1) 5657db96d56Sopenharmony_ci with self.assertRaises(TypeError): 5667db96d56Sopenharmony_ci class B: 5677db96d56Sopenharmony_ci method = functools.partialmethod() 5687db96d56Sopenharmony_ci with self.assertRaises(TypeError): 5697db96d56Sopenharmony_ci class B: 5707db96d56Sopenharmony_ci method = functools.partialmethod(func=capture, a=1) 5717db96d56Sopenharmony_ci 5727db96d56Sopenharmony_ci def test_repr(self): 5737db96d56Sopenharmony_ci self.assertEqual(repr(vars(self.A)['both']), 5747db96d56Sopenharmony_ci 'functools.partialmethod({}, 3, b=4)'.format(capture)) 5757db96d56Sopenharmony_ci 5767db96d56Sopenharmony_ci def test_abstract(self): 5777db96d56Sopenharmony_ci class Abstract(abc.ABCMeta): 5787db96d56Sopenharmony_ci 5797db96d56Sopenharmony_ci @abc.abstractmethod 5807db96d56Sopenharmony_ci def add(self, x, y): 5817db96d56Sopenharmony_ci pass 5827db96d56Sopenharmony_ci 5837db96d56Sopenharmony_ci add5 = functools.partialmethod(add, 5) 5847db96d56Sopenharmony_ci 5857db96d56Sopenharmony_ci self.assertTrue(Abstract.add.__isabstractmethod__) 5867db96d56Sopenharmony_ci self.assertTrue(Abstract.add5.__isabstractmethod__) 5877db96d56Sopenharmony_ci 5887db96d56Sopenharmony_ci for func in [self.A.static, self.A.cls, self.A.over_partial, self.A.nested, self.A.both]: 5897db96d56Sopenharmony_ci self.assertFalse(getattr(func, '__isabstractmethod__', False)) 5907db96d56Sopenharmony_ci 5917db96d56Sopenharmony_ci def test_positional_only(self): 5927db96d56Sopenharmony_ci def f(a, b, /): 5937db96d56Sopenharmony_ci return a + b 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_ci p = functools.partial(f, 1) 5967db96d56Sopenharmony_ci self.assertEqual(p(2), f(1, 2)) 5977db96d56Sopenharmony_ci 5987db96d56Sopenharmony_ci 5997db96d56Sopenharmony_ciclass TestUpdateWrapper(unittest.TestCase): 6007db96d56Sopenharmony_ci 6017db96d56Sopenharmony_ci def check_wrapper(self, wrapper, wrapped, 6027db96d56Sopenharmony_ci assigned=functools.WRAPPER_ASSIGNMENTS, 6037db96d56Sopenharmony_ci updated=functools.WRAPPER_UPDATES): 6047db96d56Sopenharmony_ci # Check attributes were assigned 6057db96d56Sopenharmony_ci for name in assigned: 6067db96d56Sopenharmony_ci self.assertIs(getattr(wrapper, name), getattr(wrapped, name)) 6077db96d56Sopenharmony_ci # Check attributes were updated 6087db96d56Sopenharmony_ci for name in updated: 6097db96d56Sopenharmony_ci wrapper_attr = getattr(wrapper, name) 6107db96d56Sopenharmony_ci wrapped_attr = getattr(wrapped, name) 6117db96d56Sopenharmony_ci for key in wrapped_attr: 6127db96d56Sopenharmony_ci if name == "__dict__" and key == "__wrapped__": 6137db96d56Sopenharmony_ci # __wrapped__ is overwritten by the update code 6147db96d56Sopenharmony_ci continue 6157db96d56Sopenharmony_ci self.assertIs(wrapped_attr[key], wrapper_attr[key]) 6167db96d56Sopenharmony_ci # Check __wrapped__ 6177db96d56Sopenharmony_ci self.assertIs(wrapper.__wrapped__, wrapped) 6187db96d56Sopenharmony_ci 6197db96d56Sopenharmony_ci 6207db96d56Sopenharmony_ci def _default_update(self): 6217db96d56Sopenharmony_ci def f(a:'This is a new annotation'): 6227db96d56Sopenharmony_ci """This is a test""" 6237db96d56Sopenharmony_ci pass 6247db96d56Sopenharmony_ci f.attr = 'This is also a test' 6257db96d56Sopenharmony_ci f.__wrapped__ = "This is a bald faced lie" 6267db96d56Sopenharmony_ci def wrapper(b:'This is the prior annotation'): 6277db96d56Sopenharmony_ci pass 6287db96d56Sopenharmony_ci functools.update_wrapper(wrapper, f) 6297db96d56Sopenharmony_ci return wrapper, f 6307db96d56Sopenharmony_ci 6317db96d56Sopenharmony_ci def test_default_update(self): 6327db96d56Sopenharmony_ci wrapper, f = self._default_update() 6337db96d56Sopenharmony_ci self.check_wrapper(wrapper, f) 6347db96d56Sopenharmony_ci self.assertIs(wrapper.__wrapped__, f) 6357db96d56Sopenharmony_ci self.assertEqual(wrapper.__name__, 'f') 6367db96d56Sopenharmony_ci self.assertEqual(wrapper.__qualname__, f.__qualname__) 6377db96d56Sopenharmony_ci self.assertEqual(wrapper.attr, 'This is also a test') 6387db96d56Sopenharmony_ci self.assertEqual(wrapper.__annotations__['a'], 'This is a new annotation') 6397db96d56Sopenharmony_ci self.assertNotIn('b', wrapper.__annotations__) 6407db96d56Sopenharmony_ci 6417db96d56Sopenharmony_ci @unittest.skipIf(sys.flags.optimize >= 2, 6427db96d56Sopenharmony_ci "Docstrings are omitted with -O2 and above") 6437db96d56Sopenharmony_ci def test_default_update_doc(self): 6447db96d56Sopenharmony_ci wrapper, f = self._default_update() 6457db96d56Sopenharmony_ci self.assertEqual(wrapper.__doc__, 'This is a test') 6467db96d56Sopenharmony_ci 6477db96d56Sopenharmony_ci def test_no_update(self): 6487db96d56Sopenharmony_ci def f(): 6497db96d56Sopenharmony_ci """This is a test""" 6507db96d56Sopenharmony_ci pass 6517db96d56Sopenharmony_ci f.attr = 'This is also a test' 6527db96d56Sopenharmony_ci def wrapper(): 6537db96d56Sopenharmony_ci pass 6547db96d56Sopenharmony_ci functools.update_wrapper(wrapper, f, (), ()) 6557db96d56Sopenharmony_ci self.check_wrapper(wrapper, f, (), ()) 6567db96d56Sopenharmony_ci self.assertEqual(wrapper.__name__, 'wrapper') 6577db96d56Sopenharmony_ci self.assertNotEqual(wrapper.__qualname__, f.__qualname__) 6587db96d56Sopenharmony_ci self.assertEqual(wrapper.__doc__, None) 6597db96d56Sopenharmony_ci self.assertEqual(wrapper.__annotations__, {}) 6607db96d56Sopenharmony_ci self.assertFalse(hasattr(wrapper, 'attr')) 6617db96d56Sopenharmony_ci 6627db96d56Sopenharmony_ci def test_selective_update(self): 6637db96d56Sopenharmony_ci def f(): 6647db96d56Sopenharmony_ci pass 6657db96d56Sopenharmony_ci f.attr = 'This is a different test' 6667db96d56Sopenharmony_ci f.dict_attr = dict(a=1, b=2, c=3) 6677db96d56Sopenharmony_ci def wrapper(): 6687db96d56Sopenharmony_ci pass 6697db96d56Sopenharmony_ci wrapper.dict_attr = {} 6707db96d56Sopenharmony_ci assign = ('attr',) 6717db96d56Sopenharmony_ci update = ('dict_attr',) 6727db96d56Sopenharmony_ci functools.update_wrapper(wrapper, f, assign, update) 6737db96d56Sopenharmony_ci self.check_wrapper(wrapper, f, assign, update) 6747db96d56Sopenharmony_ci self.assertEqual(wrapper.__name__, 'wrapper') 6757db96d56Sopenharmony_ci self.assertNotEqual(wrapper.__qualname__, f.__qualname__) 6767db96d56Sopenharmony_ci self.assertEqual(wrapper.__doc__, None) 6777db96d56Sopenharmony_ci self.assertEqual(wrapper.attr, 'This is a different test') 6787db96d56Sopenharmony_ci self.assertEqual(wrapper.dict_attr, f.dict_attr) 6797db96d56Sopenharmony_ci 6807db96d56Sopenharmony_ci def test_missing_attributes(self): 6817db96d56Sopenharmony_ci def f(): 6827db96d56Sopenharmony_ci pass 6837db96d56Sopenharmony_ci def wrapper(): 6847db96d56Sopenharmony_ci pass 6857db96d56Sopenharmony_ci wrapper.dict_attr = {} 6867db96d56Sopenharmony_ci assign = ('attr',) 6877db96d56Sopenharmony_ci update = ('dict_attr',) 6887db96d56Sopenharmony_ci # Missing attributes on wrapped object are ignored 6897db96d56Sopenharmony_ci functools.update_wrapper(wrapper, f, assign, update) 6907db96d56Sopenharmony_ci self.assertNotIn('attr', wrapper.__dict__) 6917db96d56Sopenharmony_ci self.assertEqual(wrapper.dict_attr, {}) 6927db96d56Sopenharmony_ci # Wrapper must have expected attributes for updating 6937db96d56Sopenharmony_ci del wrapper.dict_attr 6947db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 6957db96d56Sopenharmony_ci functools.update_wrapper(wrapper, f, assign, update) 6967db96d56Sopenharmony_ci wrapper.dict_attr = 1 6977db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 6987db96d56Sopenharmony_ci functools.update_wrapper(wrapper, f, assign, update) 6997db96d56Sopenharmony_ci 7007db96d56Sopenharmony_ci @support.requires_docstrings 7017db96d56Sopenharmony_ci @unittest.skipIf(sys.flags.optimize >= 2, 7027db96d56Sopenharmony_ci "Docstrings are omitted with -O2 and above") 7037db96d56Sopenharmony_ci def test_builtin_update(self): 7047db96d56Sopenharmony_ci # Test for bug #1576241 7057db96d56Sopenharmony_ci def wrapper(): 7067db96d56Sopenharmony_ci pass 7077db96d56Sopenharmony_ci functools.update_wrapper(wrapper, max) 7087db96d56Sopenharmony_ci self.assertEqual(wrapper.__name__, 'max') 7097db96d56Sopenharmony_ci self.assertTrue(wrapper.__doc__.startswith('max(')) 7107db96d56Sopenharmony_ci self.assertEqual(wrapper.__annotations__, {}) 7117db96d56Sopenharmony_ci 7127db96d56Sopenharmony_ci 7137db96d56Sopenharmony_ciclass TestWraps(TestUpdateWrapper): 7147db96d56Sopenharmony_ci 7157db96d56Sopenharmony_ci def _default_update(self): 7167db96d56Sopenharmony_ci def f(): 7177db96d56Sopenharmony_ci """This is a test""" 7187db96d56Sopenharmony_ci pass 7197db96d56Sopenharmony_ci f.attr = 'This is also a test' 7207db96d56Sopenharmony_ci f.__wrapped__ = "This is still a bald faced lie" 7217db96d56Sopenharmony_ci @functools.wraps(f) 7227db96d56Sopenharmony_ci def wrapper(): 7237db96d56Sopenharmony_ci pass 7247db96d56Sopenharmony_ci return wrapper, f 7257db96d56Sopenharmony_ci 7267db96d56Sopenharmony_ci def test_default_update(self): 7277db96d56Sopenharmony_ci wrapper, f = self._default_update() 7287db96d56Sopenharmony_ci self.check_wrapper(wrapper, f) 7297db96d56Sopenharmony_ci self.assertEqual(wrapper.__name__, 'f') 7307db96d56Sopenharmony_ci self.assertEqual(wrapper.__qualname__, f.__qualname__) 7317db96d56Sopenharmony_ci self.assertEqual(wrapper.attr, 'This is also a test') 7327db96d56Sopenharmony_ci 7337db96d56Sopenharmony_ci @unittest.skipIf(sys.flags.optimize >= 2, 7347db96d56Sopenharmony_ci "Docstrings are omitted with -O2 and above") 7357db96d56Sopenharmony_ci def test_default_update_doc(self): 7367db96d56Sopenharmony_ci wrapper, _ = self._default_update() 7377db96d56Sopenharmony_ci self.assertEqual(wrapper.__doc__, 'This is a test') 7387db96d56Sopenharmony_ci 7397db96d56Sopenharmony_ci def test_no_update(self): 7407db96d56Sopenharmony_ci def f(): 7417db96d56Sopenharmony_ci """This is a test""" 7427db96d56Sopenharmony_ci pass 7437db96d56Sopenharmony_ci f.attr = 'This is also a test' 7447db96d56Sopenharmony_ci @functools.wraps(f, (), ()) 7457db96d56Sopenharmony_ci def wrapper(): 7467db96d56Sopenharmony_ci pass 7477db96d56Sopenharmony_ci self.check_wrapper(wrapper, f, (), ()) 7487db96d56Sopenharmony_ci self.assertEqual(wrapper.__name__, 'wrapper') 7497db96d56Sopenharmony_ci self.assertNotEqual(wrapper.__qualname__, f.__qualname__) 7507db96d56Sopenharmony_ci self.assertEqual(wrapper.__doc__, None) 7517db96d56Sopenharmony_ci self.assertFalse(hasattr(wrapper, 'attr')) 7527db96d56Sopenharmony_ci 7537db96d56Sopenharmony_ci def test_selective_update(self): 7547db96d56Sopenharmony_ci def f(): 7557db96d56Sopenharmony_ci pass 7567db96d56Sopenharmony_ci f.attr = 'This is a different test' 7577db96d56Sopenharmony_ci f.dict_attr = dict(a=1, b=2, c=3) 7587db96d56Sopenharmony_ci def add_dict_attr(f): 7597db96d56Sopenharmony_ci f.dict_attr = {} 7607db96d56Sopenharmony_ci return f 7617db96d56Sopenharmony_ci assign = ('attr',) 7627db96d56Sopenharmony_ci update = ('dict_attr',) 7637db96d56Sopenharmony_ci @functools.wraps(f, assign, update) 7647db96d56Sopenharmony_ci @add_dict_attr 7657db96d56Sopenharmony_ci def wrapper(): 7667db96d56Sopenharmony_ci pass 7677db96d56Sopenharmony_ci self.check_wrapper(wrapper, f, assign, update) 7687db96d56Sopenharmony_ci self.assertEqual(wrapper.__name__, 'wrapper') 7697db96d56Sopenharmony_ci self.assertNotEqual(wrapper.__qualname__, f.__qualname__) 7707db96d56Sopenharmony_ci self.assertEqual(wrapper.__doc__, None) 7717db96d56Sopenharmony_ci self.assertEqual(wrapper.attr, 'This is a different test') 7727db96d56Sopenharmony_ci self.assertEqual(wrapper.dict_attr, f.dict_attr) 7737db96d56Sopenharmony_ci 7747db96d56Sopenharmony_ci 7757db96d56Sopenharmony_ciclass TestReduce: 7767db96d56Sopenharmony_ci def test_reduce(self): 7777db96d56Sopenharmony_ci class Squares: 7787db96d56Sopenharmony_ci def __init__(self, max): 7797db96d56Sopenharmony_ci self.max = max 7807db96d56Sopenharmony_ci self.sofar = [] 7817db96d56Sopenharmony_ci 7827db96d56Sopenharmony_ci def __len__(self): 7837db96d56Sopenharmony_ci return len(self.sofar) 7847db96d56Sopenharmony_ci 7857db96d56Sopenharmony_ci def __getitem__(self, i): 7867db96d56Sopenharmony_ci if not 0 <= i < self.max: raise IndexError 7877db96d56Sopenharmony_ci n = len(self.sofar) 7887db96d56Sopenharmony_ci while n <= i: 7897db96d56Sopenharmony_ci self.sofar.append(n*n) 7907db96d56Sopenharmony_ci n += 1 7917db96d56Sopenharmony_ci return self.sofar[i] 7927db96d56Sopenharmony_ci def add(x, y): 7937db96d56Sopenharmony_ci return x + y 7947db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, ['a', 'b', 'c'], ''), 'abc') 7957db96d56Sopenharmony_ci self.assertEqual( 7967db96d56Sopenharmony_ci self.reduce(add, [['a', 'c'], [], ['d', 'w']], []), 7977db96d56Sopenharmony_ci ['a','c','d','w'] 7987db96d56Sopenharmony_ci ) 7997db96d56Sopenharmony_ci self.assertEqual(self.reduce(lambda x, y: x*y, range(2,8), 1), 5040) 8007db96d56Sopenharmony_ci self.assertEqual( 8017db96d56Sopenharmony_ci self.reduce(lambda x, y: x*y, range(2,21), 1), 8027db96d56Sopenharmony_ci 2432902008176640000 8037db96d56Sopenharmony_ci ) 8047db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, Squares(10)), 285) 8057db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, Squares(10), 0), 285) 8067db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, Squares(0), 0), 0) 8077db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce) 8087db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, 42, 42) 8097db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, 42, 42, 42) 8107db96d56Sopenharmony_ci self.assertEqual(self.reduce(42, "1"), "1") # func is never called with one item 8117db96d56Sopenharmony_ci self.assertEqual(self.reduce(42, "", "1"), "1") # func is never called with one item 8127db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, 42, (42, 42)) 8137db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, add, []) # arg 2 must not be empty sequence with no initial value 8147db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, add, "") 8157db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, add, ()) 8167db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, add, object()) 8177db96d56Sopenharmony_ci 8187db96d56Sopenharmony_ci class TestFailingIter: 8197db96d56Sopenharmony_ci def __iter__(self): 8207db96d56Sopenharmony_ci raise RuntimeError 8217db96d56Sopenharmony_ci self.assertRaises(RuntimeError, self.reduce, add, TestFailingIter()) 8227db96d56Sopenharmony_ci 8237db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, [], None), None) 8247db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, [], 42), 42) 8257db96d56Sopenharmony_ci 8267db96d56Sopenharmony_ci class BadSeq: 8277db96d56Sopenharmony_ci def __getitem__(self, index): 8287db96d56Sopenharmony_ci raise ValueError 8297db96d56Sopenharmony_ci self.assertRaises(ValueError, self.reduce, 42, BadSeq()) 8307db96d56Sopenharmony_ci 8317db96d56Sopenharmony_ci # Test reduce()'s use of iterators. 8327db96d56Sopenharmony_ci def test_iterator_usage(self): 8337db96d56Sopenharmony_ci class SequenceClass: 8347db96d56Sopenharmony_ci def __init__(self, n): 8357db96d56Sopenharmony_ci self.n = n 8367db96d56Sopenharmony_ci def __getitem__(self, i): 8377db96d56Sopenharmony_ci if 0 <= i < self.n: 8387db96d56Sopenharmony_ci return i 8397db96d56Sopenharmony_ci else: 8407db96d56Sopenharmony_ci raise IndexError 8417db96d56Sopenharmony_ci 8427db96d56Sopenharmony_ci from operator import add 8437db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, SequenceClass(5)), 10) 8447db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, SequenceClass(5), 42), 52) 8457db96d56Sopenharmony_ci self.assertRaises(TypeError, self.reduce, add, SequenceClass(0)) 8467db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, SequenceClass(0), 42), 42) 8477db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, SequenceClass(1)), 0) 8487db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, SequenceClass(1), 42), 42) 8497db96d56Sopenharmony_ci 8507db96d56Sopenharmony_ci d = {"one": 1, "two": 2, "three": 3} 8517db96d56Sopenharmony_ci self.assertEqual(self.reduce(add, d), "".join(d.keys())) 8527db96d56Sopenharmony_ci 8537db96d56Sopenharmony_ci 8547db96d56Sopenharmony_ci@unittest.skipUnless(c_functools, 'requires the C _functools module') 8557db96d56Sopenharmony_ciclass TestReduceC(TestReduce, unittest.TestCase): 8567db96d56Sopenharmony_ci if c_functools: 8577db96d56Sopenharmony_ci reduce = c_functools.reduce 8587db96d56Sopenharmony_ci 8597db96d56Sopenharmony_ci 8607db96d56Sopenharmony_ciclass TestReducePy(TestReduce, unittest.TestCase): 8617db96d56Sopenharmony_ci reduce = staticmethod(py_functools.reduce) 8627db96d56Sopenharmony_ci 8637db96d56Sopenharmony_ci 8647db96d56Sopenharmony_ciclass TestCmpToKey: 8657db96d56Sopenharmony_ci 8667db96d56Sopenharmony_ci def test_cmp_to_key(self): 8677db96d56Sopenharmony_ci def cmp1(x, y): 8687db96d56Sopenharmony_ci return (x > y) - (x < y) 8697db96d56Sopenharmony_ci key = self.cmp_to_key(cmp1) 8707db96d56Sopenharmony_ci self.assertEqual(key(3), key(3)) 8717db96d56Sopenharmony_ci self.assertGreater(key(3), key(1)) 8727db96d56Sopenharmony_ci self.assertGreaterEqual(key(3), key(3)) 8737db96d56Sopenharmony_ci 8747db96d56Sopenharmony_ci def cmp2(x, y): 8757db96d56Sopenharmony_ci return int(x) - int(y) 8767db96d56Sopenharmony_ci key = self.cmp_to_key(cmp2) 8777db96d56Sopenharmony_ci self.assertEqual(key(4.0), key('4')) 8787db96d56Sopenharmony_ci self.assertLess(key(2), key('35')) 8797db96d56Sopenharmony_ci self.assertLessEqual(key(2), key('35')) 8807db96d56Sopenharmony_ci self.assertNotEqual(key(2), key('35')) 8817db96d56Sopenharmony_ci 8827db96d56Sopenharmony_ci def test_cmp_to_key_arguments(self): 8837db96d56Sopenharmony_ci def cmp1(x, y): 8847db96d56Sopenharmony_ci return (x > y) - (x < y) 8857db96d56Sopenharmony_ci key = self.cmp_to_key(mycmp=cmp1) 8867db96d56Sopenharmony_ci self.assertEqual(key(obj=3), key(obj=3)) 8877db96d56Sopenharmony_ci self.assertGreater(key(obj=3), key(obj=1)) 8887db96d56Sopenharmony_ci with self.assertRaises((TypeError, AttributeError)): 8897db96d56Sopenharmony_ci key(3) > 1 # rhs is not a K object 8907db96d56Sopenharmony_ci with self.assertRaises((TypeError, AttributeError)): 8917db96d56Sopenharmony_ci 1 < key(3) # lhs is not a K object 8927db96d56Sopenharmony_ci with self.assertRaises(TypeError): 8937db96d56Sopenharmony_ci key = self.cmp_to_key() # too few args 8947db96d56Sopenharmony_ci with self.assertRaises(TypeError): 8957db96d56Sopenharmony_ci key = self.cmp_to_key(cmp1, None) # too many args 8967db96d56Sopenharmony_ci key = self.cmp_to_key(cmp1) 8977db96d56Sopenharmony_ci with self.assertRaises(TypeError): 8987db96d56Sopenharmony_ci key() # too few args 8997db96d56Sopenharmony_ci with self.assertRaises(TypeError): 9007db96d56Sopenharmony_ci key(None, None) # too many args 9017db96d56Sopenharmony_ci 9027db96d56Sopenharmony_ci def test_bad_cmp(self): 9037db96d56Sopenharmony_ci def cmp1(x, y): 9047db96d56Sopenharmony_ci raise ZeroDivisionError 9057db96d56Sopenharmony_ci key = self.cmp_to_key(cmp1) 9067db96d56Sopenharmony_ci with self.assertRaises(ZeroDivisionError): 9077db96d56Sopenharmony_ci key(3) > key(1) 9087db96d56Sopenharmony_ci 9097db96d56Sopenharmony_ci class BadCmp: 9107db96d56Sopenharmony_ci def __lt__(self, other): 9117db96d56Sopenharmony_ci raise ZeroDivisionError 9127db96d56Sopenharmony_ci def cmp1(x, y): 9137db96d56Sopenharmony_ci return BadCmp() 9147db96d56Sopenharmony_ci with self.assertRaises(ZeroDivisionError): 9157db96d56Sopenharmony_ci key(3) > key(1) 9167db96d56Sopenharmony_ci 9177db96d56Sopenharmony_ci def test_obj_field(self): 9187db96d56Sopenharmony_ci def cmp1(x, y): 9197db96d56Sopenharmony_ci return (x > y) - (x < y) 9207db96d56Sopenharmony_ci key = self.cmp_to_key(mycmp=cmp1) 9217db96d56Sopenharmony_ci self.assertEqual(key(50).obj, 50) 9227db96d56Sopenharmony_ci 9237db96d56Sopenharmony_ci def test_sort_int(self): 9247db96d56Sopenharmony_ci def mycmp(x, y): 9257db96d56Sopenharmony_ci return y - x 9267db96d56Sopenharmony_ci self.assertEqual(sorted(range(5), key=self.cmp_to_key(mycmp)), 9277db96d56Sopenharmony_ci [4, 3, 2, 1, 0]) 9287db96d56Sopenharmony_ci 9297db96d56Sopenharmony_ci def test_sort_int_str(self): 9307db96d56Sopenharmony_ci def mycmp(x, y): 9317db96d56Sopenharmony_ci x, y = int(x), int(y) 9327db96d56Sopenharmony_ci return (x > y) - (x < y) 9337db96d56Sopenharmony_ci values = [5, '3', 7, 2, '0', '1', 4, '10', 1] 9347db96d56Sopenharmony_ci values = sorted(values, key=self.cmp_to_key(mycmp)) 9357db96d56Sopenharmony_ci self.assertEqual([int(value) for value in values], 9367db96d56Sopenharmony_ci [0, 1, 1, 2, 3, 4, 5, 7, 10]) 9377db96d56Sopenharmony_ci 9387db96d56Sopenharmony_ci def test_hash(self): 9397db96d56Sopenharmony_ci def mycmp(x, y): 9407db96d56Sopenharmony_ci return y - x 9417db96d56Sopenharmony_ci key = self.cmp_to_key(mycmp) 9427db96d56Sopenharmony_ci k = key(10) 9437db96d56Sopenharmony_ci self.assertRaises(TypeError, hash, k) 9447db96d56Sopenharmony_ci self.assertNotIsInstance(k, collections.abc.Hashable) 9457db96d56Sopenharmony_ci 9467db96d56Sopenharmony_ci 9477db96d56Sopenharmony_ci@unittest.skipUnless(c_functools, 'requires the C _functools module') 9487db96d56Sopenharmony_ciclass TestCmpToKeyC(TestCmpToKey, unittest.TestCase): 9497db96d56Sopenharmony_ci if c_functools: 9507db96d56Sopenharmony_ci cmp_to_key = c_functools.cmp_to_key 9517db96d56Sopenharmony_ci 9527db96d56Sopenharmony_ci @support.cpython_only 9537db96d56Sopenharmony_ci def test_disallow_instantiation(self): 9547db96d56Sopenharmony_ci # Ensure that the type disallows instantiation (bpo-43916) 9557db96d56Sopenharmony_ci support.check_disallow_instantiation( 9567db96d56Sopenharmony_ci self, type(c_functools.cmp_to_key(None)) 9577db96d56Sopenharmony_ci ) 9587db96d56Sopenharmony_ci 9597db96d56Sopenharmony_ci 9607db96d56Sopenharmony_ciclass TestCmpToKeyPy(TestCmpToKey, unittest.TestCase): 9617db96d56Sopenharmony_ci cmp_to_key = staticmethod(py_functools.cmp_to_key) 9627db96d56Sopenharmony_ci 9637db96d56Sopenharmony_ci 9647db96d56Sopenharmony_ciclass TestTotalOrdering(unittest.TestCase): 9657db96d56Sopenharmony_ci 9667db96d56Sopenharmony_ci def test_total_ordering_lt(self): 9677db96d56Sopenharmony_ci @functools.total_ordering 9687db96d56Sopenharmony_ci class A: 9697db96d56Sopenharmony_ci def __init__(self, value): 9707db96d56Sopenharmony_ci self.value = value 9717db96d56Sopenharmony_ci def __lt__(self, other): 9727db96d56Sopenharmony_ci return self.value < other.value 9737db96d56Sopenharmony_ci def __eq__(self, other): 9747db96d56Sopenharmony_ci return self.value == other.value 9757db96d56Sopenharmony_ci self.assertTrue(A(1) < A(2)) 9767db96d56Sopenharmony_ci self.assertTrue(A(2) > A(1)) 9777db96d56Sopenharmony_ci self.assertTrue(A(1) <= A(2)) 9787db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(1)) 9797db96d56Sopenharmony_ci self.assertTrue(A(2) <= A(2)) 9807db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(2)) 9817db96d56Sopenharmony_ci self.assertFalse(A(1) > A(2)) 9827db96d56Sopenharmony_ci 9837db96d56Sopenharmony_ci def test_total_ordering_le(self): 9847db96d56Sopenharmony_ci @functools.total_ordering 9857db96d56Sopenharmony_ci class A: 9867db96d56Sopenharmony_ci def __init__(self, value): 9877db96d56Sopenharmony_ci self.value = value 9887db96d56Sopenharmony_ci def __le__(self, other): 9897db96d56Sopenharmony_ci return self.value <= other.value 9907db96d56Sopenharmony_ci def __eq__(self, other): 9917db96d56Sopenharmony_ci return self.value == other.value 9927db96d56Sopenharmony_ci self.assertTrue(A(1) < A(2)) 9937db96d56Sopenharmony_ci self.assertTrue(A(2) > A(1)) 9947db96d56Sopenharmony_ci self.assertTrue(A(1) <= A(2)) 9957db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(1)) 9967db96d56Sopenharmony_ci self.assertTrue(A(2) <= A(2)) 9977db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(2)) 9987db96d56Sopenharmony_ci self.assertFalse(A(1) >= A(2)) 9997db96d56Sopenharmony_ci 10007db96d56Sopenharmony_ci def test_total_ordering_gt(self): 10017db96d56Sopenharmony_ci @functools.total_ordering 10027db96d56Sopenharmony_ci class A: 10037db96d56Sopenharmony_ci def __init__(self, value): 10047db96d56Sopenharmony_ci self.value = value 10057db96d56Sopenharmony_ci def __gt__(self, other): 10067db96d56Sopenharmony_ci return self.value > other.value 10077db96d56Sopenharmony_ci def __eq__(self, other): 10087db96d56Sopenharmony_ci return self.value == other.value 10097db96d56Sopenharmony_ci self.assertTrue(A(1) < A(2)) 10107db96d56Sopenharmony_ci self.assertTrue(A(2) > A(1)) 10117db96d56Sopenharmony_ci self.assertTrue(A(1) <= A(2)) 10127db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(1)) 10137db96d56Sopenharmony_ci self.assertTrue(A(2) <= A(2)) 10147db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(2)) 10157db96d56Sopenharmony_ci self.assertFalse(A(2) < A(1)) 10167db96d56Sopenharmony_ci 10177db96d56Sopenharmony_ci def test_total_ordering_ge(self): 10187db96d56Sopenharmony_ci @functools.total_ordering 10197db96d56Sopenharmony_ci class A: 10207db96d56Sopenharmony_ci def __init__(self, value): 10217db96d56Sopenharmony_ci self.value = value 10227db96d56Sopenharmony_ci def __ge__(self, other): 10237db96d56Sopenharmony_ci return self.value >= other.value 10247db96d56Sopenharmony_ci def __eq__(self, other): 10257db96d56Sopenharmony_ci return self.value == other.value 10267db96d56Sopenharmony_ci self.assertTrue(A(1) < A(2)) 10277db96d56Sopenharmony_ci self.assertTrue(A(2) > A(1)) 10287db96d56Sopenharmony_ci self.assertTrue(A(1) <= A(2)) 10297db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(1)) 10307db96d56Sopenharmony_ci self.assertTrue(A(2) <= A(2)) 10317db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(2)) 10327db96d56Sopenharmony_ci self.assertFalse(A(2) <= A(1)) 10337db96d56Sopenharmony_ci 10347db96d56Sopenharmony_ci def test_total_ordering_no_overwrite(self): 10357db96d56Sopenharmony_ci # new methods should not overwrite existing 10367db96d56Sopenharmony_ci @functools.total_ordering 10377db96d56Sopenharmony_ci class A(int): 10387db96d56Sopenharmony_ci pass 10397db96d56Sopenharmony_ci self.assertTrue(A(1) < A(2)) 10407db96d56Sopenharmony_ci self.assertTrue(A(2) > A(1)) 10417db96d56Sopenharmony_ci self.assertTrue(A(1) <= A(2)) 10427db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(1)) 10437db96d56Sopenharmony_ci self.assertTrue(A(2) <= A(2)) 10447db96d56Sopenharmony_ci self.assertTrue(A(2) >= A(2)) 10457db96d56Sopenharmony_ci 10467db96d56Sopenharmony_ci def test_no_operations_defined(self): 10477db96d56Sopenharmony_ci with self.assertRaises(ValueError): 10487db96d56Sopenharmony_ci @functools.total_ordering 10497db96d56Sopenharmony_ci class A: 10507db96d56Sopenharmony_ci pass 10517db96d56Sopenharmony_ci 10527db96d56Sopenharmony_ci def test_notimplemented(self): 10537db96d56Sopenharmony_ci # Verify NotImplemented results are correctly handled 10547db96d56Sopenharmony_ci @functools.total_ordering 10557db96d56Sopenharmony_ci class ImplementsLessThan: 10567db96d56Sopenharmony_ci def __init__(self, value): 10577db96d56Sopenharmony_ci self.value = value 10587db96d56Sopenharmony_ci def __eq__(self, other): 10597db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThan): 10607db96d56Sopenharmony_ci return self.value == other.value 10617db96d56Sopenharmony_ci return False 10627db96d56Sopenharmony_ci def __lt__(self, other): 10637db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThan): 10647db96d56Sopenharmony_ci return self.value < other.value 10657db96d56Sopenharmony_ci return NotImplemented 10667db96d56Sopenharmony_ci 10677db96d56Sopenharmony_ci @functools.total_ordering 10687db96d56Sopenharmony_ci class ImplementsLessThanEqualTo: 10697db96d56Sopenharmony_ci def __init__(self, value): 10707db96d56Sopenharmony_ci self.value = value 10717db96d56Sopenharmony_ci def __eq__(self, other): 10727db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThanEqualTo): 10737db96d56Sopenharmony_ci return self.value == other.value 10747db96d56Sopenharmony_ci return False 10757db96d56Sopenharmony_ci def __le__(self, other): 10767db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThanEqualTo): 10777db96d56Sopenharmony_ci return self.value <= other.value 10787db96d56Sopenharmony_ci return NotImplemented 10797db96d56Sopenharmony_ci 10807db96d56Sopenharmony_ci @functools.total_ordering 10817db96d56Sopenharmony_ci class ImplementsGreaterThan: 10827db96d56Sopenharmony_ci def __init__(self, value): 10837db96d56Sopenharmony_ci self.value = value 10847db96d56Sopenharmony_ci def __eq__(self, other): 10857db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThan): 10867db96d56Sopenharmony_ci return self.value == other.value 10877db96d56Sopenharmony_ci return False 10887db96d56Sopenharmony_ci def __gt__(self, other): 10897db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThan): 10907db96d56Sopenharmony_ci return self.value > other.value 10917db96d56Sopenharmony_ci return NotImplemented 10927db96d56Sopenharmony_ci 10937db96d56Sopenharmony_ci @functools.total_ordering 10947db96d56Sopenharmony_ci class ImplementsGreaterThanEqualTo: 10957db96d56Sopenharmony_ci def __init__(self, value): 10967db96d56Sopenharmony_ci self.value = value 10977db96d56Sopenharmony_ci def __eq__(self, other): 10987db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThanEqualTo): 10997db96d56Sopenharmony_ci return self.value == other.value 11007db96d56Sopenharmony_ci return False 11017db96d56Sopenharmony_ci def __ge__(self, other): 11027db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThanEqualTo): 11037db96d56Sopenharmony_ci return self.value >= other.value 11047db96d56Sopenharmony_ci return NotImplemented 11057db96d56Sopenharmony_ci 11067db96d56Sopenharmony_ci self.assertIs(ImplementsLessThan(1).__le__(1), NotImplemented) 11077db96d56Sopenharmony_ci self.assertIs(ImplementsLessThan(1).__gt__(1), NotImplemented) 11087db96d56Sopenharmony_ci self.assertIs(ImplementsLessThan(1).__ge__(1), NotImplemented) 11097db96d56Sopenharmony_ci self.assertIs(ImplementsLessThanEqualTo(1).__lt__(1), NotImplemented) 11107db96d56Sopenharmony_ci self.assertIs(ImplementsLessThanEqualTo(1).__gt__(1), NotImplemented) 11117db96d56Sopenharmony_ci self.assertIs(ImplementsLessThanEqualTo(1).__ge__(1), NotImplemented) 11127db96d56Sopenharmony_ci self.assertIs(ImplementsGreaterThan(1).__lt__(1), NotImplemented) 11137db96d56Sopenharmony_ci self.assertIs(ImplementsGreaterThan(1).__gt__(1), NotImplemented) 11147db96d56Sopenharmony_ci self.assertIs(ImplementsGreaterThan(1).__ge__(1), NotImplemented) 11157db96d56Sopenharmony_ci self.assertIs(ImplementsGreaterThanEqualTo(1).__lt__(1), NotImplemented) 11167db96d56Sopenharmony_ci self.assertIs(ImplementsGreaterThanEqualTo(1).__le__(1), NotImplemented) 11177db96d56Sopenharmony_ci self.assertIs(ImplementsGreaterThanEqualTo(1).__gt__(1), NotImplemented) 11187db96d56Sopenharmony_ci 11197db96d56Sopenharmony_ci def test_type_error_when_not_implemented(self): 11207db96d56Sopenharmony_ci # bug 10042; ensure stack overflow does not occur 11217db96d56Sopenharmony_ci # when decorated types return NotImplemented 11227db96d56Sopenharmony_ci @functools.total_ordering 11237db96d56Sopenharmony_ci class ImplementsLessThan: 11247db96d56Sopenharmony_ci def __init__(self, value): 11257db96d56Sopenharmony_ci self.value = value 11267db96d56Sopenharmony_ci def __eq__(self, other): 11277db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThan): 11287db96d56Sopenharmony_ci return self.value == other.value 11297db96d56Sopenharmony_ci return False 11307db96d56Sopenharmony_ci def __lt__(self, other): 11317db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThan): 11327db96d56Sopenharmony_ci return self.value < other.value 11337db96d56Sopenharmony_ci return NotImplemented 11347db96d56Sopenharmony_ci 11357db96d56Sopenharmony_ci @functools.total_ordering 11367db96d56Sopenharmony_ci class ImplementsGreaterThan: 11377db96d56Sopenharmony_ci def __init__(self, value): 11387db96d56Sopenharmony_ci self.value = value 11397db96d56Sopenharmony_ci def __eq__(self, other): 11407db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThan): 11417db96d56Sopenharmony_ci return self.value == other.value 11427db96d56Sopenharmony_ci return False 11437db96d56Sopenharmony_ci def __gt__(self, other): 11447db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThan): 11457db96d56Sopenharmony_ci return self.value > other.value 11467db96d56Sopenharmony_ci return NotImplemented 11477db96d56Sopenharmony_ci 11487db96d56Sopenharmony_ci @functools.total_ordering 11497db96d56Sopenharmony_ci class ImplementsLessThanEqualTo: 11507db96d56Sopenharmony_ci def __init__(self, value): 11517db96d56Sopenharmony_ci self.value = value 11527db96d56Sopenharmony_ci def __eq__(self, other): 11537db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThanEqualTo): 11547db96d56Sopenharmony_ci return self.value == other.value 11557db96d56Sopenharmony_ci return False 11567db96d56Sopenharmony_ci def __le__(self, other): 11577db96d56Sopenharmony_ci if isinstance(other, ImplementsLessThanEqualTo): 11587db96d56Sopenharmony_ci return self.value <= other.value 11597db96d56Sopenharmony_ci return NotImplemented 11607db96d56Sopenharmony_ci 11617db96d56Sopenharmony_ci @functools.total_ordering 11627db96d56Sopenharmony_ci class ImplementsGreaterThanEqualTo: 11637db96d56Sopenharmony_ci def __init__(self, value): 11647db96d56Sopenharmony_ci self.value = value 11657db96d56Sopenharmony_ci def __eq__(self, other): 11667db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThanEqualTo): 11677db96d56Sopenharmony_ci return self.value == other.value 11687db96d56Sopenharmony_ci return False 11697db96d56Sopenharmony_ci def __ge__(self, other): 11707db96d56Sopenharmony_ci if isinstance(other, ImplementsGreaterThanEqualTo): 11717db96d56Sopenharmony_ci return self.value >= other.value 11727db96d56Sopenharmony_ci return NotImplemented 11737db96d56Sopenharmony_ci 11747db96d56Sopenharmony_ci @functools.total_ordering 11757db96d56Sopenharmony_ci class ComparatorNotImplemented: 11767db96d56Sopenharmony_ci def __init__(self, value): 11777db96d56Sopenharmony_ci self.value = value 11787db96d56Sopenharmony_ci def __eq__(self, other): 11797db96d56Sopenharmony_ci if isinstance(other, ComparatorNotImplemented): 11807db96d56Sopenharmony_ci return self.value == other.value 11817db96d56Sopenharmony_ci return False 11827db96d56Sopenharmony_ci def __lt__(self, other): 11837db96d56Sopenharmony_ci return NotImplemented 11847db96d56Sopenharmony_ci 11857db96d56Sopenharmony_ci with self.subTest("LT < 1"), self.assertRaises(TypeError): 11867db96d56Sopenharmony_ci ImplementsLessThan(-1) < 1 11877db96d56Sopenharmony_ci 11887db96d56Sopenharmony_ci with self.subTest("LT < LE"), self.assertRaises(TypeError): 11897db96d56Sopenharmony_ci ImplementsLessThan(0) < ImplementsLessThanEqualTo(0) 11907db96d56Sopenharmony_ci 11917db96d56Sopenharmony_ci with self.subTest("LT < GT"), self.assertRaises(TypeError): 11927db96d56Sopenharmony_ci ImplementsLessThan(1) < ImplementsGreaterThan(1) 11937db96d56Sopenharmony_ci 11947db96d56Sopenharmony_ci with self.subTest("LE <= LT"), self.assertRaises(TypeError): 11957db96d56Sopenharmony_ci ImplementsLessThanEqualTo(2) <= ImplementsLessThan(2) 11967db96d56Sopenharmony_ci 11977db96d56Sopenharmony_ci with self.subTest("LE <= GE"), self.assertRaises(TypeError): 11987db96d56Sopenharmony_ci ImplementsLessThanEqualTo(3) <= ImplementsGreaterThanEqualTo(3) 11997db96d56Sopenharmony_ci 12007db96d56Sopenharmony_ci with self.subTest("GT > GE"), self.assertRaises(TypeError): 12017db96d56Sopenharmony_ci ImplementsGreaterThan(4) > ImplementsGreaterThanEqualTo(4) 12027db96d56Sopenharmony_ci 12037db96d56Sopenharmony_ci with self.subTest("GT > LT"), self.assertRaises(TypeError): 12047db96d56Sopenharmony_ci ImplementsGreaterThan(5) > ImplementsLessThan(5) 12057db96d56Sopenharmony_ci 12067db96d56Sopenharmony_ci with self.subTest("GE >= GT"), self.assertRaises(TypeError): 12077db96d56Sopenharmony_ci ImplementsGreaterThanEqualTo(6) >= ImplementsGreaterThan(6) 12087db96d56Sopenharmony_ci 12097db96d56Sopenharmony_ci with self.subTest("GE >= LE"), self.assertRaises(TypeError): 12107db96d56Sopenharmony_ci ImplementsGreaterThanEqualTo(7) >= ImplementsLessThanEqualTo(7) 12117db96d56Sopenharmony_ci 12127db96d56Sopenharmony_ci with self.subTest("GE when equal"): 12137db96d56Sopenharmony_ci a = ComparatorNotImplemented(8) 12147db96d56Sopenharmony_ci b = ComparatorNotImplemented(8) 12157db96d56Sopenharmony_ci self.assertEqual(a, b) 12167db96d56Sopenharmony_ci with self.assertRaises(TypeError): 12177db96d56Sopenharmony_ci a >= b 12187db96d56Sopenharmony_ci 12197db96d56Sopenharmony_ci with self.subTest("LE when equal"): 12207db96d56Sopenharmony_ci a = ComparatorNotImplemented(9) 12217db96d56Sopenharmony_ci b = ComparatorNotImplemented(9) 12227db96d56Sopenharmony_ci self.assertEqual(a, b) 12237db96d56Sopenharmony_ci with self.assertRaises(TypeError): 12247db96d56Sopenharmony_ci a <= b 12257db96d56Sopenharmony_ci 12267db96d56Sopenharmony_ci def test_pickle(self): 12277db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 12287db96d56Sopenharmony_ci for name in '__lt__', '__gt__', '__le__', '__ge__': 12297db96d56Sopenharmony_ci with self.subTest(method=name, proto=proto): 12307db96d56Sopenharmony_ci method = getattr(Orderable_LT, name) 12317db96d56Sopenharmony_ci method_copy = pickle.loads(pickle.dumps(method, proto)) 12327db96d56Sopenharmony_ci self.assertIs(method_copy, method) 12337db96d56Sopenharmony_ci 12347db96d56Sopenharmony_ci 12357db96d56Sopenharmony_ci def test_total_ordering_for_metaclasses_issue_44605(self): 12367db96d56Sopenharmony_ci 12377db96d56Sopenharmony_ci @functools.total_ordering 12387db96d56Sopenharmony_ci class SortableMeta(type): 12397db96d56Sopenharmony_ci def __new__(cls, name, bases, ns): 12407db96d56Sopenharmony_ci return super().__new__(cls, name, bases, ns) 12417db96d56Sopenharmony_ci 12427db96d56Sopenharmony_ci def __lt__(self, other): 12437db96d56Sopenharmony_ci if not isinstance(other, SortableMeta): 12447db96d56Sopenharmony_ci pass 12457db96d56Sopenharmony_ci return self.__name__ < other.__name__ 12467db96d56Sopenharmony_ci 12477db96d56Sopenharmony_ci def __eq__(self, other): 12487db96d56Sopenharmony_ci if not isinstance(other, SortableMeta): 12497db96d56Sopenharmony_ci pass 12507db96d56Sopenharmony_ci return self.__name__ == other.__name__ 12517db96d56Sopenharmony_ci 12527db96d56Sopenharmony_ci class B(metaclass=SortableMeta): 12537db96d56Sopenharmony_ci pass 12547db96d56Sopenharmony_ci 12557db96d56Sopenharmony_ci class A(metaclass=SortableMeta): 12567db96d56Sopenharmony_ci pass 12577db96d56Sopenharmony_ci 12587db96d56Sopenharmony_ci self.assertTrue(A < B) 12597db96d56Sopenharmony_ci self.assertFalse(A > B) 12607db96d56Sopenharmony_ci 12617db96d56Sopenharmony_ci 12627db96d56Sopenharmony_ci@functools.total_ordering 12637db96d56Sopenharmony_ciclass Orderable_LT: 12647db96d56Sopenharmony_ci def __init__(self, value): 12657db96d56Sopenharmony_ci self.value = value 12667db96d56Sopenharmony_ci def __lt__(self, other): 12677db96d56Sopenharmony_ci return self.value < other.value 12687db96d56Sopenharmony_ci def __eq__(self, other): 12697db96d56Sopenharmony_ci return self.value == other.value 12707db96d56Sopenharmony_ci 12717db96d56Sopenharmony_ci 12727db96d56Sopenharmony_ciclass TestCache: 12737db96d56Sopenharmony_ci # This tests that the pass-through is working as designed. 12747db96d56Sopenharmony_ci # The underlying functionality is tested in TestLRU. 12757db96d56Sopenharmony_ci 12767db96d56Sopenharmony_ci def test_cache(self): 12777db96d56Sopenharmony_ci @self.module.cache 12787db96d56Sopenharmony_ci def fib(n): 12797db96d56Sopenharmony_ci if n < 2: 12807db96d56Sopenharmony_ci return n 12817db96d56Sopenharmony_ci return fib(n-1) + fib(n-2) 12827db96d56Sopenharmony_ci self.assertEqual([fib(n) for n in range(16)], 12837db96d56Sopenharmony_ci [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]) 12847db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 12857db96d56Sopenharmony_ci self.module._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)) 12867db96d56Sopenharmony_ci fib.cache_clear() 12877db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 12887db96d56Sopenharmony_ci self.module._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)) 12897db96d56Sopenharmony_ci 12907db96d56Sopenharmony_ci 12917db96d56Sopenharmony_ciclass TestLRU: 12927db96d56Sopenharmony_ci 12937db96d56Sopenharmony_ci def test_lru(self): 12947db96d56Sopenharmony_ci def orig(x, y): 12957db96d56Sopenharmony_ci return 3 * x + y 12967db96d56Sopenharmony_ci f = self.module.lru_cache(maxsize=20)(orig) 12977db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 12987db96d56Sopenharmony_ci self.assertEqual(maxsize, 20) 12997db96d56Sopenharmony_ci self.assertEqual(currsize, 0) 13007db96d56Sopenharmony_ci self.assertEqual(hits, 0) 13017db96d56Sopenharmony_ci self.assertEqual(misses, 0) 13027db96d56Sopenharmony_ci 13037db96d56Sopenharmony_ci domain = range(5) 13047db96d56Sopenharmony_ci for i in range(1000): 13057db96d56Sopenharmony_ci x, y = choice(domain), choice(domain) 13067db96d56Sopenharmony_ci actual = f(x, y) 13077db96d56Sopenharmony_ci expected = orig(x, y) 13087db96d56Sopenharmony_ci self.assertEqual(actual, expected) 13097db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 13107db96d56Sopenharmony_ci self.assertTrue(hits > misses) 13117db96d56Sopenharmony_ci self.assertEqual(hits + misses, 1000) 13127db96d56Sopenharmony_ci self.assertEqual(currsize, 20) 13137db96d56Sopenharmony_ci 13147db96d56Sopenharmony_ci f.cache_clear() # test clearing 13157db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 13167db96d56Sopenharmony_ci self.assertEqual(hits, 0) 13177db96d56Sopenharmony_ci self.assertEqual(misses, 0) 13187db96d56Sopenharmony_ci self.assertEqual(currsize, 0) 13197db96d56Sopenharmony_ci f(x, y) 13207db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 13217db96d56Sopenharmony_ci self.assertEqual(hits, 0) 13227db96d56Sopenharmony_ci self.assertEqual(misses, 1) 13237db96d56Sopenharmony_ci self.assertEqual(currsize, 1) 13247db96d56Sopenharmony_ci 13257db96d56Sopenharmony_ci # Test bypassing the cache 13267db96d56Sopenharmony_ci self.assertIs(f.__wrapped__, orig) 13277db96d56Sopenharmony_ci f.__wrapped__(x, y) 13287db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 13297db96d56Sopenharmony_ci self.assertEqual(hits, 0) 13307db96d56Sopenharmony_ci self.assertEqual(misses, 1) 13317db96d56Sopenharmony_ci self.assertEqual(currsize, 1) 13327db96d56Sopenharmony_ci 13337db96d56Sopenharmony_ci # test size zero (which means "never-cache") 13347db96d56Sopenharmony_ci @self.module.lru_cache(0) 13357db96d56Sopenharmony_ci def f(): 13367db96d56Sopenharmony_ci nonlocal f_cnt 13377db96d56Sopenharmony_ci f_cnt += 1 13387db96d56Sopenharmony_ci return 20 13397db96d56Sopenharmony_ci self.assertEqual(f.cache_info().maxsize, 0) 13407db96d56Sopenharmony_ci f_cnt = 0 13417db96d56Sopenharmony_ci for i in range(5): 13427db96d56Sopenharmony_ci self.assertEqual(f(), 20) 13437db96d56Sopenharmony_ci self.assertEqual(f_cnt, 5) 13447db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 13457db96d56Sopenharmony_ci self.assertEqual(hits, 0) 13467db96d56Sopenharmony_ci self.assertEqual(misses, 5) 13477db96d56Sopenharmony_ci self.assertEqual(currsize, 0) 13487db96d56Sopenharmony_ci 13497db96d56Sopenharmony_ci # test size one 13507db96d56Sopenharmony_ci @self.module.lru_cache(1) 13517db96d56Sopenharmony_ci def f(): 13527db96d56Sopenharmony_ci nonlocal f_cnt 13537db96d56Sopenharmony_ci f_cnt += 1 13547db96d56Sopenharmony_ci return 20 13557db96d56Sopenharmony_ci self.assertEqual(f.cache_info().maxsize, 1) 13567db96d56Sopenharmony_ci f_cnt = 0 13577db96d56Sopenharmony_ci for i in range(5): 13587db96d56Sopenharmony_ci self.assertEqual(f(), 20) 13597db96d56Sopenharmony_ci self.assertEqual(f_cnt, 1) 13607db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 13617db96d56Sopenharmony_ci self.assertEqual(hits, 4) 13627db96d56Sopenharmony_ci self.assertEqual(misses, 1) 13637db96d56Sopenharmony_ci self.assertEqual(currsize, 1) 13647db96d56Sopenharmony_ci 13657db96d56Sopenharmony_ci # test size two 13667db96d56Sopenharmony_ci @self.module.lru_cache(2) 13677db96d56Sopenharmony_ci def f(x): 13687db96d56Sopenharmony_ci nonlocal f_cnt 13697db96d56Sopenharmony_ci f_cnt += 1 13707db96d56Sopenharmony_ci return x*10 13717db96d56Sopenharmony_ci self.assertEqual(f.cache_info().maxsize, 2) 13727db96d56Sopenharmony_ci f_cnt = 0 13737db96d56Sopenharmony_ci for x in 7, 9, 7, 9, 7, 9, 8, 8, 8, 9, 9, 9, 8, 8, 8, 7: 13747db96d56Sopenharmony_ci # * * * * 13757db96d56Sopenharmony_ci self.assertEqual(f(x), x*10) 13767db96d56Sopenharmony_ci self.assertEqual(f_cnt, 4) 13777db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 13787db96d56Sopenharmony_ci self.assertEqual(hits, 12) 13797db96d56Sopenharmony_ci self.assertEqual(misses, 4) 13807db96d56Sopenharmony_ci self.assertEqual(currsize, 2) 13817db96d56Sopenharmony_ci 13827db96d56Sopenharmony_ci def test_lru_no_args(self): 13837db96d56Sopenharmony_ci @self.module.lru_cache 13847db96d56Sopenharmony_ci def square(x): 13857db96d56Sopenharmony_ci return x ** 2 13867db96d56Sopenharmony_ci 13877db96d56Sopenharmony_ci self.assertEqual(list(map(square, [10, 20, 10])), 13887db96d56Sopenharmony_ci [100, 400, 100]) 13897db96d56Sopenharmony_ci self.assertEqual(square.cache_info().hits, 1) 13907db96d56Sopenharmony_ci self.assertEqual(square.cache_info().misses, 2) 13917db96d56Sopenharmony_ci self.assertEqual(square.cache_info().maxsize, 128) 13927db96d56Sopenharmony_ci self.assertEqual(square.cache_info().currsize, 2) 13937db96d56Sopenharmony_ci 13947db96d56Sopenharmony_ci def test_lru_bug_35780(self): 13957db96d56Sopenharmony_ci # C version of the lru_cache was not checking to see if 13967db96d56Sopenharmony_ci # the user function call has already modified the cache 13977db96d56Sopenharmony_ci # (this arises in recursive calls and in multi-threading). 13987db96d56Sopenharmony_ci # This cause the cache to have orphan links not referenced 13997db96d56Sopenharmony_ci # by the cache dictionary. 14007db96d56Sopenharmony_ci 14017db96d56Sopenharmony_ci once = True # Modified by f(x) below 14027db96d56Sopenharmony_ci 14037db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=10) 14047db96d56Sopenharmony_ci def f(x): 14057db96d56Sopenharmony_ci nonlocal once 14067db96d56Sopenharmony_ci rv = f'.{x}.' 14077db96d56Sopenharmony_ci if x == 20 and once: 14087db96d56Sopenharmony_ci once = False 14097db96d56Sopenharmony_ci rv = f(x) 14107db96d56Sopenharmony_ci return rv 14117db96d56Sopenharmony_ci 14127db96d56Sopenharmony_ci # Fill the cache 14137db96d56Sopenharmony_ci for x in range(15): 14147db96d56Sopenharmony_ci self.assertEqual(f(x), f'.{x}.') 14157db96d56Sopenharmony_ci self.assertEqual(f.cache_info().currsize, 10) 14167db96d56Sopenharmony_ci 14177db96d56Sopenharmony_ci # Make a recursive call and make sure the cache remains full 14187db96d56Sopenharmony_ci self.assertEqual(f(20), '.20.') 14197db96d56Sopenharmony_ci self.assertEqual(f.cache_info().currsize, 10) 14207db96d56Sopenharmony_ci 14217db96d56Sopenharmony_ci def test_lru_bug_36650(self): 14227db96d56Sopenharmony_ci # C version of lru_cache was treating a call with an empty **kwargs 14237db96d56Sopenharmony_ci # dictionary as being distinct from a call with no keywords at all. 14247db96d56Sopenharmony_ci # This did not result in an incorrect answer, but it did trigger 14257db96d56Sopenharmony_ci # an unexpected cache miss. 14267db96d56Sopenharmony_ci 14277db96d56Sopenharmony_ci @self.module.lru_cache() 14287db96d56Sopenharmony_ci def f(x): 14297db96d56Sopenharmony_ci pass 14307db96d56Sopenharmony_ci 14317db96d56Sopenharmony_ci f(0) 14327db96d56Sopenharmony_ci f(0, **{}) 14337db96d56Sopenharmony_ci self.assertEqual(f.cache_info().hits, 1) 14347db96d56Sopenharmony_ci 14357db96d56Sopenharmony_ci def test_lru_hash_only_once(self): 14367db96d56Sopenharmony_ci # To protect against weird reentrancy bugs and to improve 14377db96d56Sopenharmony_ci # efficiency when faced with slow __hash__ methods, the 14387db96d56Sopenharmony_ci # LRU cache guarantees that it will only call __hash__ 14397db96d56Sopenharmony_ci # only once per use as an argument to the cached function. 14407db96d56Sopenharmony_ci 14417db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=1) 14427db96d56Sopenharmony_ci def f(x, y): 14437db96d56Sopenharmony_ci return x * 3 + y 14447db96d56Sopenharmony_ci 14457db96d56Sopenharmony_ci # Simulate the integer 5 14467db96d56Sopenharmony_ci mock_int = unittest.mock.Mock() 14477db96d56Sopenharmony_ci mock_int.__mul__ = unittest.mock.Mock(return_value=15) 14487db96d56Sopenharmony_ci mock_int.__hash__ = unittest.mock.Mock(return_value=999) 14497db96d56Sopenharmony_ci 14507db96d56Sopenharmony_ci # Add to cache: One use as an argument gives one call 14517db96d56Sopenharmony_ci self.assertEqual(f(mock_int, 1), 16) 14527db96d56Sopenharmony_ci self.assertEqual(mock_int.__hash__.call_count, 1) 14537db96d56Sopenharmony_ci self.assertEqual(f.cache_info(), (0, 1, 1, 1)) 14547db96d56Sopenharmony_ci 14557db96d56Sopenharmony_ci # Cache hit: One use as an argument gives one additional call 14567db96d56Sopenharmony_ci self.assertEqual(f(mock_int, 1), 16) 14577db96d56Sopenharmony_ci self.assertEqual(mock_int.__hash__.call_count, 2) 14587db96d56Sopenharmony_ci self.assertEqual(f.cache_info(), (1, 1, 1, 1)) 14597db96d56Sopenharmony_ci 14607db96d56Sopenharmony_ci # Cache eviction: No use as an argument gives no additional call 14617db96d56Sopenharmony_ci self.assertEqual(f(6, 2), 20) 14627db96d56Sopenharmony_ci self.assertEqual(mock_int.__hash__.call_count, 2) 14637db96d56Sopenharmony_ci self.assertEqual(f.cache_info(), (1, 2, 1, 1)) 14647db96d56Sopenharmony_ci 14657db96d56Sopenharmony_ci # Cache miss: One use as an argument gives one additional call 14667db96d56Sopenharmony_ci self.assertEqual(f(mock_int, 1), 16) 14677db96d56Sopenharmony_ci self.assertEqual(mock_int.__hash__.call_count, 3) 14687db96d56Sopenharmony_ci self.assertEqual(f.cache_info(), (1, 3, 1, 1)) 14697db96d56Sopenharmony_ci 14707db96d56Sopenharmony_ci def test_lru_reentrancy_with_len(self): 14717db96d56Sopenharmony_ci # Test to make sure the LRU cache code isn't thrown-off by 14727db96d56Sopenharmony_ci # caching the built-in len() function. Since len() can be 14737db96d56Sopenharmony_ci # cached, we shouldn't use it inside the lru code itself. 14747db96d56Sopenharmony_ci old_len = builtins.len 14757db96d56Sopenharmony_ci try: 14767db96d56Sopenharmony_ci builtins.len = self.module.lru_cache(4)(len) 14777db96d56Sopenharmony_ci for i in [0, 0, 1, 2, 3, 3, 4, 5, 6, 1, 7, 2, 1]: 14787db96d56Sopenharmony_ci self.assertEqual(len('abcdefghijklmn'[:i]), i) 14797db96d56Sopenharmony_ci finally: 14807db96d56Sopenharmony_ci builtins.len = old_len 14817db96d56Sopenharmony_ci 14827db96d56Sopenharmony_ci def test_lru_star_arg_handling(self): 14837db96d56Sopenharmony_ci # Test regression that arose in ea064ff3c10f 14847db96d56Sopenharmony_ci @self.module.lru_cache() 14857db96d56Sopenharmony_ci def f(*args): 14867db96d56Sopenharmony_ci return args 14877db96d56Sopenharmony_ci 14887db96d56Sopenharmony_ci self.assertEqual(f(1, 2), (1, 2)) 14897db96d56Sopenharmony_ci self.assertEqual(f((1, 2)), ((1, 2),)) 14907db96d56Sopenharmony_ci 14917db96d56Sopenharmony_ci def test_lru_type_error(self): 14927db96d56Sopenharmony_ci # Regression test for issue #28653. 14937db96d56Sopenharmony_ci # lru_cache was leaking when one of the arguments 14947db96d56Sopenharmony_ci # wasn't cacheable. 14957db96d56Sopenharmony_ci 14967db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=None) 14977db96d56Sopenharmony_ci def infinite_cache(o): 14987db96d56Sopenharmony_ci pass 14997db96d56Sopenharmony_ci 15007db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=10) 15017db96d56Sopenharmony_ci def limited_cache(o): 15027db96d56Sopenharmony_ci pass 15037db96d56Sopenharmony_ci 15047db96d56Sopenharmony_ci with self.assertRaises(TypeError): 15057db96d56Sopenharmony_ci infinite_cache([]) 15067db96d56Sopenharmony_ci 15077db96d56Sopenharmony_ci with self.assertRaises(TypeError): 15087db96d56Sopenharmony_ci limited_cache([]) 15097db96d56Sopenharmony_ci 15107db96d56Sopenharmony_ci def test_lru_with_maxsize_none(self): 15117db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=None) 15127db96d56Sopenharmony_ci def fib(n): 15137db96d56Sopenharmony_ci if n < 2: 15147db96d56Sopenharmony_ci return n 15157db96d56Sopenharmony_ci return fib(n-1) + fib(n-2) 15167db96d56Sopenharmony_ci self.assertEqual([fib(n) for n in range(16)], 15177db96d56Sopenharmony_ci [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]) 15187db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 15197db96d56Sopenharmony_ci self.module._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)) 15207db96d56Sopenharmony_ci fib.cache_clear() 15217db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 15227db96d56Sopenharmony_ci self.module._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)) 15237db96d56Sopenharmony_ci 15247db96d56Sopenharmony_ci def test_lru_with_maxsize_negative(self): 15257db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=-10) 15267db96d56Sopenharmony_ci def eq(n): 15277db96d56Sopenharmony_ci return n 15287db96d56Sopenharmony_ci for i in (0, 1): 15297db96d56Sopenharmony_ci self.assertEqual([eq(n) for n in range(150)], list(range(150))) 15307db96d56Sopenharmony_ci self.assertEqual(eq.cache_info(), 15317db96d56Sopenharmony_ci self.module._CacheInfo(hits=0, misses=300, maxsize=0, currsize=0)) 15327db96d56Sopenharmony_ci 15337db96d56Sopenharmony_ci def test_lru_with_exceptions(self): 15347db96d56Sopenharmony_ci # Verify that user_function exceptions get passed through without 15357db96d56Sopenharmony_ci # creating a hard-to-read chained exception. 15367db96d56Sopenharmony_ci # http://bugs.python.org/issue13177 15377db96d56Sopenharmony_ci for maxsize in (None, 128): 15387db96d56Sopenharmony_ci @self.module.lru_cache(maxsize) 15397db96d56Sopenharmony_ci def func(i): 15407db96d56Sopenharmony_ci return 'abc'[i] 15417db96d56Sopenharmony_ci self.assertEqual(func(0), 'a') 15427db96d56Sopenharmony_ci with self.assertRaises(IndexError) as cm: 15437db96d56Sopenharmony_ci func(15) 15447db96d56Sopenharmony_ci self.assertIsNone(cm.exception.__context__) 15457db96d56Sopenharmony_ci # Verify that the previous exception did not result in a cached entry 15467db96d56Sopenharmony_ci with self.assertRaises(IndexError): 15477db96d56Sopenharmony_ci func(15) 15487db96d56Sopenharmony_ci 15497db96d56Sopenharmony_ci def test_lru_with_types(self): 15507db96d56Sopenharmony_ci for maxsize in (None, 128): 15517db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=maxsize, typed=True) 15527db96d56Sopenharmony_ci def square(x): 15537db96d56Sopenharmony_ci return x * x 15547db96d56Sopenharmony_ci self.assertEqual(square(3), 9) 15557db96d56Sopenharmony_ci self.assertEqual(type(square(3)), type(9)) 15567db96d56Sopenharmony_ci self.assertEqual(square(3.0), 9.0) 15577db96d56Sopenharmony_ci self.assertEqual(type(square(3.0)), type(9.0)) 15587db96d56Sopenharmony_ci self.assertEqual(square(x=3), 9) 15597db96d56Sopenharmony_ci self.assertEqual(type(square(x=3)), type(9)) 15607db96d56Sopenharmony_ci self.assertEqual(square(x=3.0), 9.0) 15617db96d56Sopenharmony_ci self.assertEqual(type(square(x=3.0)), type(9.0)) 15627db96d56Sopenharmony_ci self.assertEqual(square.cache_info().hits, 4) 15637db96d56Sopenharmony_ci self.assertEqual(square.cache_info().misses, 4) 15647db96d56Sopenharmony_ci 15657db96d56Sopenharmony_ci def test_lru_cache_typed_is_not_recursive(self): 15667db96d56Sopenharmony_ci cached = self.module.lru_cache(typed=True)(repr) 15677db96d56Sopenharmony_ci 15687db96d56Sopenharmony_ci self.assertEqual(cached(1), '1') 15697db96d56Sopenharmony_ci self.assertEqual(cached(True), 'True') 15707db96d56Sopenharmony_ci self.assertEqual(cached(1.0), '1.0') 15717db96d56Sopenharmony_ci self.assertEqual(cached(0), '0') 15727db96d56Sopenharmony_ci self.assertEqual(cached(False), 'False') 15737db96d56Sopenharmony_ci self.assertEqual(cached(0.0), '0.0') 15747db96d56Sopenharmony_ci 15757db96d56Sopenharmony_ci self.assertEqual(cached((1,)), '(1,)') 15767db96d56Sopenharmony_ci self.assertEqual(cached((True,)), '(1,)') 15777db96d56Sopenharmony_ci self.assertEqual(cached((1.0,)), '(1,)') 15787db96d56Sopenharmony_ci self.assertEqual(cached((0,)), '(0,)') 15797db96d56Sopenharmony_ci self.assertEqual(cached((False,)), '(0,)') 15807db96d56Sopenharmony_ci self.assertEqual(cached((0.0,)), '(0,)') 15817db96d56Sopenharmony_ci 15827db96d56Sopenharmony_ci class T(tuple): 15837db96d56Sopenharmony_ci pass 15847db96d56Sopenharmony_ci 15857db96d56Sopenharmony_ci self.assertEqual(cached(T((1,))), '(1,)') 15867db96d56Sopenharmony_ci self.assertEqual(cached(T((True,))), '(1,)') 15877db96d56Sopenharmony_ci self.assertEqual(cached(T((1.0,))), '(1,)') 15887db96d56Sopenharmony_ci self.assertEqual(cached(T((0,))), '(0,)') 15897db96d56Sopenharmony_ci self.assertEqual(cached(T((False,))), '(0,)') 15907db96d56Sopenharmony_ci self.assertEqual(cached(T((0.0,))), '(0,)') 15917db96d56Sopenharmony_ci 15927db96d56Sopenharmony_ci def test_lru_with_keyword_args(self): 15937db96d56Sopenharmony_ci @self.module.lru_cache() 15947db96d56Sopenharmony_ci def fib(n): 15957db96d56Sopenharmony_ci if n < 2: 15967db96d56Sopenharmony_ci return n 15977db96d56Sopenharmony_ci return fib(n=n-1) + fib(n=n-2) 15987db96d56Sopenharmony_ci self.assertEqual( 15997db96d56Sopenharmony_ci [fib(n=number) for number in range(16)], 16007db96d56Sopenharmony_ci [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] 16017db96d56Sopenharmony_ci ) 16027db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 16037db96d56Sopenharmony_ci self.module._CacheInfo(hits=28, misses=16, maxsize=128, currsize=16)) 16047db96d56Sopenharmony_ci fib.cache_clear() 16057db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 16067db96d56Sopenharmony_ci self.module._CacheInfo(hits=0, misses=0, maxsize=128, currsize=0)) 16077db96d56Sopenharmony_ci 16087db96d56Sopenharmony_ci def test_lru_with_keyword_args_maxsize_none(self): 16097db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=None) 16107db96d56Sopenharmony_ci def fib(n): 16117db96d56Sopenharmony_ci if n < 2: 16127db96d56Sopenharmony_ci return n 16137db96d56Sopenharmony_ci return fib(n=n-1) + fib(n=n-2) 16147db96d56Sopenharmony_ci self.assertEqual([fib(n=number) for number in range(16)], 16157db96d56Sopenharmony_ci [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]) 16167db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 16177db96d56Sopenharmony_ci self.module._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)) 16187db96d56Sopenharmony_ci fib.cache_clear() 16197db96d56Sopenharmony_ci self.assertEqual(fib.cache_info(), 16207db96d56Sopenharmony_ci self.module._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)) 16217db96d56Sopenharmony_ci 16227db96d56Sopenharmony_ci def test_kwargs_order(self): 16237db96d56Sopenharmony_ci # PEP 468: Preserving Keyword Argument Order 16247db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=10) 16257db96d56Sopenharmony_ci def f(**kwargs): 16267db96d56Sopenharmony_ci return list(kwargs.items()) 16277db96d56Sopenharmony_ci self.assertEqual(f(a=1, b=2), [('a', 1), ('b', 2)]) 16287db96d56Sopenharmony_ci self.assertEqual(f(b=2, a=1), [('b', 2), ('a', 1)]) 16297db96d56Sopenharmony_ci self.assertEqual(f.cache_info(), 16307db96d56Sopenharmony_ci self.module._CacheInfo(hits=0, misses=2, maxsize=10, currsize=2)) 16317db96d56Sopenharmony_ci 16327db96d56Sopenharmony_ci def test_lru_cache_decoration(self): 16337db96d56Sopenharmony_ci def f(zomg: 'zomg_annotation'): 16347db96d56Sopenharmony_ci """f doc string""" 16357db96d56Sopenharmony_ci return 42 16367db96d56Sopenharmony_ci g = self.module.lru_cache()(f) 16377db96d56Sopenharmony_ci for attr in self.module.WRAPPER_ASSIGNMENTS: 16387db96d56Sopenharmony_ci self.assertEqual(getattr(g, attr), getattr(f, attr)) 16397db96d56Sopenharmony_ci 16407db96d56Sopenharmony_ci @threading_helper.requires_working_threading() 16417db96d56Sopenharmony_ci def test_lru_cache_threaded(self): 16427db96d56Sopenharmony_ci n, m = 5, 11 16437db96d56Sopenharmony_ci def orig(x, y): 16447db96d56Sopenharmony_ci return 3 * x + y 16457db96d56Sopenharmony_ci f = self.module.lru_cache(maxsize=n*m)(orig) 16467db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 16477db96d56Sopenharmony_ci self.assertEqual(currsize, 0) 16487db96d56Sopenharmony_ci 16497db96d56Sopenharmony_ci start = threading.Event() 16507db96d56Sopenharmony_ci def full(k): 16517db96d56Sopenharmony_ci start.wait(10) 16527db96d56Sopenharmony_ci for _ in range(m): 16537db96d56Sopenharmony_ci self.assertEqual(f(k, 0), orig(k, 0)) 16547db96d56Sopenharmony_ci 16557db96d56Sopenharmony_ci def clear(): 16567db96d56Sopenharmony_ci start.wait(10) 16577db96d56Sopenharmony_ci for _ in range(2*m): 16587db96d56Sopenharmony_ci f.cache_clear() 16597db96d56Sopenharmony_ci 16607db96d56Sopenharmony_ci orig_si = sys.getswitchinterval() 16617db96d56Sopenharmony_ci support.setswitchinterval(1e-6) 16627db96d56Sopenharmony_ci try: 16637db96d56Sopenharmony_ci # create n threads in order to fill cache 16647db96d56Sopenharmony_ci threads = [threading.Thread(target=full, args=[k]) 16657db96d56Sopenharmony_ci for k in range(n)] 16667db96d56Sopenharmony_ci with threading_helper.start_threads(threads): 16677db96d56Sopenharmony_ci start.set() 16687db96d56Sopenharmony_ci 16697db96d56Sopenharmony_ci hits, misses, maxsize, currsize = f.cache_info() 16707db96d56Sopenharmony_ci if self.module is py_functools: 16717db96d56Sopenharmony_ci # XXX: Why can be not equal? 16727db96d56Sopenharmony_ci self.assertLessEqual(misses, n) 16737db96d56Sopenharmony_ci self.assertLessEqual(hits, m*n - misses) 16747db96d56Sopenharmony_ci else: 16757db96d56Sopenharmony_ci self.assertEqual(misses, n) 16767db96d56Sopenharmony_ci self.assertEqual(hits, m*n - misses) 16777db96d56Sopenharmony_ci self.assertEqual(currsize, n) 16787db96d56Sopenharmony_ci 16797db96d56Sopenharmony_ci # create n threads in order to fill cache and 1 to clear it 16807db96d56Sopenharmony_ci threads = [threading.Thread(target=clear)] 16817db96d56Sopenharmony_ci threads += [threading.Thread(target=full, args=[k]) 16827db96d56Sopenharmony_ci for k in range(n)] 16837db96d56Sopenharmony_ci start.clear() 16847db96d56Sopenharmony_ci with threading_helper.start_threads(threads): 16857db96d56Sopenharmony_ci start.set() 16867db96d56Sopenharmony_ci finally: 16877db96d56Sopenharmony_ci sys.setswitchinterval(orig_si) 16887db96d56Sopenharmony_ci 16897db96d56Sopenharmony_ci @threading_helper.requires_working_threading() 16907db96d56Sopenharmony_ci def test_lru_cache_threaded2(self): 16917db96d56Sopenharmony_ci # Simultaneous call with the same arguments 16927db96d56Sopenharmony_ci n, m = 5, 7 16937db96d56Sopenharmony_ci start = threading.Barrier(n+1) 16947db96d56Sopenharmony_ci pause = threading.Barrier(n+1) 16957db96d56Sopenharmony_ci stop = threading.Barrier(n+1) 16967db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=m*n) 16977db96d56Sopenharmony_ci def f(x): 16987db96d56Sopenharmony_ci pause.wait(10) 16997db96d56Sopenharmony_ci return 3 * x 17007db96d56Sopenharmony_ci self.assertEqual(f.cache_info(), (0, 0, m*n, 0)) 17017db96d56Sopenharmony_ci def test(): 17027db96d56Sopenharmony_ci for i in range(m): 17037db96d56Sopenharmony_ci start.wait(10) 17047db96d56Sopenharmony_ci self.assertEqual(f(i), 3 * i) 17057db96d56Sopenharmony_ci stop.wait(10) 17067db96d56Sopenharmony_ci threads = [threading.Thread(target=test) for k in range(n)] 17077db96d56Sopenharmony_ci with threading_helper.start_threads(threads): 17087db96d56Sopenharmony_ci for i in range(m): 17097db96d56Sopenharmony_ci start.wait(10) 17107db96d56Sopenharmony_ci stop.reset() 17117db96d56Sopenharmony_ci pause.wait(10) 17127db96d56Sopenharmony_ci start.reset() 17137db96d56Sopenharmony_ci stop.wait(10) 17147db96d56Sopenharmony_ci pause.reset() 17157db96d56Sopenharmony_ci self.assertEqual(f.cache_info(), (0, (i+1)*n, m*n, i+1)) 17167db96d56Sopenharmony_ci 17177db96d56Sopenharmony_ci @threading_helper.requires_working_threading() 17187db96d56Sopenharmony_ci def test_lru_cache_threaded3(self): 17197db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=2) 17207db96d56Sopenharmony_ci def f(x): 17217db96d56Sopenharmony_ci time.sleep(.01) 17227db96d56Sopenharmony_ci return 3 * x 17237db96d56Sopenharmony_ci def test(i, x): 17247db96d56Sopenharmony_ci with self.subTest(thread=i): 17257db96d56Sopenharmony_ci self.assertEqual(f(x), 3 * x, i) 17267db96d56Sopenharmony_ci threads = [threading.Thread(target=test, args=(i, v)) 17277db96d56Sopenharmony_ci for i, v in enumerate([1, 2, 2, 3, 2])] 17287db96d56Sopenharmony_ci with threading_helper.start_threads(threads): 17297db96d56Sopenharmony_ci pass 17307db96d56Sopenharmony_ci 17317db96d56Sopenharmony_ci def test_need_for_rlock(self): 17327db96d56Sopenharmony_ci # This will deadlock on an LRU cache that uses a regular lock 17337db96d56Sopenharmony_ci 17347db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=10) 17357db96d56Sopenharmony_ci def test_func(x): 17367db96d56Sopenharmony_ci 'Used to demonstrate a reentrant lru_cache call within a single thread' 17377db96d56Sopenharmony_ci return x 17387db96d56Sopenharmony_ci 17397db96d56Sopenharmony_ci class DoubleEq: 17407db96d56Sopenharmony_ci 'Demonstrate a reentrant lru_cache call within a single thread' 17417db96d56Sopenharmony_ci def __init__(self, x): 17427db96d56Sopenharmony_ci self.x = x 17437db96d56Sopenharmony_ci def __hash__(self): 17447db96d56Sopenharmony_ci return self.x 17457db96d56Sopenharmony_ci def __eq__(self, other): 17467db96d56Sopenharmony_ci if self.x == 2: 17477db96d56Sopenharmony_ci test_func(DoubleEq(1)) 17487db96d56Sopenharmony_ci return self.x == other.x 17497db96d56Sopenharmony_ci 17507db96d56Sopenharmony_ci test_func(DoubleEq(1)) # Load the cache 17517db96d56Sopenharmony_ci test_func(DoubleEq(2)) # Load the cache 17527db96d56Sopenharmony_ci self.assertEqual(test_func(DoubleEq(2)), # Trigger a re-entrant __eq__ call 17537db96d56Sopenharmony_ci DoubleEq(2)) # Verify the correct return value 17547db96d56Sopenharmony_ci 17557db96d56Sopenharmony_ci def test_lru_method(self): 17567db96d56Sopenharmony_ci class X(int): 17577db96d56Sopenharmony_ci f_cnt = 0 17587db96d56Sopenharmony_ci @self.module.lru_cache(2) 17597db96d56Sopenharmony_ci def f(self, x): 17607db96d56Sopenharmony_ci self.f_cnt += 1 17617db96d56Sopenharmony_ci return x*10+self 17627db96d56Sopenharmony_ci a = X(5) 17637db96d56Sopenharmony_ci b = X(5) 17647db96d56Sopenharmony_ci c = X(7) 17657db96d56Sopenharmony_ci self.assertEqual(X.f.cache_info(), (0, 0, 2, 0)) 17667db96d56Sopenharmony_ci 17677db96d56Sopenharmony_ci for x in 1, 2, 2, 3, 1, 1, 1, 2, 3, 3: 17687db96d56Sopenharmony_ci self.assertEqual(a.f(x), x*10 + 5) 17697db96d56Sopenharmony_ci self.assertEqual((a.f_cnt, b.f_cnt, c.f_cnt), (6, 0, 0)) 17707db96d56Sopenharmony_ci self.assertEqual(X.f.cache_info(), (4, 6, 2, 2)) 17717db96d56Sopenharmony_ci 17727db96d56Sopenharmony_ci for x in 1, 2, 1, 1, 1, 1, 3, 2, 2, 2: 17737db96d56Sopenharmony_ci self.assertEqual(b.f(x), x*10 + 5) 17747db96d56Sopenharmony_ci self.assertEqual((a.f_cnt, b.f_cnt, c.f_cnt), (6, 4, 0)) 17757db96d56Sopenharmony_ci self.assertEqual(X.f.cache_info(), (10, 10, 2, 2)) 17767db96d56Sopenharmony_ci 17777db96d56Sopenharmony_ci for x in 2, 1, 1, 1, 1, 2, 1, 3, 2, 1: 17787db96d56Sopenharmony_ci self.assertEqual(c.f(x), x*10 + 7) 17797db96d56Sopenharmony_ci self.assertEqual((a.f_cnt, b.f_cnt, c.f_cnt), (6, 4, 5)) 17807db96d56Sopenharmony_ci self.assertEqual(X.f.cache_info(), (15, 15, 2, 2)) 17817db96d56Sopenharmony_ci 17827db96d56Sopenharmony_ci self.assertEqual(a.f.cache_info(), X.f.cache_info()) 17837db96d56Sopenharmony_ci self.assertEqual(b.f.cache_info(), X.f.cache_info()) 17847db96d56Sopenharmony_ci self.assertEqual(c.f.cache_info(), X.f.cache_info()) 17857db96d56Sopenharmony_ci 17867db96d56Sopenharmony_ci def test_pickle(self): 17877db96d56Sopenharmony_ci cls = self.__class__ 17887db96d56Sopenharmony_ci for f in cls.cached_func[0], cls.cached_meth, cls.cached_staticmeth: 17897db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 17907db96d56Sopenharmony_ci with self.subTest(proto=proto, func=f): 17917db96d56Sopenharmony_ci f_copy = pickle.loads(pickle.dumps(f, proto)) 17927db96d56Sopenharmony_ci self.assertIs(f_copy, f) 17937db96d56Sopenharmony_ci 17947db96d56Sopenharmony_ci def test_copy(self): 17957db96d56Sopenharmony_ci cls = self.__class__ 17967db96d56Sopenharmony_ci def orig(x, y): 17977db96d56Sopenharmony_ci return 3 * x + y 17987db96d56Sopenharmony_ci part = self.module.partial(orig, 2) 17997db96d56Sopenharmony_ci funcs = (cls.cached_func[0], cls.cached_meth, cls.cached_staticmeth, 18007db96d56Sopenharmony_ci self.module.lru_cache(2)(part)) 18017db96d56Sopenharmony_ci for f in funcs: 18027db96d56Sopenharmony_ci with self.subTest(func=f): 18037db96d56Sopenharmony_ci f_copy = copy.copy(f) 18047db96d56Sopenharmony_ci self.assertIs(f_copy, f) 18057db96d56Sopenharmony_ci 18067db96d56Sopenharmony_ci def test_deepcopy(self): 18077db96d56Sopenharmony_ci cls = self.__class__ 18087db96d56Sopenharmony_ci def orig(x, y): 18097db96d56Sopenharmony_ci return 3 * x + y 18107db96d56Sopenharmony_ci part = self.module.partial(orig, 2) 18117db96d56Sopenharmony_ci funcs = (cls.cached_func[0], cls.cached_meth, cls.cached_staticmeth, 18127db96d56Sopenharmony_ci self.module.lru_cache(2)(part)) 18137db96d56Sopenharmony_ci for f in funcs: 18147db96d56Sopenharmony_ci with self.subTest(func=f): 18157db96d56Sopenharmony_ci f_copy = copy.deepcopy(f) 18167db96d56Sopenharmony_ci self.assertIs(f_copy, f) 18177db96d56Sopenharmony_ci 18187db96d56Sopenharmony_ci def test_lru_cache_parameters(self): 18197db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=2) 18207db96d56Sopenharmony_ci def f(): 18217db96d56Sopenharmony_ci return 1 18227db96d56Sopenharmony_ci self.assertEqual(f.cache_parameters(), {'maxsize': 2, "typed": False}) 18237db96d56Sopenharmony_ci 18247db96d56Sopenharmony_ci @self.module.lru_cache(maxsize=1000, typed=True) 18257db96d56Sopenharmony_ci def f(): 18267db96d56Sopenharmony_ci return 1 18277db96d56Sopenharmony_ci self.assertEqual(f.cache_parameters(), {'maxsize': 1000, "typed": True}) 18287db96d56Sopenharmony_ci 18297db96d56Sopenharmony_ci def test_lru_cache_weakrefable(self): 18307db96d56Sopenharmony_ci @self.module.lru_cache 18317db96d56Sopenharmony_ci def test_function(x): 18327db96d56Sopenharmony_ci return x 18337db96d56Sopenharmony_ci 18347db96d56Sopenharmony_ci class A: 18357db96d56Sopenharmony_ci @self.module.lru_cache 18367db96d56Sopenharmony_ci def test_method(self, x): 18377db96d56Sopenharmony_ci return (self, x) 18387db96d56Sopenharmony_ci 18397db96d56Sopenharmony_ci @staticmethod 18407db96d56Sopenharmony_ci @self.module.lru_cache 18417db96d56Sopenharmony_ci def test_staticmethod(x): 18427db96d56Sopenharmony_ci return (self, x) 18437db96d56Sopenharmony_ci 18447db96d56Sopenharmony_ci refs = [weakref.ref(test_function), 18457db96d56Sopenharmony_ci weakref.ref(A.test_method), 18467db96d56Sopenharmony_ci weakref.ref(A.test_staticmethod)] 18477db96d56Sopenharmony_ci 18487db96d56Sopenharmony_ci for ref in refs: 18497db96d56Sopenharmony_ci self.assertIsNotNone(ref()) 18507db96d56Sopenharmony_ci 18517db96d56Sopenharmony_ci del A 18527db96d56Sopenharmony_ci del test_function 18537db96d56Sopenharmony_ci gc.collect() 18547db96d56Sopenharmony_ci 18557db96d56Sopenharmony_ci for ref in refs: 18567db96d56Sopenharmony_ci self.assertIsNone(ref()) 18577db96d56Sopenharmony_ci 18587db96d56Sopenharmony_ci 18597db96d56Sopenharmony_ci@py_functools.lru_cache() 18607db96d56Sopenharmony_cidef py_cached_func(x, y): 18617db96d56Sopenharmony_ci return 3 * x + y 18627db96d56Sopenharmony_ci 18637db96d56Sopenharmony_ci@c_functools.lru_cache() 18647db96d56Sopenharmony_cidef c_cached_func(x, y): 18657db96d56Sopenharmony_ci return 3 * x + y 18667db96d56Sopenharmony_ci 18677db96d56Sopenharmony_ci 18687db96d56Sopenharmony_ciclass TestLRUPy(TestLRU, unittest.TestCase): 18697db96d56Sopenharmony_ci module = py_functools 18707db96d56Sopenharmony_ci cached_func = py_cached_func, 18717db96d56Sopenharmony_ci 18727db96d56Sopenharmony_ci @module.lru_cache() 18737db96d56Sopenharmony_ci def cached_meth(self, x, y): 18747db96d56Sopenharmony_ci return 3 * x + y 18757db96d56Sopenharmony_ci 18767db96d56Sopenharmony_ci @staticmethod 18777db96d56Sopenharmony_ci @module.lru_cache() 18787db96d56Sopenharmony_ci def cached_staticmeth(x, y): 18797db96d56Sopenharmony_ci return 3 * x + y 18807db96d56Sopenharmony_ci 18817db96d56Sopenharmony_ci 18827db96d56Sopenharmony_ciclass TestLRUC(TestLRU, unittest.TestCase): 18837db96d56Sopenharmony_ci module = c_functools 18847db96d56Sopenharmony_ci cached_func = c_cached_func, 18857db96d56Sopenharmony_ci 18867db96d56Sopenharmony_ci @module.lru_cache() 18877db96d56Sopenharmony_ci def cached_meth(self, x, y): 18887db96d56Sopenharmony_ci return 3 * x + y 18897db96d56Sopenharmony_ci 18907db96d56Sopenharmony_ci @staticmethod 18917db96d56Sopenharmony_ci @module.lru_cache() 18927db96d56Sopenharmony_ci def cached_staticmeth(x, y): 18937db96d56Sopenharmony_ci return 3 * x + y 18947db96d56Sopenharmony_ci 18957db96d56Sopenharmony_ci 18967db96d56Sopenharmony_ciclass TestSingleDispatch(unittest.TestCase): 18977db96d56Sopenharmony_ci def test_simple_overloads(self): 18987db96d56Sopenharmony_ci @functools.singledispatch 18997db96d56Sopenharmony_ci def g(obj): 19007db96d56Sopenharmony_ci return "base" 19017db96d56Sopenharmony_ci def g_int(i): 19027db96d56Sopenharmony_ci return "integer" 19037db96d56Sopenharmony_ci g.register(int, g_int) 19047db96d56Sopenharmony_ci self.assertEqual(g("str"), "base") 19057db96d56Sopenharmony_ci self.assertEqual(g(1), "integer") 19067db96d56Sopenharmony_ci self.assertEqual(g([1,2,3]), "base") 19077db96d56Sopenharmony_ci 19087db96d56Sopenharmony_ci def test_mro(self): 19097db96d56Sopenharmony_ci @functools.singledispatch 19107db96d56Sopenharmony_ci def g(obj): 19117db96d56Sopenharmony_ci return "base" 19127db96d56Sopenharmony_ci class A: 19137db96d56Sopenharmony_ci pass 19147db96d56Sopenharmony_ci class C(A): 19157db96d56Sopenharmony_ci pass 19167db96d56Sopenharmony_ci class B(A): 19177db96d56Sopenharmony_ci pass 19187db96d56Sopenharmony_ci class D(C, B): 19197db96d56Sopenharmony_ci pass 19207db96d56Sopenharmony_ci def g_A(a): 19217db96d56Sopenharmony_ci return "A" 19227db96d56Sopenharmony_ci def g_B(b): 19237db96d56Sopenharmony_ci return "B" 19247db96d56Sopenharmony_ci g.register(A, g_A) 19257db96d56Sopenharmony_ci g.register(B, g_B) 19267db96d56Sopenharmony_ci self.assertEqual(g(A()), "A") 19277db96d56Sopenharmony_ci self.assertEqual(g(B()), "B") 19287db96d56Sopenharmony_ci self.assertEqual(g(C()), "A") 19297db96d56Sopenharmony_ci self.assertEqual(g(D()), "B") 19307db96d56Sopenharmony_ci 19317db96d56Sopenharmony_ci def test_register_decorator(self): 19327db96d56Sopenharmony_ci @functools.singledispatch 19337db96d56Sopenharmony_ci def g(obj): 19347db96d56Sopenharmony_ci return "base" 19357db96d56Sopenharmony_ci @g.register(int) 19367db96d56Sopenharmony_ci def g_int(i): 19377db96d56Sopenharmony_ci return "int %s" % (i,) 19387db96d56Sopenharmony_ci self.assertEqual(g(""), "base") 19397db96d56Sopenharmony_ci self.assertEqual(g(12), "int 12") 19407db96d56Sopenharmony_ci self.assertIs(g.dispatch(int), g_int) 19417db96d56Sopenharmony_ci self.assertIs(g.dispatch(object), g.dispatch(str)) 19427db96d56Sopenharmony_ci # Note: in the assert above this is not g. 19437db96d56Sopenharmony_ci # @singledispatch returns the wrapper. 19447db96d56Sopenharmony_ci 19457db96d56Sopenharmony_ci def test_wrapping_attributes(self): 19467db96d56Sopenharmony_ci @functools.singledispatch 19477db96d56Sopenharmony_ci def g(obj): 19487db96d56Sopenharmony_ci "Simple test" 19497db96d56Sopenharmony_ci return "Test" 19507db96d56Sopenharmony_ci self.assertEqual(g.__name__, "g") 19517db96d56Sopenharmony_ci if sys.flags.optimize < 2: 19527db96d56Sopenharmony_ci self.assertEqual(g.__doc__, "Simple test") 19537db96d56Sopenharmony_ci 19547db96d56Sopenharmony_ci @unittest.skipUnless(decimal, 'requires _decimal') 19557db96d56Sopenharmony_ci @support.cpython_only 19567db96d56Sopenharmony_ci def test_c_classes(self): 19577db96d56Sopenharmony_ci @functools.singledispatch 19587db96d56Sopenharmony_ci def g(obj): 19597db96d56Sopenharmony_ci return "base" 19607db96d56Sopenharmony_ci @g.register(decimal.DecimalException) 19617db96d56Sopenharmony_ci def _(obj): 19627db96d56Sopenharmony_ci return obj.args 19637db96d56Sopenharmony_ci subn = decimal.Subnormal("Exponent < Emin") 19647db96d56Sopenharmony_ci rnd = decimal.Rounded("Number got rounded") 19657db96d56Sopenharmony_ci self.assertEqual(g(subn), ("Exponent < Emin",)) 19667db96d56Sopenharmony_ci self.assertEqual(g(rnd), ("Number got rounded",)) 19677db96d56Sopenharmony_ci @g.register(decimal.Subnormal) 19687db96d56Sopenharmony_ci def _(obj): 19697db96d56Sopenharmony_ci return "Too small to care." 19707db96d56Sopenharmony_ci self.assertEqual(g(subn), "Too small to care.") 19717db96d56Sopenharmony_ci self.assertEqual(g(rnd), ("Number got rounded",)) 19727db96d56Sopenharmony_ci 19737db96d56Sopenharmony_ci def test_compose_mro(self): 19747db96d56Sopenharmony_ci # None of the examples in this test depend on haystack ordering. 19757db96d56Sopenharmony_ci c = collections.abc 19767db96d56Sopenharmony_ci mro = functools._compose_mro 19777db96d56Sopenharmony_ci bases = [c.Sequence, c.MutableMapping, c.Mapping, c.Set] 19787db96d56Sopenharmony_ci for haystack in permutations(bases): 19797db96d56Sopenharmony_ci m = mro(dict, haystack) 19807db96d56Sopenharmony_ci self.assertEqual(m, [dict, c.MutableMapping, c.Mapping, 19817db96d56Sopenharmony_ci c.Collection, c.Sized, c.Iterable, 19827db96d56Sopenharmony_ci c.Container, object]) 19837db96d56Sopenharmony_ci bases = [c.Container, c.Mapping, c.MutableMapping, collections.OrderedDict] 19847db96d56Sopenharmony_ci for haystack in permutations(bases): 19857db96d56Sopenharmony_ci m = mro(collections.ChainMap, haystack) 19867db96d56Sopenharmony_ci self.assertEqual(m, [collections.ChainMap, c.MutableMapping, c.Mapping, 19877db96d56Sopenharmony_ci c.Collection, c.Sized, c.Iterable, 19887db96d56Sopenharmony_ci c.Container, object]) 19897db96d56Sopenharmony_ci 19907db96d56Sopenharmony_ci # If there's a generic function with implementations registered for 19917db96d56Sopenharmony_ci # both Sized and Container, passing a defaultdict to it results in an 19927db96d56Sopenharmony_ci # ambiguous dispatch which will cause a RuntimeError (see 19937db96d56Sopenharmony_ci # test_mro_conflicts). 19947db96d56Sopenharmony_ci bases = [c.Container, c.Sized, str] 19957db96d56Sopenharmony_ci for haystack in permutations(bases): 19967db96d56Sopenharmony_ci m = mro(collections.defaultdict, [c.Sized, c.Container, str]) 19977db96d56Sopenharmony_ci self.assertEqual(m, [collections.defaultdict, dict, c.Sized, 19987db96d56Sopenharmony_ci c.Container, object]) 19997db96d56Sopenharmony_ci 20007db96d56Sopenharmony_ci # MutableSequence below is registered directly on D. In other words, it 20017db96d56Sopenharmony_ci # precedes MutableMapping which means single dispatch will always 20027db96d56Sopenharmony_ci # choose MutableSequence here. 20037db96d56Sopenharmony_ci class D(collections.defaultdict): 20047db96d56Sopenharmony_ci pass 20057db96d56Sopenharmony_ci c.MutableSequence.register(D) 20067db96d56Sopenharmony_ci bases = [c.MutableSequence, c.MutableMapping] 20077db96d56Sopenharmony_ci for haystack in permutations(bases): 20087db96d56Sopenharmony_ci m = mro(D, bases) 20097db96d56Sopenharmony_ci self.assertEqual(m, [D, c.MutableSequence, c.Sequence, c.Reversible, 20107db96d56Sopenharmony_ci collections.defaultdict, dict, c.MutableMapping, c.Mapping, 20117db96d56Sopenharmony_ci c.Collection, c.Sized, c.Iterable, c.Container, 20127db96d56Sopenharmony_ci object]) 20137db96d56Sopenharmony_ci 20147db96d56Sopenharmony_ci # Container and Callable are registered on different base classes and 20157db96d56Sopenharmony_ci # a generic function supporting both should always pick the Callable 20167db96d56Sopenharmony_ci # implementation if a C instance is passed. 20177db96d56Sopenharmony_ci class C(collections.defaultdict): 20187db96d56Sopenharmony_ci def __call__(self): 20197db96d56Sopenharmony_ci pass 20207db96d56Sopenharmony_ci bases = [c.Sized, c.Callable, c.Container, c.Mapping] 20217db96d56Sopenharmony_ci for haystack in permutations(bases): 20227db96d56Sopenharmony_ci m = mro(C, haystack) 20237db96d56Sopenharmony_ci self.assertEqual(m, [C, c.Callable, collections.defaultdict, dict, c.Mapping, 20247db96d56Sopenharmony_ci c.Collection, c.Sized, c.Iterable, 20257db96d56Sopenharmony_ci c.Container, object]) 20267db96d56Sopenharmony_ci 20277db96d56Sopenharmony_ci def test_register_abc(self): 20287db96d56Sopenharmony_ci c = collections.abc 20297db96d56Sopenharmony_ci d = {"a": "b"} 20307db96d56Sopenharmony_ci l = [1, 2, 3] 20317db96d56Sopenharmony_ci s = {object(), None} 20327db96d56Sopenharmony_ci f = frozenset(s) 20337db96d56Sopenharmony_ci t = (1, 2, 3) 20347db96d56Sopenharmony_ci @functools.singledispatch 20357db96d56Sopenharmony_ci def g(obj): 20367db96d56Sopenharmony_ci return "base" 20377db96d56Sopenharmony_ci self.assertEqual(g(d), "base") 20387db96d56Sopenharmony_ci self.assertEqual(g(l), "base") 20397db96d56Sopenharmony_ci self.assertEqual(g(s), "base") 20407db96d56Sopenharmony_ci self.assertEqual(g(f), "base") 20417db96d56Sopenharmony_ci self.assertEqual(g(t), "base") 20427db96d56Sopenharmony_ci g.register(c.Sized, lambda obj: "sized") 20437db96d56Sopenharmony_ci self.assertEqual(g(d), "sized") 20447db96d56Sopenharmony_ci self.assertEqual(g(l), "sized") 20457db96d56Sopenharmony_ci self.assertEqual(g(s), "sized") 20467db96d56Sopenharmony_ci self.assertEqual(g(f), "sized") 20477db96d56Sopenharmony_ci self.assertEqual(g(t), "sized") 20487db96d56Sopenharmony_ci g.register(c.MutableMapping, lambda obj: "mutablemapping") 20497db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") 20507db96d56Sopenharmony_ci self.assertEqual(g(l), "sized") 20517db96d56Sopenharmony_ci self.assertEqual(g(s), "sized") 20527db96d56Sopenharmony_ci self.assertEqual(g(f), "sized") 20537db96d56Sopenharmony_ci self.assertEqual(g(t), "sized") 20547db96d56Sopenharmony_ci g.register(collections.ChainMap, lambda obj: "chainmap") 20557db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") # irrelevant ABCs registered 20567db96d56Sopenharmony_ci self.assertEqual(g(l), "sized") 20577db96d56Sopenharmony_ci self.assertEqual(g(s), "sized") 20587db96d56Sopenharmony_ci self.assertEqual(g(f), "sized") 20597db96d56Sopenharmony_ci self.assertEqual(g(t), "sized") 20607db96d56Sopenharmony_ci g.register(c.MutableSequence, lambda obj: "mutablesequence") 20617db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") 20627db96d56Sopenharmony_ci self.assertEqual(g(l), "mutablesequence") 20637db96d56Sopenharmony_ci self.assertEqual(g(s), "sized") 20647db96d56Sopenharmony_ci self.assertEqual(g(f), "sized") 20657db96d56Sopenharmony_ci self.assertEqual(g(t), "sized") 20667db96d56Sopenharmony_ci g.register(c.MutableSet, lambda obj: "mutableset") 20677db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") 20687db96d56Sopenharmony_ci self.assertEqual(g(l), "mutablesequence") 20697db96d56Sopenharmony_ci self.assertEqual(g(s), "mutableset") 20707db96d56Sopenharmony_ci self.assertEqual(g(f), "sized") 20717db96d56Sopenharmony_ci self.assertEqual(g(t), "sized") 20727db96d56Sopenharmony_ci g.register(c.Mapping, lambda obj: "mapping") 20737db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") # not specific enough 20747db96d56Sopenharmony_ci self.assertEqual(g(l), "mutablesequence") 20757db96d56Sopenharmony_ci self.assertEqual(g(s), "mutableset") 20767db96d56Sopenharmony_ci self.assertEqual(g(f), "sized") 20777db96d56Sopenharmony_ci self.assertEqual(g(t), "sized") 20787db96d56Sopenharmony_ci g.register(c.Sequence, lambda obj: "sequence") 20797db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") 20807db96d56Sopenharmony_ci self.assertEqual(g(l), "mutablesequence") 20817db96d56Sopenharmony_ci self.assertEqual(g(s), "mutableset") 20827db96d56Sopenharmony_ci self.assertEqual(g(f), "sized") 20837db96d56Sopenharmony_ci self.assertEqual(g(t), "sequence") 20847db96d56Sopenharmony_ci g.register(c.Set, lambda obj: "set") 20857db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") 20867db96d56Sopenharmony_ci self.assertEqual(g(l), "mutablesequence") 20877db96d56Sopenharmony_ci self.assertEqual(g(s), "mutableset") 20887db96d56Sopenharmony_ci self.assertEqual(g(f), "set") 20897db96d56Sopenharmony_ci self.assertEqual(g(t), "sequence") 20907db96d56Sopenharmony_ci g.register(dict, lambda obj: "dict") 20917db96d56Sopenharmony_ci self.assertEqual(g(d), "dict") 20927db96d56Sopenharmony_ci self.assertEqual(g(l), "mutablesequence") 20937db96d56Sopenharmony_ci self.assertEqual(g(s), "mutableset") 20947db96d56Sopenharmony_ci self.assertEqual(g(f), "set") 20957db96d56Sopenharmony_ci self.assertEqual(g(t), "sequence") 20967db96d56Sopenharmony_ci g.register(list, lambda obj: "list") 20977db96d56Sopenharmony_ci self.assertEqual(g(d), "dict") 20987db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 20997db96d56Sopenharmony_ci self.assertEqual(g(s), "mutableset") 21007db96d56Sopenharmony_ci self.assertEqual(g(f), "set") 21017db96d56Sopenharmony_ci self.assertEqual(g(t), "sequence") 21027db96d56Sopenharmony_ci g.register(set, lambda obj: "concrete-set") 21037db96d56Sopenharmony_ci self.assertEqual(g(d), "dict") 21047db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 21057db96d56Sopenharmony_ci self.assertEqual(g(s), "concrete-set") 21067db96d56Sopenharmony_ci self.assertEqual(g(f), "set") 21077db96d56Sopenharmony_ci self.assertEqual(g(t), "sequence") 21087db96d56Sopenharmony_ci g.register(frozenset, lambda obj: "frozen-set") 21097db96d56Sopenharmony_ci self.assertEqual(g(d), "dict") 21107db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 21117db96d56Sopenharmony_ci self.assertEqual(g(s), "concrete-set") 21127db96d56Sopenharmony_ci self.assertEqual(g(f), "frozen-set") 21137db96d56Sopenharmony_ci self.assertEqual(g(t), "sequence") 21147db96d56Sopenharmony_ci g.register(tuple, lambda obj: "tuple") 21157db96d56Sopenharmony_ci self.assertEqual(g(d), "dict") 21167db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 21177db96d56Sopenharmony_ci self.assertEqual(g(s), "concrete-set") 21187db96d56Sopenharmony_ci self.assertEqual(g(f), "frozen-set") 21197db96d56Sopenharmony_ci self.assertEqual(g(t), "tuple") 21207db96d56Sopenharmony_ci 21217db96d56Sopenharmony_ci def test_c3_abc(self): 21227db96d56Sopenharmony_ci c = collections.abc 21237db96d56Sopenharmony_ci mro = functools._c3_mro 21247db96d56Sopenharmony_ci class A(object): 21257db96d56Sopenharmony_ci pass 21267db96d56Sopenharmony_ci class B(A): 21277db96d56Sopenharmony_ci def __len__(self): 21287db96d56Sopenharmony_ci return 0 # implies Sized 21297db96d56Sopenharmony_ci @c.Container.register 21307db96d56Sopenharmony_ci class C(object): 21317db96d56Sopenharmony_ci pass 21327db96d56Sopenharmony_ci class D(object): 21337db96d56Sopenharmony_ci pass # unrelated 21347db96d56Sopenharmony_ci class X(D, C, B): 21357db96d56Sopenharmony_ci def __call__(self): 21367db96d56Sopenharmony_ci pass # implies Callable 21377db96d56Sopenharmony_ci expected = [X, c.Callable, D, C, c.Container, B, c.Sized, A, object] 21387db96d56Sopenharmony_ci for abcs in permutations([c.Sized, c.Callable, c.Container]): 21397db96d56Sopenharmony_ci self.assertEqual(mro(X, abcs=abcs), expected) 21407db96d56Sopenharmony_ci # unrelated ABCs don't appear in the resulting MRO 21417db96d56Sopenharmony_ci many_abcs = [c.Mapping, c.Sized, c.Callable, c.Container, c.Iterable] 21427db96d56Sopenharmony_ci self.assertEqual(mro(X, abcs=many_abcs), expected) 21437db96d56Sopenharmony_ci 21447db96d56Sopenharmony_ci def test_false_meta(self): 21457db96d56Sopenharmony_ci # see issue23572 21467db96d56Sopenharmony_ci class MetaA(type): 21477db96d56Sopenharmony_ci def __len__(self): 21487db96d56Sopenharmony_ci return 0 21497db96d56Sopenharmony_ci class A(metaclass=MetaA): 21507db96d56Sopenharmony_ci pass 21517db96d56Sopenharmony_ci class AA(A): 21527db96d56Sopenharmony_ci pass 21537db96d56Sopenharmony_ci @functools.singledispatch 21547db96d56Sopenharmony_ci def fun(a): 21557db96d56Sopenharmony_ci return 'base A' 21567db96d56Sopenharmony_ci @fun.register(A) 21577db96d56Sopenharmony_ci def _(a): 21587db96d56Sopenharmony_ci return 'fun A' 21597db96d56Sopenharmony_ci aa = AA() 21607db96d56Sopenharmony_ci self.assertEqual(fun(aa), 'fun A') 21617db96d56Sopenharmony_ci 21627db96d56Sopenharmony_ci def test_mro_conflicts(self): 21637db96d56Sopenharmony_ci c = collections.abc 21647db96d56Sopenharmony_ci @functools.singledispatch 21657db96d56Sopenharmony_ci def g(arg): 21667db96d56Sopenharmony_ci return "base" 21677db96d56Sopenharmony_ci class O(c.Sized): 21687db96d56Sopenharmony_ci def __len__(self): 21697db96d56Sopenharmony_ci return 0 21707db96d56Sopenharmony_ci o = O() 21717db96d56Sopenharmony_ci self.assertEqual(g(o), "base") 21727db96d56Sopenharmony_ci g.register(c.Iterable, lambda arg: "iterable") 21737db96d56Sopenharmony_ci g.register(c.Container, lambda arg: "container") 21747db96d56Sopenharmony_ci g.register(c.Sized, lambda arg: "sized") 21757db96d56Sopenharmony_ci g.register(c.Set, lambda arg: "set") 21767db96d56Sopenharmony_ci self.assertEqual(g(o), "sized") 21777db96d56Sopenharmony_ci c.Iterable.register(O) 21787db96d56Sopenharmony_ci self.assertEqual(g(o), "sized") # because it's explicitly in __mro__ 21797db96d56Sopenharmony_ci c.Container.register(O) 21807db96d56Sopenharmony_ci self.assertEqual(g(o), "sized") # see above: Sized is in __mro__ 21817db96d56Sopenharmony_ci c.Set.register(O) 21827db96d56Sopenharmony_ci self.assertEqual(g(o), "set") # because c.Set is a subclass of 21837db96d56Sopenharmony_ci # c.Sized and c.Container 21847db96d56Sopenharmony_ci class P: 21857db96d56Sopenharmony_ci pass 21867db96d56Sopenharmony_ci p = P() 21877db96d56Sopenharmony_ci self.assertEqual(g(p), "base") 21887db96d56Sopenharmony_ci c.Iterable.register(P) 21897db96d56Sopenharmony_ci self.assertEqual(g(p), "iterable") 21907db96d56Sopenharmony_ci c.Container.register(P) 21917db96d56Sopenharmony_ci with self.assertRaises(RuntimeError) as re_one: 21927db96d56Sopenharmony_ci g(p) 21937db96d56Sopenharmony_ci self.assertIn( 21947db96d56Sopenharmony_ci str(re_one.exception), 21957db96d56Sopenharmony_ci (("Ambiguous dispatch: <class 'collections.abc.Container'> " 21967db96d56Sopenharmony_ci "or <class 'collections.abc.Iterable'>"), 21977db96d56Sopenharmony_ci ("Ambiguous dispatch: <class 'collections.abc.Iterable'> " 21987db96d56Sopenharmony_ci "or <class 'collections.abc.Container'>")), 21997db96d56Sopenharmony_ci ) 22007db96d56Sopenharmony_ci class Q(c.Sized): 22017db96d56Sopenharmony_ci def __len__(self): 22027db96d56Sopenharmony_ci return 0 22037db96d56Sopenharmony_ci q = Q() 22047db96d56Sopenharmony_ci self.assertEqual(g(q), "sized") 22057db96d56Sopenharmony_ci c.Iterable.register(Q) 22067db96d56Sopenharmony_ci self.assertEqual(g(q), "sized") # because it's explicitly in __mro__ 22077db96d56Sopenharmony_ci c.Set.register(Q) 22087db96d56Sopenharmony_ci self.assertEqual(g(q), "set") # because c.Set is a subclass of 22097db96d56Sopenharmony_ci # c.Sized and c.Iterable 22107db96d56Sopenharmony_ci @functools.singledispatch 22117db96d56Sopenharmony_ci def h(arg): 22127db96d56Sopenharmony_ci return "base" 22137db96d56Sopenharmony_ci @h.register(c.Sized) 22147db96d56Sopenharmony_ci def _(arg): 22157db96d56Sopenharmony_ci return "sized" 22167db96d56Sopenharmony_ci @h.register(c.Container) 22177db96d56Sopenharmony_ci def _(arg): 22187db96d56Sopenharmony_ci return "container" 22197db96d56Sopenharmony_ci # Even though Sized and Container are explicit bases of MutableMapping, 22207db96d56Sopenharmony_ci # this ABC is implicitly registered on defaultdict which makes all of 22217db96d56Sopenharmony_ci # MutableMapping's bases implicit as well from defaultdict's 22227db96d56Sopenharmony_ci # perspective. 22237db96d56Sopenharmony_ci with self.assertRaises(RuntimeError) as re_two: 22247db96d56Sopenharmony_ci h(collections.defaultdict(lambda: 0)) 22257db96d56Sopenharmony_ci self.assertIn( 22267db96d56Sopenharmony_ci str(re_two.exception), 22277db96d56Sopenharmony_ci (("Ambiguous dispatch: <class 'collections.abc.Container'> " 22287db96d56Sopenharmony_ci "or <class 'collections.abc.Sized'>"), 22297db96d56Sopenharmony_ci ("Ambiguous dispatch: <class 'collections.abc.Sized'> " 22307db96d56Sopenharmony_ci "or <class 'collections.abc.Container'>")), 22317db96d56Sopenharmony_ci ) 22327db96d56Sopenharmony_ci class R(collections.defaultdict): 22337db96d56Sopenharmony_ci pass 22347db96d56Sopenharmony_ci c.MutableSequence.register(R) 22357db96d56Sopenharmony_ci @functools.singledispatch 22367db96d56Sopenharmony_ci def i(arg): 22377db96d56Sopenharmony_ci return "base" 22387db96d56Sopenharmony_ci @i.register(c.MutableMapping) 22397db96d56Sopenharmony_ci def _(arg): 22407db96d56Sopenharmony_ci return "mapping" 22417db96d56Sopenharmony_ci @i.register(c.MutableSequence) 22427db96d56Sopenharmony_ci def _(arg): 22437db96d56Sopenharmony_ci return "sequence" 22447db96d56Sopenharmony_ci r = R() 22457db96d56Sopenharmony_ci self.assertEqual(i(r), "sequence") 22467db96d56Sopenharmony_ci class S: 22477db96d56Sopenharmony_ci pass 22487db96d56Sopenharmony_ci class T(S, c.Sized): 22497db96d56Sopenharmony_ci def __len__(self): 22507db96d56Sopenharmony_ci return 0 22517db96d56Sopenharmony_ci t = T() 22527db96d56Sopenharmony_ci self.assertEqual(h(t), "sized") 22537db96d56Sopenharmony_ci c.Container.register(T) 22547db96d56Sopenharmony_ci self.assertEqual(h(t), "sized") # because it's explicitly in the MRO 22557db96d56Sopenharmony_ci class U: 22567db96d56Sopenharmony_ci def __len__(self): 22577db96d56Sopenharmony_ci return 0 22587db96d56Sopenharmony_ci u = U() 22597db96d56Sopenharmony_ci self.assertEqual(h(u), "sized") # implicit Sized subclass inferred 22607db96d56Sopenharmony_ci # from the existence of __len__() 22617db96d56Sopenharmony_ci c.Container.register(U) 22627db96d56Sopenharmony_ci # There is no preference for registered versus inferred ABCs. 22637db96d56Sopenharmony_ci with self.assertRaises(RuntimeError) as re_three: 22647db96d56Sopenharmony_ci h(u) 22657db96d56Sopenharmony_ci self.assertIn( 22667db96d56Sopenharmony_ci str(re_three.exception), 22677db96d56Sopenharmony_ci (("Ambiguous dispatch: <class 'collections.abc.Container'> " 22687db96d56Sopenharmony_ci "or <class 'collections.abc.Sized'>"), 22697db96d56Sopenharmony_ci ("Ambiguous dispatch: <class 'collections.abc.Sized'> " 22707db96d56Sopenharmony_ci "or <class 'collections.abc.Container'>")), 22717db96d56Sopenharmony_ci ) 22727db96d56Sopenharmony_ci class V(c.Sized, S): 22737db96d56Sopenharmony_ci def __len__(self): 22747db96d56Sopenharmony_ci return 0 22757db96d56Sopenharmony_ci @functools.singledispatch 22767db96d56Sopenharmony_ci def j(arg): 22777db96d56Sopenharmony_ci return "base" 22787db96d56Sopenharmony_ci @j.register(S) 22797db96d56Sopenharmony_ci def _(arg): 22807db96d56Sopenharmony_ci return "s" 22817db96d56Sopenharmony_ci @j.register(c.Container) 22827db96d56Sopenharmony_ci def _(arg): 22837db96d56Sopenharmony_ci return "container" 22847db96d56Sopenharmony_ci v = V() 22857db96d56Sopenharmony_ci self.assertEqual(j(v), "s") 22867db96d56Sopenharmony_ci c.Container.register(V) 22877db96d56Sopenharmony_ci self.assertEqual(j(v), "container") # because it ends up right after 22887db96d56Sopenharmony_ci # Sized in the MRO 22897db96d56Sopenharmony_ci 22907db96d56Sopenharmony_ci def test_cache_invalidation(self): 22917db96d56Sopenharmony_ci from collections import UserDict 22927db96d56Sopenharmony_ci import weakref 22937db96d56Sopenharmony_ci 22947db96d56Sopenharmony_ci class TracingDict(UserDict): 22957db96d56Sopenharmony_ci def __init__(self, *args, **kwargs): 22967db96d56Sopenharmony_ci super(TracingDict, self).__init__(*args, **kwargs) 22977db96d56Sopenharmony_ci self.set_ops = [] 22987db96d56Sopenharmony_ci self.get_ops = [] 22997db96d56Sopenharmony_ci def __getitem__(self, key): 23007db96d56Sopenharmony_ci result = self.data[key] 23017db96d56Sopenharmony_ci self.get_ops.append(key) 23027db96d56Sopenharmony_ci return result 23037db96d56Sopenharmony_ci def __setitem__(self, key, value): 23047db96d56Sopenharmony_ci self.set_ops.append(key) 23057db96d56Sopenharmony_ci self.data[key] = value 23067db96d56Sopenharmony_ci def clear(self): 23077db96d56Sopenharmony_ci self.data.clear() 23087db96d56Sopenharmony_ci 23097db96d56Sopenharmony_ci td = TracingDict() 23107db96d56Sopenharmony_ci with support.swap_attr(weakref, "WeakKeyDictionary", lambda: td): 23117db96d56Sopenharmony_ci c = collections.abc 23127db96d56Sopenharmony_ci @functools.singledispatch 23137db96d56Sopenharmony_ci def g(arg): 23147db96d56Sopenharmony_ci return "base" 23157db96d56Sopenharmony_ci d = {} 23167db96d56Sopenharmony_ci l = [] 23177db96d56Sopenharmony_ci self.assertEqual(len(td), 0) 23187db96d56Sopenharmony_ci self.assertEqual(g(d), "base") 23197db96d56Sopenharmony_ci self.assertEqual(len(td), 1) 23207db96d56Sopenharmony_ci self.assertEqual(td.get_ops, []) 23217db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict]) 23227db96d56Sopenharmony_ci self.assertEqual(td.data[dict], g.registry[object]) 23237db96d56Sopenharmony_ci self.assertEqual(g(l), "base") 23247db96d56Sopenharmony_ci self.assertEqual(len(td), 2) 23257db96d56Sopenharmony_ci self.assertEqual(td.get_ops, []) 23267db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list]) 23277db96d56Sopenharmony_ci self.assertEqual(td.data[dict], g.registry[object]) 23287db96d56Sopenharmony_ci self.assertEqual(td.data[list], g.registry[object]) 23297db96d56Sopenharmony_ci self.assertEqual(td.data[dict], td.data[list]) 23307db96d56Sopenharmony_ci self.assertEqual(g(l), "base") 23317db96d56Sopenharmony_ci self.assertEqual(g(d), "base") 23327db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict]) 23337db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list]) 23347db96d56Sopenharmony_ci g.register(list, lambda arg: "list") 23357db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict]) 23367db96d56Sopenharmony_ci self.assertEqual(len(td), 0) 23377db96d56Sopenharmony_ci self.assertEqual(g(d), "base") 23387db96d56Sopenharmony_ci self.assertEqual(len(td), 1) 23397db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict]) 23407db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list, dict]) 23417db96d56Sopenharmony_ci self.assertEqual(td.data[dict], 23427db96d56Sopenharmony_ci functools._find_impl(dict, g.registry)) 23437db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 23447db96d56Sopenharmony_ci self.assertEqual(len(td), 2) 23457db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict]) 23467db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list, dict, list]) 23477db96d56Sopenharmony_ci self.assertEqual(td.data[list], 23487db96d56Sopenharmony_ci functools._find_impl(list, g.registry)) 23497db96d56Sopenharmony_ci class X: 23507db96d56Sopenharmony_ci pass 23517db96d56Sopenharmony_ci c.MutableMapping.register(X) # Will not invalidate the cache, 23527db96d56Sopenharmony_ci # not using ABCs yet. 23537db96d56Sopenharmony_ci self.assertEqual(g(d), "base") 23547db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 23557db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict, dict, list]) 23567db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list, dict, list]) 23577db96d56Sopenharmony_ci g.register(c.Sized, lambda arg: "sized") 23587db96d56Sopenharmony_ci self.assertEqual(len(td), 0) 23597db96d56Sopenharmony_ci self.assertEqual(g(d), "sized") 23607db96d56Sopenharmony_ci self.assertEqual(len(td), 1) 23617db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict, dict, list]) 23627db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list, dict, list, dict]) 23637db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 23647db96d56Sopenharmony_ci self.assertEqual(len(td), 2) 23657db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict, dict, list]) 23667db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list, dict, list, dict, list]) 23677db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 23687db96d56Sopenharmony_ci self.assertEqual(g(d), "sized") 23697db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict, dict, list, list, dict]) 23707db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list, dict, list, dict, list]) 23717db96d56Sopenharmony_ci g.dispatch(list) 23727db96d56Sopenharmony_ci g.dispatch(dict) 23737db96d56Sopenharmony_ci self.assertEqual(td.get_ops, [list, dict, dict, list, list, dict, 23747db96d56Sopenharmony_ci list, dict]) 23757db96d56Sopenharmony_ci self.assertEqual(td.set_ops, [dict, list, dict, list, dict, list]) 23767db96d56Sopenharmony_ci c.MutableSet.register(X) # Will invalidate the cache. 23777db96d56Sopenharmony_ci self.assertEqual(len(td), 2) # Stale cache. 23787db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 23797db96d56Sopenharmony_ci self.assertEqual(len(td), 1) 23807db96d56Sopenharmony_ci g.register(c.MutableMapping, lambda arg: "mutablemapping") 23817db96d56Sopenharmony_ci self.assertEqual(len(td), 0) 23827db96d56Sopenharmony_ci self.assertEqual(g(d), "mutablemapping") 23837db96d56Sopenharmony_ci self.assertEqual(len(td), 1) 23847db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 23857db96d56Sopenharmony_ci self.assertEqual(len(td), 2) 23867db96d56Sopenharmony_ci g.register(dict, lambda arg: "dict") 23877db96d56Sopenharmony_ci self.assertEqual(g(d), "dict") 23887db96d56Sopenharmony_ci self.assertEqual(g(l), "list") 23897db96d56Sopenharmony_ci g._clear_cache() 23907db96d56Sopenharmony_ci self.assertEqual(len(td), 0) 23917db96d56Sopenharmony_ci 23927db96d56Sopenharmony_ci def test_annotations(self): 23937db96d56Sopenharmony_ci @functools.singledispatch 23947db96d56Sopenharmony_ci def i(arg): 23957db96d56Sopenharmony_ci return "base" 23967db96d56Sopenharmony_ci @i.register 23977db96d56Sopenharmony_ci def _(arg: collections.abc.Mapping): 23987db96d56Sopenharmony_ci return "mapping" 23997db96d56Sopenharmony_ci @i.register 24007db96d56Sopenharmony_ci def _(arg: "collections.abc.Sequence"): 24017db96d56Sopenharmony_ci return "sequence" 24027db96d56Sopenharmony_ci self.assertEqual(i(None), "base") 24037db96d56Sopenharmony_ci self.assertEqual(i({"a": 1}), "mapping") 24047db96d56Sopenharmony_ci self.assertEqual(i([1, 2, 3]), "sequence") 24057db96d56Sopenharmony_ci self.assertEqual(i((1, 2, 3)), "sequence") 24067db96d56Sopenharmony_ci self.assertEqual(i("str"), "sequence") 24077db96d56Sopenharmony_ci 24087db96d56Sopenharmony_ci # Registering classes as callables doesn't work with annotations, 24097db96d56Sopenharmony_ci # you need to pass the type explicitly. 24107db96d56Sopenharmony_ci @i.register(str) 24117db96d56Sopenharmony_ci class _: 24127db96d56Sopenharmony_ci def __init__(self, arg): 24137db96d56Sopenharmony_ci self.arg = arg 24147db96d56Sopenharmony_ci 24157db96d56Sopenharmony_ci def __eq__(self, other): 24167db96d56Sopenharmony_ci return self.arg == other 24177db96d56Sopenharmony_ci self.assertEqual(i("str"), "str") 24187db96d56Sopenharmony_ci 24197db96d56Sopenharmony_ci def test_method_register(self): 24207db96d56Sopenharmony_ci class A: 24217db96d56Sopenharmony_ci @functools.singledispatchmethod 24227db96d56Sopenharmony_ci def t(self, arg): 24237db96d56Sopenharmony_ci self.arg = "base" 24247db96d56Sopenharmony_ci @t.register(int) 24257db96d56Sopenharmony_ci def _(self, arg): 24267db96d56Sopenharmony_ci self.arg = "int" 24277db96d56Sopenharmony_ci @t.register(str) 24287db96d56Sopenharmony_ci def _(self, arg): 24297db96d56Sopenharmony_ci self.arg = "str" 24307db96d56Sopenharmony_ci a = A() 24317db96d56Sopenharmony_ci 24327db96d56Sopenharmony_ci a.t(0) 24337db96d56Sopenharmony_ci self.assertEqual(a.arg, "int") 24347db96d56Sopenharmony_ci aa = A() 24357db96d56Sopenharmony_ci self.assertFalse(hasattr(aa, 'arg')) 24367db96d56Sopenharmony_ci a.t('') 24377db96d56Sopenharmony_ci self.assertEqual(a.arg, "str") 24387db96d56Sopenharmony_ci aa = A() 24397db96d56Sopenharmony_ci self.assertFalse(hasattr(aa, 'arg')) 24407db96d56Sopenharmony_ci a.t(0.0) 24417db96d56Sopenharmony_ci self.assertEqual(a.arg, "base") 24427db96d56Sopenharmony_ci aa = A() 24437db96d56Sopenharmony_ci self.assertFalse(hasattr(aa, 'arg')) 24447db96d56Sopenharmony_ci 24457db96d56Sopenharmony_ci def test_staticmethod_register(self): 24467db96d56Sopenharmony_ci class A: 24477db96d56Sopenharmony_ci @functools.singledispatchmethod 24487db96d56Sopenharmony_ci @staticmethod 24497db96d56Sopenharmony_ci def t(arg): 24507db96d56Sopenharmony_ci return arg 24517db96d56Sopenharmony_ci @t.register(int) 24527db96d56Sopenharmony_ci @staticmethod 24537db96d56Sopenharmony_ci def _(arg): 24547db96d56Sopenharmony_ci return isinstance(arg, int) 24557db96d56Sopenharmony_ci @t.register(str) 24567db96d56Sopenharmony_ci @staticmethod 24577db96d56Sopenharmony_ci def _(arg): 24587db96d56Sopenharmony_ci return isinstance(arg, str) 24597db96d56Sopenharmony_ci a = A() 24607db96d56Sopenharmony_ci 24617db96d56Sopenharmony_ci self.assertTrue(A.t(0)) 24627db96d56Sopenharmony_ci self.assertTrue(A.t('')) 24637db96d56Sopenharmony_ci self.assertEqual(A.t(0.0), 0.0) 24647db96d56Sopenharmony_ci 24657db96d56Sopenharmony_ci def test_classmethod_register(self): 24667db96d56Sopenharmony_ci class A: 24677db96d56Sopenharmony_ci def __init__(self, arg): 24687db96d56Sopenharmony_ci self.arg = arg 24697db96d56Sopenharmony_ci 24707db96d56Sopenharmony_ci @functools.singledispatchmethod 24717db96d56Sopenharmony_ci @classmethod 24727db96d56Sopenharmony_ci def t(cls, arg): 24737db96d56Sopenharmony_ci return cls("base") 24747db96d56Sopenharmony_ci @t.register(int) 24757db96d56Sopenharmony_ci @classmethod 24767db96d56Sopenharmony_ci def _(cls, arg): 24777db96d56Sopenharmony_ci return cls("int") 24787db96d56Sopenharmony_ci @t.register(str) 24797db96d56Sopenharmony_ci @classmethod 24807db96d56Sopenharmony_ci def _(cls, arg): 24817db96d56Sopenharmony_ci return cls("str") 24827db96d56Sopenharmony_ci 24837db96d56Sopenharmony_ci self.assertEqual(A.t(0).arg, "int") 24847db96d56Sopenharmony_ci self.assertEqual(A.t('').arg, "str") 24857db96d56Sopenharmony_ci self.assertEqual(A.t(0.0).arg, "base") 24867db96d56Sopenharmony_ci 24877db96d56Sopenharmony_ci def test_callable_register(self): 24887db96d56Sopenharmony_ci class A: 24897db96d56Sopenharmony_ci def __init__(self, arg): 24907db96d56Sopenharmony_ci self.arg = arg 24917db96d56Sopenharmony_ci 24927db96d56Sopenharmony_ci @functools.singledispatchmethod 24937db96d56Sopenharmony_ci @classmethod 24947db96d56Sopenharmony_ci def t(cls, arg): 24957db96d56Sopenharmony_ci return cls("base") 24967db96d56Sopenharmony_ci 24977db96d56Sopenharmony_ci @A.t.register(int) 24987db96d56Sopenharmony_ci @classmethod 24997db96d56Sopenharmony_ci def _(cls, arg): 25007db96d56Sopenharmony_ci return cls("int") 25017db96d56Sopenharmony_ci @A.t.register(str) 25027db96d56Sopenharmony_ci @classmethod 25037db96d56Sopenharmony_ci def _(cls, arg): 25047db96d56Sopenharmony_ci return cls("str") 25057db96d56Sopenharmony_ci 25067db96d56Sopenharmony_ci self.assertEqual(A.t(0).arg, "int") 25077db96d56Sopenharmony_ci self.assertEqual(A.t('').arg, "str") 25087db96d56Sopenharmony_ci self.assertEqual(A.t(0.0).arg, "base") 25097db96d56Sopenharmony_ci 25107db96d56Sopenharmony_ci def test_abstractmethod_register(self): 25117db96d56Sopenharmony_ci class Abstract(metaclass=abc.ABCMeta): 25127db96d56Sopenharmony_ci 25137db96d56Sopenharmony_ci @functools.singledispatchmethod 25147db96d56Sopenharmony_ci @abc.abstractmethod 25157db96d56Sopenharmony_ci def add(self, x, y): 25167db96d56Sopenharmony_ci pass 25177db96d56Sopenharmony_ci 25187db96d56Sopenharmony_ci self.assertTrue(Abstract.add.__isabstractmethod__) 25197db96d56Sopenharmony_ci self.assertTrue(Abstract.__dict__['add'].__isabstractmethod__) 25207db96d56Sopenharmony_ci 25217db96d56Sopenharmony_ci with self.assertRaises(TypeError): 25227db96d56Sopenharmony_ci Abstract() 25237db96d56Sopenharmony_ci 25247db96d56Sopenharmony_ci def test_type_ann_register(self): 25257db96d56Sopenharmony_ci class A: 25267db96d56Sopenharmony_ci @functools.singledispatchmethod 25277db96d56Sopenharmony_ci def t(self, arg): 25287db96d56Sopenharmony_ci return "base" 25297db96d56Sopenharmony_ci @t.register 25307db96d56Sopenharmony_ci def _(self, arg: int): 25317db96d56Sopenharmony_ci return "int" 25327db96d56Sopenharmony_ci @t.register 25337db96d56Sopenharmony_ci def _(self, arg: str): 25347db96d56Sopenharmony_ci return "str" 25357db96d56Sopenharmony_ci a = A() 25367db96d56Sopenharmony_ci 25377db96d56Sopenharmony_ci self.assertEqual(a.t(0), "int") 25387db96d56Sopenharmony_ci self.assertEqual(a.t(''), "str") 25397db96d56Sopenharmony_ci self.assertEqual(a.t(0.0), "base") 25407db96d56Sopenharmony_ci 25417db96d56Sopenharmony_ci def test_staticmethod_type_ann_register(self): 25427db96d56Sopenharmony_ci class A: 25437db96d56Sopenharmony_ci @functools.singledispatchmethod 25447db96d56Sopenharmony_ci @staticmethod 25457db96d56Sopenharmony_ci def t(arg): 25467db96d56Sopenharmony_ci return arg 25477db96d56Sopenharmony_ci @t.register 25487db96d56Sopenharmony_ci @staticmethod 25497db96d56Sopenharmony_ci def _(arg: int): 25507db96d56Sopenharmony_ci return isinstance(arg, int) 25517db96d56Sopenharmony_ci @t.register 25527db96d56Sopenharmony_ci @staticmethod 25537db96d56Sopenharmony_ci def _(arg: str): 25547db96d56Sopenharmony_ci return isinstance(arg, str) 25557db96d56Sopenharmony_ci a = A() 25567db96d56Sopenharmony_ci 25577db96d56Sopenharmony_ci self.assertTrue(A.t(0)) 25587db96d56Sopenharmony_ci self.assertTrue(A.t('')) 25597db96d56Sopenharmony_ci self.assertEqual(A.t(0.0), 0.0) 25607db96d56Sopenharmony_ci 25617db96d56Sopenharmony_ci def test_classmethod_type_ann_register(self): 25627db96d56Sopenharmony_ci class A: 25637db96d56Sopenharmony_ci def __init__(self, arg): 25647db96d56Sopenharmony_ci self.arg = arg 25657db96d56Sopenharmony_ci 25667db96d56Sopenharmony_ci @functools.singledispatchmethod 25677db96d56Sopenharmony_ci @classmethod 25687db96d56Sopenharmony_ci def t(cls, arg): 25697db96d56Sopenharmony_ci return cls("base") 25707db96d56Sopenharmony_ci @t.register 25717db96d56Sopenharmony_ci @classmethod 25727db96d56Sopenharmony_ci def _(cls, arg: int): 25737db96d56Sopenharmony_ci return cls("int") 25747db96d56Sopenharmony_ci @t.register 25757db96d56Sopenharmony_ci @classmethod 25767db96d56Sopenharmony_ci def _(cls, arg: str): 25777db96d56Sopenharmony_ci return cls("str") 25787db96d56Sopenharmony_ci 25797db96d56Sopenharmony_ci self.assertEqual(A.t(0).arg, "int") 25807db96d56Sopenharmony_ci self.assertEqual(A.t('').arg, "str") 25817db96d56Sopenharmony_ci self.assertEqual(A.t(0.0).arg, "base") 25827db96d56Sopenharmony_ci 25837db96d56Sopenharmony_ci def test_method_wrapping_attributes(self): 25847db96d56Sopenharmony_ci class A: 25857db96d56Sopenharmony_ci @functools.singledispatchmethod 25867db96d56Sopenharmony_ci def func(self, arg: int) -> str: 25877db96d56Sopenharmony_ci """My function docstring""" 25887db96d56Sopenharmony_ci return str(arg) 25897db96d56Sopenharmony_ci @functools.singledispatchmethod 25907db96d56Sopenharmony_ci @classmethod 25917db96d56Sopenharmony_ci def cls_func(cls, arg: int) -> str: 25927db96d56Sopenharmony_ci """My function docstring""" 25937db96d56Sopenharmony_ci return str(arg) 25947db96d56Sopenharmony_ci @functools.singledispatchmethod 25957db96d56Sopenharmony_ci @staticmethod 25967db96d56Sopenharmony_ci def static_func(arg: int) -> str: 25977db96d56Sopenharmony_ci """My function docstring""" 25987db96d56Sopenharmony_ci return str(arg) 25997db96d56Sopenharmony_ci 26007db96d56Sopenharmony_ci for meth in ( 26017db96d56Sopenharmony_ci A.func, 26027db96d56Sopenharmony_ci A().func, 26037db96d56Sopenharmony_ci A.cls_func, 26047db96d56Sopenharmony_ci A().cls_func, 26057db96d56Sopenharmony_ci A.static_func, 26067db96d56Sopenharmony_ci A().static_func 26077db96d56Sopenharmony_ci ): 26087db96d56Sopenharmony_ci with self.subTest(meth=meth): 26097db96d56Sopenharmony_ci self.assertEqual(meth.__doc__, 'My function docstring') 26107db96d56Sopenharmony_ci self.assertEqual(meth.__annotations__['arg'], int) 26117db96d56Sopenharmony_ci 26127db96d56Sopenharmony_ci self.assertEqual(A.func.__name__, 'func') 26137db96d56Sopenharmony_ci self.assertEqual(A().func.__name__, 'func') 26147db96d56Sopenharmony_ci self.assertEqual(A.cls_func.__name__, 'cls_func') 26157db96d56Sopenharmony_ci self.assertEqual(A().cls_func.__name__, 'cls_func') 26167db96d56Sopenharmony_ci self.assertEqual(A.static_func.__name__, 'static_func') 26177db96d56Sopenharmony_ci self.assertEqual(A().static_func.__name__, 'static_func') 26187db96d56Sopenharmony_ci 26197db96d56Sopenharmony_ci def test_double_wrapped_methods(self): 26207db96d56Sopenharmony_ci def classmethod_friendly_decorator(func): 26217db96d56Sopenharmony_ci wrapped = func.__func__ 26227db96d56Sopenharmony_ci @classmethod 26237db96d56Sopenharmony_ci @functools.wraps(wrapped) 26247db96d56Sopenharmony_ci def wrapper(*args, **kwargs): 26257db96d56Sopenharmony_ci return wrapped(*args, **kwargs) 26267db96d56Sopenharmony_ci return wrapper 26277db96d56Sopenharmony_ci 26287db96d56Sopenharmony_ci class WithoutSingleDispatch: 26297db96d56Sopenharmony_ci @classmethod 26307db96d56Sopenharmony_ci @contextlib.contextmanager 26317db96d56Sopenharmony_ci def cls_context_manager(cls, arg: int) -> str: 26327db96d56Sopenharmony_ci try: 26337db96d56Sopenharmony_ci yield str(arg) 26347db96d56Sopenharmony_ci finally: 26357db96d56Sopenharmony_ci return 'Done' 26367db96d56Sopenharmony_ci 26377db96d56Sopenharmony_ci @classmethod_friendly_decorator 26387db96d56Sopenharmony_ci @classmethod 26397db96d56Sopenharmony_ci def decorated_classmethod(cls, arg: int) -> str: 26407db96d56Sopenharmony_ci return str(arg) 26417db96d56Sopenharmony_ci 26427db96d56Sopenharmony_ci class WithSingleDispatch: 26437db96d56Sopenharmony_ci @functools.singledispatchmethod 26447db96d56Sopenharmony_ci @classmethod 26457db96d56Sopenharmony_ci @contextlib.contextmanager 26467db96d56Sopenharmony_ci def cls_context_manager(cls, arg: int) -> str: 26477db96d56Sopenharmony_ci """My function docstring""" 26487db96d56Sopenharmony_ci try: 26497db96d56Sopenharmony_ci yield str(arg) 26507db96d56Sopenharmony_ci finally: 26517db96d56Sopenharmony_ci return 'Done' 26527db96d56Sopenharmony_ci 26537db96d56Sopenharmony_ci @functools.singledispatchmethod 26547db96d56Sopenharmony_ci @classmethod_friendly_decorator 26557db96d56Sopenharmony_ci @classmethod 26567db96d56Sopenharmony_ci def decorated_classmethod(cls, arg: int) -> str: 26577db96d56Sopenharmony_ci """My function docstring""" 26587db96d56Sopenharmony_ci return str(arg) 26597db96d56Sopenharmony_ci 26607db96d56Sopenharmony_ci # These are sanity checks 26617db96d56Sopenharmony_ci # to test the test itself is working as expected 26627db96d56Sopenharmony_ci with WithoutSingleDispatch.cls_context_manager(5) as foo: 26637db96d56Sopenharmony_ci without_single_dispatch_foo = foo 26647db96d56Sopenharmony_ci 26657db96d56Sopenharmony_ci with WithSingleDispatch.cls_context_manager(5) as foo: 26667db96d56Sopenharmony_ci single_dispatch_foo = foo 26677db96d56Sopenharmony_ci 26687db96d56Sopenharmony_ci self.assertEqual(without_single_dispatch_foo, single_dispatch_foo) 26697db96d56Sopenharmony_ci self.assertEqual(single_dispatch_foo, '5') 26707db96d56Sopenharmony_ci 26717db96d56Sopenharmony_ci self.assertEqual( 26727db96d56Sopenharmony_ci WithoutSingleDispatch.decorated_classmethod(5), 26737db96d56Sopenharmony_ci WithSingleDispatch.decorated_classmethod(5) 26747db96d56Sopenharmony_ci ) 26757db96d56Sopenharmony_ci 26767db96d56Sopenharmony_ci self.assertEqual(WithSingleDispatch.decorated_classmethod(5), '5') 26777db96d56Sopenharmony_ci 26787db96d56Sopenharmony_ci # Behavioural checks now follow 26797db96d56Sopenharmony_ci for method_name in ('cls_context_manager', 'decorated_classmethod'): 26807db96d56Sopenharmony_ci with self.subTest(method=method_name): 26817db96d56Sopenharmony_ci self.assertEqual( 26827db96d56Sopenharmony_ci getattr(WithSingleDispatch, method_name).__name__, 26837db96d56Sopenharmony_ci getattr(WithoutSingleDispatch, method_name).__name__ 26847db96d56Sopenharmony_ci ) 26857db96d56Sopenharmony_ci 26867db96d56Sopenharmony_ci self.assertEqual( 26877db96d56Sopenharmony_ci getattr(WithSingleDispatch(), method_name).__name__, 26887db96d56Sopenharmony_ci getattr(WithoutSingleDispatch(), method_name).__name__ 26897db96d56Sopenharmony_ci ) 26907db96d56Sopenharmony_ci 26917db96d56Sopenharmony_ci for meth in ( 26927db96d56Sopenharmony_ci WithSingleDispatch.cls_context_manager, 26937db96d56Sopenharmony_ci WithSingleDispatch().cls_context_manager, 26947db96d56Sopenharmony_ci WithSingleDispatch.decorated_classmethod, 26957db96d56Sopenharmony_ci WithSingleDispatch().decorated_classmethod 26967db96d56Sopenharmony_ci ): 26977db96d56Sopenharmony_ci with self.subTest(meth=meth): 26987db96d56Sopenharmony_ci self.assertEqual(meth.__doc__, 'My function docstring') 26997db96d56Sopenharmony_ci self.assertEqual(meth.__annotations__['arg'], int) 27007db96d56Sopenharmony_ci 27017db96d56Sopenharmony_ci self.assertEqual( 27027db96d56Sopenharmony_ci WithSingleDispatch.cls_context_manager.__name__, 27037db96d56Sopenharmony_ci 'cls_context_manager' 27047db96d56Sopenharmony_ci ) 27057db96d56Sopenharmony_ci self.assertEqual( 27067db96d56Sopenharmony_ci WithSingleDispatch().cls_context_manager.__name__, 27077db96d56Sopenharmony_ci 'cls_context_manager' 27087db96d56Sopenharmony_ci ) 27097db96d56Sopenharmony_ci self.assertEqual( 27107db96d56Sopenharmony_ci WithSingleDispatch.decorated_classmethod.__name__, 27117db96d56Sopenharmony_ci 'decorated_classmethod' 27127db96d56Sopenharmony_ci ) 27137db96d56Sopenharmony_ci self.assertEqual( 27147db96d56Sopenharmony_ci WithSingleDispatch().decorated_classmethod.__name__, 27157db96d56Sopenharmony_ci 'decorated_classmethod' 27167db96d56Sopenharmony_ci ) 27177db96d56Sopenharmony_ci 27187db96d56Sopenharmony_ci def test_invalid_registrations(self): 27197db96d56Sopenharmony_ci msg_prefix = "Invalid first argument to `register()`: " 27207db96d56Sopenharmony_ci msg_suffix = ( 27217db96d56Sopenharmony_ci ". Use either `@register(some_class)` or plain `@register` on an " 27227db96d56Sopenharmony_ci "annotated function." 27237db96d56Sopenharmony_ci ) 27247db96d56Sopenharmony_ci @functools.singledispatch 27257db96d56Sopenharmony_ci def i(arg): 27267db96d56Sopenharmony_ci return "base" 27277db96d56Sopenharmony_ci with self.assertRaises(TypeError) as exc: 27287db96d56Sopenharmony_ci @i.register(42) 27297db96d56Sopenharmony_ci def _(arg): 27307db96d56Sopenharmony_ci return "I annotated with a non-type" 27317db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).startswith(msg_prefix + "42")) 27327db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).endswith(msg_suffix)) 27337db96d56Sopenharmony_ci with self.assertRaises(TypeError) as exc: 27347db96d56Sopenharmony_ci @i.register 27357db96d56Sopenharmony_ci def _(arg): 27367db96d56Sopenharmony_ci return "I forgot to annotate" 27377db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).startswith(msg_prefix + 27387db96d56Sopenharmony_ci "<function TestSingleDispatch.test_invalid_registrations.<locals>._" 27397db96d56Sopenharmony_ci )) 27407db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).endswith(msg_suffix)) 27417db96d56Sopenharmony_ci 27427db96d56Sopenharmony_ci with self.assertRaises(TypeError) as exc: 27437db96d56Sopenharmony_ci @i.register 27447db96d56Sopenharmony_ci def _(arg: typing.Iterable[str]): 27457db96d56Sopenharmony_ci # At runtime, dispatching on generics is impossible. 27467db96d56Sopenharmony_ci # When registering implementations with singledispatch, avoid 27477db96d56Sopenharmony_ci # types from `typing`. Instead, annotate with regular types 27487db96d56Sopenharmony_ci # or ABCs. 27497db96d56Sopenharmony_ci return "I annotated with a generic collection" 27507db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).startswith( 27517db96d56Sopenharmony_ci "Invalid annotation for 'arg'." 27527db96d56Sopenharmony_ci )) 27537db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).endswith( 27547db96d56Sopenharmony_ci 'typing.Iterable[str] is not a class.' 27557db96d56Sopenharmony_ci )) 27567db96d56Sopenharmony_ci 27577db96d56Sopenharmony_ci with self.assertRaises(TypeError) as exc: 27587db96d56Sopenharmony_ci @i.register 27597db96d56Sopenharmony_ci def _(arg: typing.Union[int, typing.Iterable[str]]): 27607db96d56Sopenharmony_ci return "Invalid Union" 27617db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).startswith( 27627db96d56Sopenharmony_ci "Invalid annotation for 'arg'." 27637db96d56Sopenharmony_ci )) 27647db96d56Sopenharmony_ci self.assertTrue(str(exc.exception).endswith( 27657db96d56Sopenharmony_ci 'typing.Union[int, typing.Iterable[str]] not all arguments are classes.' 27667db96d56Sopenharmony_ci )) 27677db96d56Sopenharmony_ci 27687db96d56Sopenharmony_ci def test_invalid_positional_argument(self): 27697db96d56Sopenharmony_ci @functools.singledispatch 27707db96d56Sopenharmony_ci def f(*args): 27717db96d56Sopenharmony_ci pass 27727db96d56Sopenharmony_ci msg = 'f requires at least 1 positional argument' 27737db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, msg): 27747db96d56Sopenharmony_ci f() 27757db96d56Sopenharmony_ci 27767db96d56Sopenharmony_ci def test_union(self): 27777db96d56Sopenharmony_ci @functools.singledispatch 27787db96d56Sopenharmony_ci def f(arg): 27797db96d56Sopenharmony_ci return "default" 27807db96d56Sopenharmony_ci 27817db96d56Sopenharmony_ci @f.register 27827db96d56Sopenharmony_ci def _(arg: typing.Union[str, bytes]): 27837db96d56Sopenharmony_ci return "typing.Union" 27847db96d56Sopenharmony_ci 27857db96d56Sopenharmony_ci @f.register 27867db96d56Sopenharmony_ci def _(arg: int | float): 27877db96d56Sopenharmony_ci return "types.UnionType" 27887db96d56Sopenharmony_ci 27897db96d56Sopenharmony_ci self.assertEqual(f([]), "default") 27907db96d56Sopenharmony_ci self.assertEqual(f(""), "typing.Union") 27917db96d56Sopenharmony_ci self.assertEqual(f(b""), "typing.Union") 27927db96d56Sopenharmony_ci self.assertEqual(f(1), "types.UnionType") 27937db96d56Sopenharmony_ci self.assertEqual(f(1.0), "types.UnionType") 27947db96d56Sopenharmony_ci 27957db96d56Sopenharmony_ci def test_union_conflict(self): 27967db96d56Sopenharmony_ci @functools.singledispatch 27977db96d56Sopenharmony_ci def f(arg): 27987db96d56Sopenharmony_ci return "default" 27997db96d56Sopenharmony_ci 28007db96d56Sopenharmony_ci @f.register 28017db96d56Sopenharmony_ci def _(arg: typing.Union[str, bytes]): 28027db96d56Sopenharmony_ci return "typing.Union" 28037db96d56Sopenharmony_ci 28047db96d56Sopenharmony_ci @f.register 28057db96d56Sopenharmony_ci def _(arg: int | str): 28067db96d56Sopenharmony_ci return "types.UnionType" 28077db96d56Sopenharmony_ci 28087db96d56Sopenharmony_ci self.assertEqual(f([]), "default") 28097db96d56Sopenharmony_ci self.assertEqual(f(""), "types.UnionType") # last one wins 28107db96d56Sopenharmony_ci self.assertEqual(f(b""), "typing.Union") 28117db96d56Sopenharmony_ci self.assertEqual(f(1), "types.UnionType") 28127db96d56Sopenharmony_ci 28137db96d56Sopenharmony_ci def test_union_None(self): 28147db96d56Sopenharmony_ci @functools.singledispatch 28157db96d56Sopenharmony_ci def typing_union(arg): 28167db96d56Sopenharmony_ci return "default" 28177db96d56Sopenharmony_ci 28187db96d56Sopenharmony_ci @typing_union.register 28197db96d56Sopenharmony_ci def _(arg: typing.Union[str, None]): 28207db96d56Sopenharmony_ci return "typing.Union" 28217db96d56Sopenharmony_ci 28227db96d56Sopenharmony_ci self.assertEqual(typing_union(1), "default") 28237db96d56Sopenharmony_ci self.assertEqual(typing_union(""), "typing.Union") 28247db96d56Sopenharmony_ci self.assertEqual(typing_union(None), "typing.Union") 28257db96d56Sopenharmony_ci 28267db96d56Sopenharmony_ci @functools.singledispatch 28277db96d56Sopenharmony_ci def types_union(arg): 28287db96d56Sopenharmony_ci return "default" 28297db96d56Sopenharmony_ci 28307db96d56Sopenharmony_ci @types_union.register 28317db96d56Sopenharmony_ci def _(arg: int | None): 28327db96d56Sopenharmony_ci return "types.UnionType" 28337db96d56Sopenharmony_ci 28347db96d56Sopenharmony_ci self.assertEqual(types_union(""), "default") 28357db96d56Sopenharmony_ci self.assertEqual(types_union(1), "types.UnionType") 28367db96d56Sopenharmony_ci self.assertEqual(types_union(None), "types.UnionType") 28377db96d56Sopenharmony_ci 28387db96d56Sopenharmony_ci def test_register_genericalias(self): 28397db96d56Sopenharmony_ci @functools.singledispatch 28407db96d56Sopenharmony_ci def f(arg): 28417db96d56Sopenharmony_ci return "default" 28427db96d56Sopenharmony_ci 28437db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28447db96d56Sopenharmony_ci f.register(list[int], lambda arg: "types.GenericAlias") 28457db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28467db96d56Sopenharmony_ci f.register(typing.List[int], lambda arg: "typing.GenericAlias") 28477db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28487db96d56Sopenharmony_ci f.register(list[int] | str, lambda arg: "types.UnionTypes(types.GenericAlias)") 28497db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28507db96d56Sopenharmony_ci f.register(typing.List[float] | bytes, lambda arg: "typing.Union[typing.GenericAlias]") 28517db96d56Sopenharmony_ci 28527db96d56Sopenharmony_ci self.assertEqual(f([1]), "default") 28537db96d56Sopenharmony_ci self.assertEqual(f([1.0]), "default") 28547db96d56Sopenharmony_ci self.assertEqual(f(""), "default") 28557db96d56Sopenharmony_ci self.assertEqual(f(b""), "default") 28567db96d56Sopenharmony_ci 28577db96d56Sopenharmony_ci def test_register_genericalias_decorator(self): 28587db96d56Sopenharmony_ci @functools.singledispatch 28597db96d56Sopenharmony_ci def f(arg): 28607db96d56Sopenharmony_ci return "default" 28617db96d56Sopenharmony_ci 28627db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28637db96d56Sopenharmony_ci f.register(list[int]) 28647db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28657db96d56Sopenharmony_ci f.register(typing.List[int]) 28667db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28677db96d56Sopenharmony_ci f.register(list[int] | str) 28687db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid first argument to "): 28697db96d56Sopenharmony_ci f.register(typing.List[int] | str) 28707db96d56Sopenharmony_ci 28717db96d56Sopenharmony_ci def test_register_genericalias_annotation(self): 28727db96d56Sopenharmony_ci @functools.singledispatch 28737db96d56Sopenharmony_ci def f(arg): 28747db96d56Sopenharmony_ci return "default" 28757db96d56Sopenharmony_ci 28767db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"): 28777db96d56Sopenharmony_ci @f.register 28787db96d56Sopenharmony_ci def _(arg: list[int]): 28797db96d56Sopenharmony_ci return "types.GenericAlias" 28807db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"): 28817db96d56Sopenharmony_ci @f.register 28827db96d56Sopenharmony_ci def _(arg: typing.List[float]): 28837db96d56Sopenharmony_ci return "typing.GenericAlias" 28847db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"): 28857db96d56Sopenharmony_ci @f.register 28867db96d56Sopenharmony_ci def _(arg: list[int] | str): 28877db96d56Sopenharmony_ci return "types.UnionType(types.GenericAlias)" 28887db96d56Sopenharmony_ci with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"): 28897db96d56Sopenharmony_ci @f.register 28907db96d56Sopenharmony_ci def _(arg: typing.List[float] | bytes): 28917db96d56Sopenharmony_ci return "typing.Union[typing.GenericAlias]" 28927db96d56Sopenharmony_ci 28937db96d56Sopenharmony_ci self.assertEqual(f([1]), "default") 28947db96d56Sopenharmony_ci self.assertEqual(f([1.0]), "default") 28957db96d56Sopenharmony_ci self.assertEqual(f(""), "default") 28967db96d56Sopenharmony_ci self.assertEqual(f(b""), "default") 28977db96d56Sopenharmony_ci 28987db96d56Sopenharmony_ci 28997db96d56Sopenharmony_ciclass CachedCostItem: 29007db96d56Sopenharmony_ci _cost = 1 29017db96d56Sopenharmony_ci 29027db96d56Sopenharmony_ci def __init__(self): 29037db96d56Sopenharmony_ci self.lock = py_functools.RLock() 29047db96d56Sopenharmony_ci 29057db96d56Sopenharmony_ci @py_functools.cached_property 29067db96d56Sopenharmony_ci def cost(self): 29077db96d56Sopenharmony_ci """The cost of the item.""" 29087db96d56Sopenharmony_ci with self.lock: 29097db96d56Sopenharmony_ci self._cost += 1 29107db96d56Sopenharmony_ci return self._cost 29117db96d56Sopenharmony_ci 29127db96d56Sopenharmony_ci 29137db96d56Sopenharmony_ciclass OptionallyCachedCostItem: 29147db96d56Sopenharmony_ci _cost = 1 29157db96d56Sopenharmony_ci 29167db96d56Sopenharmony_ci def get_cost(self): 29177db96d56Sopenharmony_ci """The cost of the item.""" 29187db96d56Sopenharmony_ci self._cost += 1 29197db96d56Sopenharmony_ci return self._cost 29207db96d56Sopenharmony_ci 29217db96d56Sopenharmony_ci cached_cost = py_functools.cached_property(get_cost) 29227db96d56Sopenharmony_ci 29237db96d56Sopenharmony_ci 29247db96d56Sopenharmony_ciclass CachedCostItemWait: 29257db96d56Sopenharmony_ci 29267db96d56Sopenharmony_ci def __init__(self, event): 29277db96d56Sopenharmony_ci self._cost = 1 29287db96d56Sopenharmony_ci self.lock = py_functools.RLock() 29297db96d56Sopenharmony_ci self.event = event 29307db96d56Sopenharmony_ci 29317db96d56Sopenharmony_ci @py_functools.cached_property 29327db96d56Sopenharmony_ci def cost(self): 29337db96d56Sopenharmony_ci self.event.wait(1) 29347db96d56Sopenharmony_ci with self.lock: 29357db96d56Sopenharmony_ci self._cost += 1 29367db96d56Sopenharmony_ci return self._cost 29377db96d56Sopenharmony_ci 29387db96d56Sopenharmony_ci 29397db96d56Sopenharmony_ciclass CachedCostItemWithSlots: 29407db96d56Sopenharmony_ci __slots__ = ('_cost') 29417db96d56Sopenharmony_ci 29427db96d56Sopenharmony_ci def __init__(self): 29437db96d56Sopenharmony_ci self._cost = 1 29447db96d56Sopenharmony_ci 29457db96d56Sopenharmony_ci @py_functools.cached_property 29467db96d56Sopenharmony_ci def cost(self): 29477db96d56Sopenharmony_ci raise RuntimeError('never called, slots not supported') 29487db96d56Sopenharmony_ci 29497db96d56Sopenharmony_ci 29507db96d56Sopenharmony_ciclass TestCachedProperty(unittest.TestCase): 29517db96d56Sopenharmony_ci def test_cached(self): 29527db96d56Sopenharmony_ci item = CachedCostItem() 29537db96d56Sopenharmony_ci self.assertEqual(item.cost, 2) 29547db96d56Sopenharmony_ci self.assertEqual(item.cost, 2) # not 3 29557db96d56Sopenharmony_ci 29567db96d56Sopenharmony_ci def test_cached_attribute_name_differs_from_func_name(self): 29577db96d56Sopenharmony_ci item = OptionallyCachedCostItem() 29587db96d56Sopenharmony_ci self.assertEqual(item.get_cost(), 2) 29597db96d56Sopenharmony_ci self.assertEqual(item.cached_cost, 3) 29607db96d56Sopenharmony_ci self.assertEqual(item.get_cost(), 4) 29617db96d56Sopenharmony_ci self.assertEqual(item.cached_cost, 3) 29627db96d56Sopenharmony_ci 29637db96d56Sopenharmony_ci @threading_helper.requires_working_threading() 29647db96d56Sopenharmony_ci def test_threaded(self): 29657db96d56Sopenharmony_ci go = threading.Event() 29667db96d56Sopenharmony_ci item = CachedCostItemWait(go) 29677db96d56Sopenharmony_ci 29687db96d56Sopenharmony_ci num_threads = 3 29697db96d56Sopenharmony_ci 29707db96d56Sopenharmony_ci orig_si = sys.getswitchinterval() 29717db96d56Sopenharmony_ci sys.setswitchinterval(1e-6) 29727db96d56Sopenharmony_ci try: 29737db96d56Sopenharmony_ci threads = [ 29747db96d56Sopenharmony_ci threading.Thread(target=lambda: item.cost) 29757db96d56Sopenharmony_ci for k in range(num_threads) 29767db96d56Sopenharmony_ci ] 29777db96d56Sopenharmony_ci with threading_helper.start_threads(threads): 29787db96d56Sopenharmony_ci go.set() 29797db96d56Sopenharmony_ci finally: 29807db96d56Sopenharmony_ci sys.setswitchinterval(orig_si) 29817db96d56Sopenharmony_ci 29827db96d56Sopenharmony_ci self.assertEqual(item.cost, 2) 29837db96d56Sopenharmony_ci 29847db96d56Sopenharmony_ci def test_object_with_slots(self): 29857db96d56Sopenharmony_ci item = CachedCostItemWithSlots() 29867db96d56Sopenharmony_ci with self.assertRaisesRegex( 29877db96d56Sopenharmony_ci TypeError, 29887db96d56Sopenharmony_ci "No '__dict__' attribute on 'CachedCostItemWithSlots' instance to cache 'cost' property.", 29897db96d56Sopenharmony_ci ): 29907db96d56Sopenharmony_ci item.cost 29917db96d56Sopenharmony_ci 29927db96d56Sopenharmony_ci def test_immutable_dict(self): 29937db96d56Sopenharmony_ci class MyMeta(type): 29947db96d56Sopenharmony_ci @py_functools.cached_property 29957db96d56Sopenharmony_ci def prop(self): 29967db96d56Sopenharmony_ci return True 29977db96d56Sopenharmony_ci 29987db96d56Sopenharmony_ci class MyClass(metaclass=MyMeta): 29997db96d56Sopenharmony_ci pass 30007db96d56Sopenharmony_ci 30017db96d56Sopenharmony_ci with self.assertRaisesRegex( 30027db96d56Sopenharmony_ci TypeError, 30037db96d56Sopenharmony_ci "The '__dict__' attribute on 'MyMeta' instance does not support item assignment for caching 'prop' property.", 30047db96d56Sopenharmony_ci ): 30057db96d56Sopenharmony_ci MyClass.prop 30067db96d56Sopenharmony_ci 30077db96d56Sopenharmony_ci def test_reuse_different_names(self): 30087db96d56Sopenharmony_ci """Disallow this case because decorated function a would not be cached.""" 30097db96d56Sopenharmony_ci with self.assertRaises(RuntimeError) as ctx: 30107db96d56Sopenharmony_ci class ReusedCachedProperty: 30117db96d56Sopenharmony_ci @py_functools.cached_property 30127db96d56Sopenharmony_ci def a(self): 30137db96d56Sopenharmony_ci pass 30147db96d56Sopenharmony_ci 30157db96d56Sopenharmony_ci b = a 30167db96d56Sopenharmony_ci 30177db96d56Sopenharmony_ci self.assertEqual( 30187db96d56Sopenharmony_ci str(ctx.exception.__context__), 30197db96d56Sopenharmony_ci str(TypeError("Cannot assign the same cached_property to two different names ('a' and 'b').")) 30207db96d56Sopenharmony_ci ) 30217db96d56Sopenharmony_ci 30227db96d56Sopenharmony_ci def test_reuse_same_name(self): 30237db96d56Sopenharmony_ci """Reusing a cached_property on different classes under the same name is OK.""" 30247db96d56Sopenharmony_ci counter = 0 30257db96d56Sopenharmony_ci 30267db96d56Sopenharmony_ci @py_functools.cached_property 30277db96d56Sopenharmony_ci def _cp(_self): 30287db96d56Sopenharmony_ci nonlocal counter 30297db96d56Sopenharmony_ci counter += 1 30307db96d56Sopenharmony_ci return counter 30317db96d56Sopenharmony_ci 30327db96d56Sopenharmony_ci class A: 30337db96d56Sopenharmony_ci cp = _cp 30347db96d56Sopenharmony_ci 30357db96d56Sopenharmony_ci class B: 30367db96d56Sopenharmony_ci cp = _cp 30377db96d56Sopenharmony_ci 30387db96d56Sopenharmony_ci a = A() 30397db96d56Sopenharmony_ci b = B() 30407db96d56Sopenharmony_ci 30417db96d56Sopenharmony_ci self.assertEqual(a.cp, 1) 30427db96d56Sopenharmony_ci self.assertEqual(b.cp, 2) 30437db96d56Sopenharmony_ci self.assertEqual(a.cp, 1) 30447db96d56Sopenharmony_ci 30457db96d56Sopenharmony_ci def test_set_name_not_called(self): 30467db96d56Sopenharmony_ci cp = py_functools.cached_property(lambda s: None) 30477db96d56Sopenharmony_ci class Foo: 30487db96d56Sopenharmony_ci pass 30497db96d56Sopenharmony_ci 30507db96d56Sopenharmony_ci Foo.cp = cp 30517db96d56Sopenharmony_ci 30527db96d56Sopenharmony_ci with self.assertRaisesRegex( 30537db96d56Sopenharmony_ci TypeError, 30547db96d56Sopenharmony_ci "Cannot use cached_property instance without calling __set_name__ on it.", 30557db96d56Sopenharmony_ci ): 30567db96d56Sopenharmony_ci Foo().cp 30577db96d56Sopenharmony_ci 30587db96d56Sopenharmony_ci def test_access_from_class(self): 30597db96d56Sopenharmony_ci self.assertIsInstance(CachedCostItem.cost, py_functools.cached_property) 30607db96d56Sopenharmony_ci 30617db96d56Sopenharmony_ci def test_doc(self): 30627db96d56Sopenharmony_ci self.assertEqual(CachedCostItem.cost.__doc__, "The cost of the item.") 30637db96d56Sopenharmony_ci 30647db96d56Sopenharmony_ci 30657db96d56Sopenharmony_ciif __name__ == '__main__': 30667db96d56Sopenharmony_ci unittest.main() 3067