1import textwrap 2import types 3import typing 4import unittest 5import warnings 6 7 8def global_function(): 9 def inner_function(): 10 class LocalClass: 11 pass 12 global inner_global_function 13 def inner_global_function(): 14 def inner_function2(): 15 pass 16 return inner_function2 17 return LocalClass 18 return lambda: inner_function 19 20 21class FuncAttrsTest(unittest.TestCase): 22 def setUp(self): 23 class F: 24 def a(self): 25 pass 26 def b(): 27 return 3 28 self.fi = F() 29 self.F = F 30 self.b = b 31 32 def cannot_set_attr(self, obj, name, value, exceptions): 33 try: 34 setattr(obj, name, value) 35 except exceptions: 36 pass 37 else: 38 self.fail("shouldn't be able to set %s to %r" % (name, value)) 39 try: 40 delattr(obj, name) 41 except exceptions: 42 pass 43 else: 44 self.fail("shouldn't be able to del %s" % name) 45 46 47class FunctionPropertiesTest(FuncAttrsTest): 48 # Include the external setUp method that is common to all tests 49 def test_module(self): 50 self.assertEqual(self.b.__module__, __name__) 51 52 def test_dir_includes_correct_attrs(self): 53 self.b.known_attr = 7 54 self.assertIn('known_attr', dir(self.b), 55 "set attributes not in dir listing of method") 56 # Test on underlying function object of method 57 self.F.a.known_attr = 7 58 self.assertIn('known_attr', dir(self.fi.a), "set attribute on function " 59 "implementations, should show up in next dir") 60 61 def test_duplicate_function_equality(self): 62 # Body of `duplicate' is the exact same as self.b 63 def duplicate(): 64 'my docstring' 65 return 3 66 self.assertNotEqual(self.b, duplicate) 67 68 def test_copying___code__(self): 69 def test(): pass 70 self.assertEqual(test(), None) 71 test.__code__ = self.b.__code__ 72 self.assertEqual(test(), 3) # self.b always returns 3, arbitrarily 73 74 def test_invalid___code___assignment(self): 75 def A(): pass 76 def B(): yield 77 async def C(): yield 78 async def D(x): await x 79 80 for src in [A, B, C, D]: 81 for dst in [A, B, C, D]: 82 if src == dst: 83 continue 84 85 assert src.__code__.co_flags != dst.__code__.co_flags 86 prev = dst.__code__ 87 try: 88 with self.assertWarnsRegex(DeprecationWarning, 'code object of non-matching type'): 89 dst.__code__ = src.__code__ 90 finally: 91 with warnings.catch_warnings(): 92 warnings.filterwarnings('ignore', '', DeprecationWarning) 93 dst.__code__ = prev 94 95 def test___globals__(self): 96 self.assertIs(self.b.__globals__, globals()) 97 self.cannot_set_attr(self.b, '__globals__', 2, 98 (AttributeError, TypeError)) 99 100 def test___builtins__(self): 101 if __name__ == "__main__": 102 builtins_dict = __builtins__.__dict__ 103 else: 104 builtins_dict = __builtins__ 105 106 self.assertIs(self.b.__builtins__, builtins_dict) 107 self.cannot_set_attr(self.b, '__builtins__', 2, 108 (AttributeError, TypeError)) 109 110 # bpo-42990: If globals is specified and has no "__builtins__" key, 111 # a function inherits the current builtins namespace. 112 def func(s): return len(s) 113 ns = {} 114 func2 = type(func)(func.__code__, ns) 115 self.assertIs(func2.__globals__, ns) 116 self.assertIs(func2.__builtins__, builtins_dict) 117 118 # Make sure that the function actually works. 119 self.assertEqual(func2("abc"), 3) 120 self.assertEqual(ns, {}) 121 122 # Define functions using exec() with different builtins, 123 # and test inheritance when globals has no "__builtins__" key 124 code = textwrap.dedent(""" 125 def func3(s): pass 126 func4 = type(func3)(func3.__code__, {}) 127 """) 128 safe_builtins = {'None': None} 129 ns = {'type': type, '__builtins__': safe_builtins} 130 exec(code, ns) 131 self.assertIs(ns['func3'].__builtins__, safe_builtins) 132 self.assertIs(ns['func4'].__builtins__, safe_builtins) 133 self.assertIs(ns['func3'].__globals__['__builtins__'], safe_builtins) 134 self.assertNotIn('__builtins__', ns['func4'].__globals__) 135 136 def test___closure__(self): 137 a = 12 138 def f(): print(a) 139 c = f.__closure__ 140 self.assertIsInstance(c, tuple) 141 self.assertEqual(len(c), 1) 142 # don't have a type object handy 143 self.assertEqual(c[0].__class__.__name__, "cell") 144 self.cannot_set_attr(f, "__closure__", c, AttributeError) 145 146 def test_cell_new(self): 147 cell_obj = types.CellType(1) 148 self.assertEqual(cell_obj.cell_contents, 1) 149 150 cell_obj = types.CellType() 151 msg = "shouldn't be able to read an empty cell" 152 with self.assertRaises(ValueError, msg=msg): 153 cell_obj.cell_contents 154 155 def test_empty_cell(self): 156 def f(): print(a) 157 try: 158 f.__closure__[0].cell_contents 159 except ValueError: 160 pass 161 else: 162 self.fail("shouldn't be able to read an empty cell") 163 a = 12 164 165 def test_set_cell(self): 166 a = 12 167 def f(): return a 168 c = f.__closure__ 169 c[0].cell_contents = 9 170 self.assertEqual(c[0].cell_contents, 9) 171 self.assertEqual(f(), 9) 172 self.assertEqual(a, 9) 173 del c[0].cell_contents 174 try: 175 c[0].cell_contents 176 except ValueError: 177 pass 178 else: 179 self.fail("shouldn't be able to read an empty cell") 180 with self.assertRaises(NameError): 181 f() 182 with self.assertRaises(UnboundLocalError): 183 print(a) 184 185 def test___name__(self): 186 self.assertEqual(self.b.__name__, 'b') 187 self.b.__name__ = 'c' 188 self.assertEqual(self.b.__name__, 'c') 189 self.b.__name__ = 'd' 190 self.assertEqual(self.b.__name__, 'd') 191 # __name__ and __name__ must be a string 192 self.cannot_set_attr(self.b, '__name__', 7, TypeError) 193 # __name__ must be available when in restricted mode. Exec will raise 194 # AttributeError if __name__ is not available on f. 195 s = """def f(): pass\nf.__name__""" 196 exec(s, {'__builtins__': {}}) 197 # Test on methods, too 198 self.assertEqual(self.fi.a.__name__, 'a') 199 self.cannot_set_attr(self.fi.a, "__name__", 'a', AttributeError) 200 201 def test___qualname__(self): 202 # PEP 3155 203 self.assertEqual(self.b.__qualname__, 'FuncAttrsTest.setUp.<locals>.b') 204 self.assertEqual(FuncAttrsTest.setUp.__qualname__, 'FuncAttrsTest.setUp') 205 self.assertEqual(global_function.__qualname__, 'global_function') 206 self.assertEqual(global_function().__qualname__, 207 'global_function.<locals>.<lambda>') 208 self.assertEqual(global_function()().__qualname__, 209 'global_function.<locals>.inner_function') 210 self.assertEqual(global_function()()().__qualname__, 211 'global_function.<locals>.inner_function.<locals>.LocalClass') 212 self.assertEqual(inner_global_function.__qualname__, 'inner_global_function') 213 self.assertEqual(inner_global_function().__qualname__, 'inner_global_function.<locals>.inner_function2') 214 self.b.__qualname__ = 'c' 215 self.assertEqual(self.b.__qualname__, 'c') 216 self.b.__qualname__ = 'd' 217 self.assertEqual(self.b.__qualname__, 'd') 218 # __qualname__ must be a string 219 self.cannot_set_attr(self.b, '__qualname__', 7, TypeError) 220 221 def test___type_params__(self): 222 def generic[T](): pass 223 def not_generic(): pass 224 lambda_ = lambda: ... 225 T, = generic.__type_params__ 226 self.assertIsInstance(T, typing.TypeVar) 227 self.assertEqual(generic.__type_params__, (T,)) 228 for func in (not_generic, lambda_): 229 with self.subTest(func=func): 230 self.assertEqual(func.__type_params__, ()) 231 with self.assertRaises(TypeError): 232 del func.__type_params__ 233 with self.assertRaises(TypeError): 234 func.__type_params__ = 42 235 func.__type_params__ = (T,) 236 self.assertEqual(func.__type_params__, (T,)) 237 238 def test___code__(self): 239 num_one, num_two = 7, 8 240 def a(): pass 241 def b(): return 12 242 def c(): return num_one 243 def d(): return num_two 244 def e(): return num_one, num_two 245 for func in [a, b, c, d, e]: 246 self.assertEqual(type(func.__code__), types.CodeType) 247 self.assertEqual(c(), 7) 248 self.assertEqual(d(), 8) 249 d.__code__ = c.__code__ 250 self.assertEqual(c.__code__, d.__code__) 251 self.assertEqual(c(), 7) 252 # self.assertEqual(d(), 7) 253 try: 254 b.__code__ = c.__code__ 255 except ValueError: 256 pass 257 else: 258 self.fail("__code__ with different numbers of free vars should " 259 "not be possible") 260 try: 261 e.__code__ = d.__code__ 262 except ValueError: 263 pass 264 else: 265 self.fail("__code__ with different numbers of free vars should " 266 "not be possible") 267 268 def test_blank_func_defaults(self): 269 self.assertEqual(self.b.__defaults__, None) 270 del self.b.__defaults__ 271 self.assertEqual(self.b.__defaults__, None) 272 273 def test_func_default_args(self): 274 def first_func(a, b): 275 return a+b 276 def second_func(a=1, b=2): 277 return a+b 278 self.assertEqual(first_func.__defaults__, None) 279 self.assertEqual(second_func.__defaults__, (1, 2)) 280 first_func.__defaults__ = (1, 2) 281 self.assertEqual(first_func.__defaults__, (1, 2)) 282 self.assertEqual(first_func(), 3) 283 self.assertEqual(first_func(3), 5) 284 self.assertEqual(first_func(3, 5), 8) 285 del second_func.__defaults__ 286 self.assertEqual(second_func.__defaults__, None) 287 try: 288 second_func() 289 except TypeError: 290 pass 291 else: 292 self.fail("__defaults__ does not update; deleting it does not " 293 "remove requirement") 294 295 296class InstancemethodAttrTest(FuncAttrsTest): 297 298 def test___class__(self): 299 self.assertEqual(self.fi.a.__self__.__class__, self.F) 300 self.cannot_set_attr(self.fi.a, "__class__", self.F, TypeError) 301 302 def test___func__(self): 303 self.assertEqual(self.fi.a.__func__, self.F.a) 304 self.cannot_set_attr(self.fi.a, "__func__", self.F.a, AttributeError) 305 306 def test___self__(self): 307 self.assertEqual(self.fi.a.__self__, self.fi) 308 self.cannot_set_attr(self.fi.a, "__self__", self.fi, AttributeError) 309 310 def test___func___non_method(self): 311 # Behavior should be the same when a method is added via an attr 312 # assignment 313 self.fi.id = types.MethodType(id, self.fi) 314 self.assertEqual(self.fi.id(), id(self.fi)) 315 # Test usage 316 try: 317 self.fi.id.unknown_attr 318 except AttributeError: 319 pass 320 else: 321 self.fail("using unknown attributes should raise AttributeError") 322 # Test assignment and deletion 323 self.cannot_set_attr(self.fi.id, 'unknown_attr', 2, AttributeError) 324 325 326class ArbitraryFunctionAttrTest(FuncAttrsTest): 327 def test_set_attr(self): 328 self.b.known_attr = 7 329 self.assertEqual(self.b.known_attr, 7) 330 try: 331 self.fi.a.known_attr = 7 332 except AttributeError: 333 pass 334 else: 335 self.fail("setting attributes on methods should raise error") 336 337 def test_delete_unknown_attr(self): 338 try: 339 del self.b.unknown_attr 340 except AttributeError: 341 pass 342 else: 343 self.fail("deleting unknown attribute should raise TypeError") 344 345 def test_unset_attr(self): 346 for func in [self.b, self.fi.a]: 347 try: 348 func.non_existent_attr 349 except AttributeError: 350 pass 351 else: 352 self.fail("using unknown attributes should raise " 353 "AttributeError") 354 355 356class FunctionDictsTest(FuncAttrsTest): 357 def test_setting_dict_to_invalid(self): 358 self.cannot_set_attr(self.b, '__dict__', None, TypeError) 359 from collections import UserDict 360 d = UserDict({'known_attr': 7}) 361 self.cannot_set_attr(self.fi.a.__func__, '__dict__', d, TypeError) 362 363 def test_setting_dict_to_valid(self): 364 d = {'known_attr': 7} 365 self.b.__dict__ = d 366 # Test assignment 367 self.assertIs(d, self.b.__dict__) 368 # ... and on all the different ways of referencing the method's func 369 self.F.a.__dict__ = d 370 self.assertIs(d, self.fi.a.__func__.__dict__) 371 self.assertIs(d, self.fi.a.__dict__) 372 # Test value 373 self.assertEqual(self.b.known_attr, 7) 374 self.assertEqual(self.b.__dict__['known_attr'], 7) 375 # ... and again, on all the different method's names 376 self.assertEqual(self.fi.a.__func__.known_attr, 7) 377 self.assertEqual(self.fi.a.known_attr, 7) 378 379 def test_delete___dict__(self): 380 try: 381 del self.b.__dict__ 382 except TypeError: 383 pass 384 else: 385 self.fail("deleting function dictionary should raise TypeError") 386 387 def test_unassigned_dict(self): 388 self.assertEqual(self.b.__dict__, {}) 389 390 def test_func_as_dict_key(self): 391 value = "Some string" 392 d = {} 393 d[self.b] = value 394 self.assertEqual(d[self.b], value) 395 396 397class FunctionDocstringTest(FuncAttrsTest): 398 def test_set_docstring_attr(self): 399 self.assertEqual(self.b.__doc__, None) 400 docstr = "A test method that does nothing" 401 self.b.__doc__ = docstr 402 self.F.a.__doc__ = docstr 403 self.assertEqual(self.b.__doc__, docstr) 404 self.assertEqual(self.fi.a.__doc__, docstr) 405 self.cannot_set_attr(self.fi.a, "__doc__", docstr, AttributeError) 406 407 def test_delete_docstring(self): 408 self.b.__doc__ = "The docstring" 409 del self.b.__doc__ 410 self.assertEqual(self.b.__doc__, None) 411 412 413def cell(value): 414 """Create a cell containing the given value.""" 415 def f(): 416 print(a) 417 a = value 418 return f.__closure__[0] 419 420def empty_cell(empty=True): 421 """Create an empty cell.""" 422 def f(): 423 print(a) 424 # the intent of the following line is simply "if False:"; it's 425 # spelt this way to avoid the danger that a future optimization 426 # might simply remove an "if False:" code block. 427 if not empty: 428 a = 1729 429 return f.__closure__[0] 430 431 432class CellTest(unittest.TestCase): 433 def test_comparison(self): 434 # These tests are here simply to exercise the comparison code; 435 # their presence should not be interpreted as providing any 436 # guarantees about the semantics (or even existence) of cell 437 # comparisons in future versions of CPython. 438 self.assertTrue(cell(2) < cell(3)) 439 self.assertTrue(empty_cell() < cell('saturday')) 440 self.assertTrue(empty_cell() == empty_cell()) 441 self.assertTrue(cell(-36) == cell(-36.0)) 442 self.assertTrue(cell(True) > empty_cell()) 443 444 445class StaticMethodAttrsTest(unittest.TestCase): 446 def test_func_attribute(self): 447 def f(): 448 pass 449 450 c = classmethod(f) 451 self.assertTrue(c.__func__ is f) 452 453 s = staticmethod(f) 454 self.assertTrue(s.__func__ is f) 455 456 457class BuiltinFunctionPropertiesTest(unittest.TestCase): 458 # XXX Not sure where this should really go since I can't find a 459 # test module specifically for builtin_function_or_method. 460 461 def test_builtin__qualname__(self): 462 import time 463 464 # builtin function: 465 self.assertEqual(len.__qualname__, 'len') 466 self.assertEqual(time.time.__qualname__, 'time') 467 468 # builtin classmethod: 469 self.assertEqual(dict.fromkeys.__qualname__, 'dict.fromkeys') 470 self.assertEqual(float.__getformat__.__qualname__, 471 'float.__getformat__') 472 473 # builtin staticmethod: 474 self.assertEqual(str.maketrans.__qualname__, 'str.maketrans') 475 self.assertEqual(bytes.maketrans.__qualname__, 'bytes.maketrans') 476 477 # builtin bound instance method: 478 self.assertEqual([1, 2, 3].append.__qualname__, 'list.append') 479 self.assertEqual({'foo': 'bar'}.pop.__qualname__, 'dict.pop') 480 481 482if __name__ == "__main__": 483 unittest.main() 484