test_funcattrs.py revision d9d1d4ac6fda7f4c898b55194be37b03b89450e9
1from test_support import verbose, TestFailed, verify 2import types 3 4class F: 5 def a(self): 6 pass 7 8def b(): 9 'my docstring' 10 pass 11 12# setting attributes on functions 13try: 14 b.publish 15except AttributeError: pass 16else: raise TestFailed, 'expected AttributeError' 17 18if b.__dict__ <> {}: 19 raise TestFailed, 'expected unassigned func.__dict__ to be {}' 20 21b.publish = 1 22if b.publish <> 1: 23 raise TestFailed, 'function attribute not set to expected value' 24 25docstring = 'its docstring' 26b.__doc__ = docstring 27if b.__doc__ <> docstring: 28 raise TestFailed, 'problem with setting __doc__ attribute' 29 30if 'publish' not in dir(b): 31 raise TestFailed, 'attribute not in dir()' 32 33try: 34 del b.__dict__ 35except TypeError: pass 36else: raise TestFailed, 'del func.__dict__ expected TypeError' 37 38b.publish = 1 39try: 40 b.__dict__ = None 41except TypeError: pass 42else: raise TestFailed, 'func.__dict__ = None expected TypeError' 43 44d = {'hello': 'world'} 45b.__dict__ = d 46if b.func_dict is not d: 47 raise TestFailed, 'func.__dict__ assignment to dictionary failed' 48if b.hello <> 'world': 49 raise TestFailed, 'attribute after func.__dict__ assignment failed' 50 51f1 = F() 52f2 = F() 53 54try: 55 F.a.publish 56except AttributeError: pass 57else: raise TestFailed, 'expected AttributeError' 58 59try: 60 f1.a.publish 61except AttributeError: pass 62else: raise TestFailed, 'expected AttributeError' 63 64# In Python 2.1 beta 1, we disallowed setting attributes on unbound methods 65# (it was already disallowed on bound methods). See the PEP for details. 66try: 67 F.a.publish = 1 68except TypeError: pass 69else: raise TestFailed, 'expected TypeError' 70 71# But setting it explicitly on the underlying function object is okay. 72F.a.im_func.publish = 1 73 74if F.a.publish <> 1: 75 raise TestFailed, 'unbound method attribute not set to expected value' 76 77if f1.a.publish <> 1: 78 raise TestFailed, 'bound method attribute access did not work' 79 80if f2.a.publish <> 1: 81 raise TestFailed, 'bound method attribute access did not work' 82 83if 'publish' not in dir(F.a): 84 raise TestFailed, 'attribute not in dir()' 85 86try: 87 f1.a.publish = 0 88except TypeError: pass 89else: raise TestFailed, 'expected TypeError' 90 91# See the comment above about the change in semantics for Python 2.1b1 92try: 93 F.a.myclass = F 94except TypeError: pass 95else: raise TestFailed, 'expected TypeError' 96 97F.a.im_func.myclass = F 98 99f1.a.myclass 100f2.a.myclass 101f1.a.myclass 102F.a.myclass 103 104if f1.a.myclass is not f2.a.myclass or \ 105 f1.a.myclass is not F.a.myclass: 106 raise TestFailed, 'attributes were not the same' 107 108# try setting __dict__ 109try: 110 F.a.__dict__ = (1, 2, 3) 111except TypeError: pass 112else: raise TestFailed, 'expected TypeError' 113 114F.a.im_func.__dict__ = {'one': 11, 'two': 22, 'three': 33} 115 116if f1.a.two <> 22: 117 raise TestFailed, 'setting __dict__' 118 119from UserDict import UserDict 120d = UserDict({'four': 44, 'five': 55}) 121 122try: 123 F.a.__dict__ = d 124except TypeError: pass 125else: raise TestFailed 126 127if f2.a.one <> f1.a.one <> F.a.one <> 11: 128 raise TestFailed 129 130# im_func may not be a Python method! 131import new 132F.id = new.instancemethod(id, None, F) 133 134eff = F() 135if eff.id() <> id(eff): 136 raise TestFailed 137 138try: 139 F.id.foo 140except AttributeError: pass 141else: raise TestFailed 142 143try: 144 F.id.foo = 12 145except TypeError: pass 146else: raise TestFailed 147 148try: 149 F.id.foo 150except AttributeError: pass 151else: raise TestFailed 152 153try: 154 eff.id.foo 155except AttributeError: pass 156else: raise TestFailed 157 158try: 159 eff.id.foo = 12 160except TypeError: pass 161else: raise TestFailed 162 163try: 164 eff.id.foo 165except AttributeError: pass 166else: raise TestFailed 167 168# Regression test for a crash in pre-2.1a1 169def another(): 170 pass 171 172try: 173 del another.__dict__ 174except TypeError: pass 175else: raise TestFailed 176 177try: 178 del another.func_dict 179except TypeError: pass 180else: raise TestFailed 181 182try: 183 another.func_dict = None 184except TypeError: pass 185else: raise TestFailed 186 187try: 188 del another.bar 189except AttributeError: pass 190else: raise TestFailed 191 192# This isn't specifically related to function attributes, but it does test a 193# core dump regression in funcobject.c 194del another.func_defaults 195 196def foo(): 197 pass 198 199def bar(): 200 pass 201 202def temp(): 203 print 1 204 205if foo==bar: 206 raise TestFailed 207 208d={} 209d[foo] = 1 210 211foo.func_code = temp.func_code 212 213d[foo] 214 215# Test all predefined function attributes systematically 216 217def test_func_closure(): 218 a = 12 219 def f(): print a 220 c = f.func_closure 221 verify(isinstance(c, tuple)) 222 verify(len(c) == 1) 223 verify(c[0].__class__.__name__ == "cell") # don't have a type object handy 224 try: 225 f.func_closure = c 226 except (AttributeError, TypeError): 227 pass 228 else: 229 raise TestFailed, "shouldn't be allowed to set func_closure" 230 try: 231 del a.func_closure 232 except (AttributeError, TypeError): 233 pass 234 else: 235 raise TestFailed, "shouldn't be allowed to del func_closure" 236 237def test_func_doc(): 238 def f(): pass 239 verify(f.__doc__ is None) 240 verify(f.func_doc is None) 241 f.__doc__ = "hello" 242 verify(f.__doc__ == "hello") 243 verify(f.func_doc == "hello") 244 del f.__doc__ 245 verify(f.__doc__ is None) 246 verify(f.func_doc is None) 247 f.func_doc = "world" 248 verify(f.__doc__ == "world") 249 verify(f.func_doc == "world") 250 del f.func_doc 251 verify(f.func_doc is None) 252 verify(f.__doc__ is None) 253 254def test_func_globals(): 255 def f(): pass 256 verify(f.func_globals is globals()) 257 try: 258 f.func_globals = globals() 259 except (AttributeError, TypeError): 260 pass 261 else: 262 raise TestFailed, "shouldn't be allowed to set func_globals" 263 try: 264 del f.func_globals 265 except (AttributeError, TypeError): 266 pass 267 else: 268 raise TestFailed, "shouldn't be allowed to del func_globals" 269 270def test_func_name(): 271 def f(): pass 272 verify(f.__name__ == "f") 273 verify(f.func_name == "f") 274 try: 275 f.func_name = "f" 276 except (AttributeError, TypeError): 277 pass 278 else: 279 raise TestFailed, "shouldn't be allowed to set func_name" 280 try: 281 f.__name__ = "f" 282 except (AttributeError, TypeError): 283 pass 284 else: 285 raise TestFailed, "shouldn't be allowed to set __name__" 286 try: 287 del f.func_name 288 except (AttributeError, TypeError): 289 pass 290 else: 291 raise TestFailed, "shouldn't be allowed to del func_name" 292 try: 293 del f.__name__ 294 except (AttributeError, TypeError): 295 pass 296 else: 297 raise TestFailed, "shouldn't be allowed to del __name__" 298 299def test_func_code(): 300 def f(): pass 301 def g(): print 12 302 verify(type(f.func_code) is types.CodeType) 303 f.func_code = g.func_code 304 try: 305 del f.func_code 306 except (AttributeError, TypeError): 307 pass 308 else: 309 raise TestFailed, "shouldn't be allowed to del func_code" 310 311def test_func_defaults(): 312 def f(a, b): return (a, b) 313 verify(f.func_defaults is None) 314 f.func_defaults = (1, 2) 315 verify(f.func_defaults == (1, 2)) 316 verify(f(10) == (10, 2)) 317 def g(a=1, b=2): return (a, b) 318 verify(g.func_defaults == (1, 2)) 319 del g.func_defaults 320 verify(g.func_defaults is None) 321 try: 322 g() 323 except TypeError: 324 pass 325 else: 326 raise TestFailed, "shouldn't be allowed to call g() w/o defaults" 327 328def test_func_dict(): 329 def f(): pass 330 a = f.__dict__ 331 b = f.func_dict 332 verify(a == {}) 333 verify(a is b) 334 f.hello = 'world' 335 verify(a == {'hello': 'world'}) 336 verify(f.func_dict is a is f.__dict__) 337 f.func_dict = {} 338 try: 339 f.hello 340 except (AttributeError, TypeError): 341 pass 342 else: 343 raise TestFailed, "hello attribute should have disappeared" 344 f.__dict__ = {'world': 'hello'} 345 verify(f.world == "hello") 346 verify(f.__dict__ is f.func_dict == {'world': 'hello'}) 347 try: 348 del f.func_dict 349 except (AttributeError, TypeError): 350 pass 351 else: 352 raise TestFailed, "shouldn't be allowed to delete func_dict" 353 try: 354 del f.__dict__ 355 except (AttributeError, TypeError): 356 pass 357 else: 358 raise TestFailed, "shouldn't be allowed to delete __dict__" 359 360def testmore(): 361 test_func_closure() 362 test_func_doc() 363 test_func_globals() 364 test_func_name() 365 test_func_code() 366 test_func_defaults() 367 test_func_dict() 368 369testmore() 370