test_funcattrs.py revision 5c8da86f3a515ce1a6d5f27fd15e3c5f4d8e931e
1from test import test_support 2import types 3import unittest 4 5class FuncAttrsTest(unittest.TestCase): 6 def setUp(self): 7 class F: 8 def a(self): 9 pass 10 def b(): 11 return 3 12 self.f = F 13 self.fi = F() 14 self.b = b 15 16 def cannot_set_attr(self,obj, name, value, exceptions): 17 # This method is not called as a test (name doesn't start with 'test'), 18 # but may be used by other tests. 19 try: setattr(obj, name, value) 20 except exceptions: pass 21 else: self.fail("shouldn't be able to set %s to %r" % (name, value)) 22 try: delattr(obj, name) 23 except exceptions: pass 24 else: self.fail("shouldn't be able to del %s" % name) 25 26 27class FunctionPropertiesTest(FuncAttrsTest): 28 # Include the external setUp method that is common to all tests 29 def test_module(self): 30 self.assertEqual(self.b.__module__, __name__) 31 32 def test_dir_includes_correct_attrs(self): 33 self.b.known_attr = 7 34 self.assertTrue('known_attr' in dir(self.b), 35 "set attributes not in dir listing of method") 36 # Test on underlying function object of method 37 self.f.a.im_func.known_attr = 7 38 self.assertTrue('known_attr' in dir(self.f.a), 39 "set attribute on unbound method implementation in class not in " 40 "dir") 41 self.assertTrue('known_attr' in dir(self.fi.a), 42 "set attribute on unbound method implementations, should show up" 43 " in next dir") 44 45 def test_duplicate_function_equality(self): 46 # Body of `duplicate' is the exact same as self.b 47 def duplicate(): 48 'my docstring' 49 return 3 50 self.assertNotEqual(self.b, duplicate) 51 52 def test_copying_func_code(self): 53 def test(): pass 54 self.assertEqual(test(), None) 55 test.func_code = self.b.func_code 56 self.assertEqual(test(), 3) # self.b always returns 3, arbitrarily 57 58 def test_func_globals(self): 59 self.assertEqual(self.b.func_globals, globals()) 60 self.cannot_set_attr(self.b, 'func_globals', 2, TypeError) 61 62 def test_func_name(self): 63 self.assertEqual(self.b.__name__, 'b') 64 self.assertEqual(self.b.func_name, 'b') 65 self.b.__name__ = 'c' 66 self.assertEqual(self.b.__name__, 'c') 67 self.assertEqual(self.b.func_name, 'c') 68 self.b.func_name = 'd' 69 self.assertEqual(self.b.__name__, 'd') 70 self.assertEqual(self.b.func_name, 'd') 71 # __name__ and func_name must be a string 72 self.cannot_set_attr(self.b, '__name__', 7, TypeError) 73 self.cannot_set_attr(self.b, 'func_name', 7, TypeError) 74 # __name__ must be available when in restricted mode. Exec will raise 75 # AttributeError if __name__ is not available on f. 76 s = """def f(): pass\nf.__name__""" 77 exec s in {'__builtins__': {}} 78 # Test on methods, too 79 self.assertEqual(self.f.a.__name__, 'a') 80 self.assertEqual(self.fi.a.__name__, 'a') 81 self.cannot_set_attr(self.f.a, "__name__", 'a', AttributeError) 82 self.cannot_set_attr(self.fi.a, "__name__", 'a', AttributeError) 83 84 def test_func_code(self): 85 num_one, num_two = 7, 8 86 def a(): pass 87 def b(): return 12 88 def c(): return num_one 89 def d(): return num_two 90 def e(): return num_one, num_two 91 for func in [a, b, c, d, e]: 92 self.assertEqual(type(func.func_code), types.CodeType) 93 self.assertEqual(c(), 7) 94 self.assertEqual(d(), 8) 95 d.func_code = c.func_code 96 self.assertEqual(c.func_code, d.func_code) 97 self.assertEqual(c(), 7) 98 # self.assertEqual(d(), 7) 99 try: b.func_code = c.func_code 100 except ValueError: pass 101 else: self.fail( 102 "func_code with different numbers of free vars should not be " 103 "possible") 104 try: e.func_code = d.func_code 105 except ValueError: pass 106 else: self.fail( 107 "func_code with different numbers of free vars should not be " 108 "possible") 109 110 def test_blank_func_defaults(self): 111 self.assertEqual(self.b.func_defaults, None) 112 del self.b.func_defaults 113 self.assertEqual(self.b.func_defaults, None) 114 115 def test_func_default_args(self): 116 def first_func(a, b): 117 return a+b 118 def second_func(a=1, b=2): 119 return a+b 120 self.assertEqual(first_func.func_defaults, None) 121 self.assertEqual(second_func.func_defaults, (1, 2)) 122 first_func.func_defaults = (1, 2) 123 self.assertEqual(first_func.func_defaults, (1, 2)) 124 self.assertEqual(first_func(), 3) 125 self.assertEqual(first_func(3), 5) 126 self.assertEqual(first_func(3, 5), 8) 127 del second_func.func_defaults 128 self.assertEqual(second_func.func_defaults, None) 129 try: second_func() 130 except TypeError: pass 131 else: self.fail( 132 "func_defaults does not update; deleting it does not remove " 133 "requirement") 134 135class ImplicitReferencesTest(FuncAttrsTest): 136 def test_im_class(self): 137 self.assertEqual(self.f.a.im_class, self.f) 138 self.assertEqual(self.fi.a.im_class, self.f) 139 self.cannot_set_attr(self.f.a, "im_class", self.f, TypeError) 140 self.cannot_set_attr(self.fi.a, "im_class", self.f, TypeError) 141 142 def test_im_func(self): 143 self.f.b = self.b 144 self.assertEqual(self.f.b.im_func, self.b) 145 self.assertEqual(self.fi.b.im_func, self.b) 146 self.cannot_set_attr(self.f.b, "im_func", self.b, TypeError) 147 self.cannot_set_attr(self.fi.b, "im_func", self.b, TypeError) 148 149 def test_im_self(self): 150 self.assertEqual(self.f.a.im_self, None) 151 self.assertEqual(self.fi.a.im_self, self.fi) 152 self.cannot_set_attr(self.f.a, "im_self", None, TypeError) 153 self.cannot_set_attr(self.fi.a, "im_self", self.fi, TypeError) 154 155 def test_im_func_non_method(self): 156 # Behavior should be the same when a method is added via an attr 157 # assignment 158 self.f.id = types.MethodType(id, None, self.f) 159 self.assertEqual(self.fi.id(), id(self.fi)) 160 self.assertNotEqual(self.fi.id(), id(self.f)) 161 # Test usage 162 try: self.f.id.unknown_attr 163 except AttributeError: pass 164 else: self.fail("using unknown attributes should raise AttributeError") 165 # Test assignment and deletion 166 self.cannot_set_attr(self.f.id, 'unknown_attr', 2, AttributeError) 167 self.cannot_set_attr(self.fi.id, 'unknown_attr', 2, AttributeError) 168 169 def test_implicit_method_properties(self): 170 self.f.a.im_func.known_attr = 7 171 self.assertEqual(self.f.a.known_attr, 7) 172 self.assertEqual(self.fi.a.known_attr, 7) 173 174class ArbitraryFunctionAttrTest(FuncAttrsTest): 175 def test_set_attr(self): 176 self.b.known_attr = 7 177 self.assertEqual(self.b.known_attr, 7) 178 for func in [self.f.a, self.fi.a]: 179 try: func.known_attr = 7 180 except AttributeError: pass 181 else: self.fail("setting attributes on methods should raise error") 182 183 def test_delete_unknown_attr(self): 184 try: del self.b.unknown_attr 185 except AttributeError: pass 186 else: self.fail("deleting unknown attribute should raise TypeError") 187 188 def test_setting_attrs_duplicates(self): 189 try: self.f.a.klass = self.f 190 except AttributeError: pass 191 else: self.fail("setting arbitrary attribute in unbound function " 192 " should raise AttributeError") 193 self.f.a.im_func.klass = self.f 194 for method in [self.f.a, self.fi.a, self.fi.a.im_func]: 195 self.assertEqual(method.klass, self.f) 196 197 def test_unset_attr(self): 198 for func in [self.b, self.f.a, self.fi.a]: 199 try: func.non_existent_attr 200 except AttributeError: pass 201 else: self.fail("using unknown attributes should raise " 202 "AttributeError") 203 204class FunctionDictsTest(FuncAttrsTest): 205 def test_setting_dict_to_invalid(self): 206 self.cannot_set_attr(self.b, '__dict__', None, TypeError) 207 self.cannot_set_attr(self.b, 'func_dict', None, TypeError) 208 from UserDict import UserDict 209 d = UserDict({'known_attr': 7}) 210 self.cannot_set_attr(self.f.a.im_func, '__dict__', d, TypeError) 211 self.cannot_set_attr(self.fi.a.im_func, '__dict__', d, TypeError) 212 213 def test_setting_dict_to_valid(self): 214 d = {'known_attr': 7} 215 self.b.__dict__ = d 216 # Setting dict is only possible on the underlying function objects 217 self.f.a.im_func.__dict__ = d 218 # Test assignment 219 self.assertEqual(d, self.b.__dict__) 220 self.assertEqual(d, self.b.func_dict) 221 # ... and on all the different ways of referencing the method's func 222 self.assertEqual(d, self.f.a.im_func.__dict__) 223 self.assertEqual(d, self.f.a.__dict__) 224 self.assertEqual(d, self.fi.a.im_func.__dict__) 225 self.assertEqual(d, self.fi.a.__dict__) 226 # Test value 227 self.assertEqual(self.b.known_attr, 7) 228 self.assertEqual(self.b.__dict__['known_attr'], 7) 229 self.assertEqual(self.b.func_dict['known_attr'], 7) 230 # ... and again, on all the different method's names 231 self.assertEqual(self.f.a.im_func.known_attr, 7) 232 self.assertEqual(self.f.a.known_attr, 7) 233 self.assertEqual(self.fi.a.im_func.known_attr, 7) 234 self.assertEqual(self.fi.a.known_attr, 7) 235 236 def test_delete_func_dict(self): 237 try: del self.b.__dict__ 238 except TypeError: pass 239 else: self.fail("deleting function dictionary should raise TypeError") 240 try: del self.b.func_dict 241 except TypeError: pass 242 else: self.fail("deleting function dictionary should raise TypeError") 243 244 def test_unassigned_dict(self): 245 self.assertEqual(self.b.__dict__, {}) 246 247 def test_func_as_dict_key(self): 248 value = "Some string" 249 d = {} 250 d[self.b] = value 251 self.assertEqual(d[self.b], value) 252 253class FunctionDocstringTest(FuncAttrsTest): 254 def test_set_docstring_attr(self): 255 self.assertEqual(self.b.__doc__, None) 256 self.assertEqual(self.b.func_doc, None) 257 docstr = "A test method that does nothing" 258 self.b.__doc__ = self.f.a.im_func.__doc__ = docstr 259 self.assertEqual(self.b.__doc__, docstr) 260 self.assertEqual(self.b.func_doc, docstr) 261 self.assertEqual(self.f.a.__doc__, docstr) 262 self.assertEqual(self.fi.a.__doc__, docstr) 263 self.cannot_set_attr(self.f.a, "__doc__", docstr, AttributeError) 264 self.cannot_set_attr(self.fi.a, "__doc__", docstr, AttributeError) 265 266 def test_delete_docstring(self): 267 self.b.__doc__ = "The docstring" 268 del self.b.__doc__ 269 self.assertEqual(self.b.__doc__, None) 270 self.assertEqual(self.b.func_doc, None) 271 self.b.func_doc = "The docstring" 272 del self.b.func_doc 273 self.assertEqual(self.b.__doc__, None) 274 self.assertEqual(self.b.func_doc, None) 275 276class StaticMethodAttrsTest(unittest.TestCase): 277 def test_func_attribute(self): 278 def f(): 279 pass 280 281 c = classmethod(f) 282 self.assertTrue(c.__func__ is f) 283 284 s = staticmethod(f) 285 self.assertTrue(s.__func__ is f) 286 287 288def test_main(): 289 test_support.run_unittest(FunctionPropertiesTest, ImplicitReferencesTest, 290 ArbitraryFunctionAttrTest, FunctionDictsTest, 291 FunctionDocstringTest, 292 StaticMethodAttrsTest) 293 294if __name__ == "__main__": 295 test_main() 296