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