|
1 from test.test_support import verbose, TestFailed, verify |
|
2 import types |
|
3 |
|
4 class F: |
|
5 def a(self): |
|
6 pass |
|
7 |
|
8 def b(): |
|
9 'my docstring' |
|
10 pass |
|
11 |
|
12 # __module__ is a special attribute |
|
13 verify(b.__module__ == __name__) |
|
14 verify(verify.__module__ == "test.test_support") |
|
15 |
|
16 # setting attributes on functions |
|
17 try: |
|
18 b.publish |
|
19 except AttributeError: pass |
|
20 else: raise TestFailed, 'expected AttributeError' |
|
21 |
|
22 if b.__dict__ <> {}: |
|
23 raise TestFailed, 'expected unassigned func.__dict__ to be {}' |
|
24 |
|
25 b.publish = 1 |
|
26 if b.publish <> 1: |
|
27 raise TestFailed, 'function attribute not set to expected value' |
|
28 |
|
29 docstring = 'its docstring' |
|
30 b.__doc__ = docstring |
|
31 if b.__doc__ <> docstring: |
|
32 raise TestFailed, 'problem with setting __doc__ attribute' |
|
33 |
|
34 if 'publish' not in dir(b): |
|
35 raise TestFailed, 'attribute not in dir()' |
|
36 |
|
37 try: |
|
38 del b.__dict__ |
|
39 except TypeError: pass |
|
40 else: raise TestFailed, 'del func.__dict__ expected TypeError' |
|
41 |
|
42 b.publish = 1 |
|
43 try: |
|
44 b.__dict__ = None |
|
45 except TypeError: pass |
|
46 else: raise TestFailed, 'func.__dict__ = None expected TypeError' |
|
47 |
|
48 d = {'hello': 'world'} |
|
49 b.__dict__ = d |
|
50 if b.func_dict is not d: |
|
51 raise TestFailed, 'func.__dict__ assignment to dictionary failed' |
|
52 if b.hello <> 'world': |
|
53 raise TestFailed, 'attribute after func.__dict__ assignment failed' |
|
54 |
|
55 f1 = F() |
|
56 f2 = F() |
|
57 |
|
58 try: |
|
59 F.a.publish |
|
60 except AttributeError: pass |
|
61 else: raise TestFailed, 'expected AttributeError' |
|
62 |
|
63 try: |
|
64 f1.a.publish |
|
65 except AttributeError: pass |
|
66 else: raise TestFailed, 'expected AttributeError' |
|
67 |
|
68 # In Python 2.1 beta 1, we disallowed setting attributes on unbound methods |
|
69 # (it was already disallowed on bound methods). See the PEP for details. |
|
70 try: |
|
71 F.a.publish = 1 |
|
72 except (AttributeError, TypeError): pass |
|
73 else: raise TestFailed, 'expected AttributeError or TypeError' |
|
74 |
|
75 # But setting it explicitly on the underlying function object is okay. |
|
76 F.a.im_func.publish = 1 |
|
77 |
|
78 if F.a.publish <> 1: |
|
79 raise TestFailed, 'unbound method attribute not set to expected value' |
|
80 |
|
81 if f1.a.publish <> 1: |
|
82 raise TestFailed, 'bound method attribute access did not work' |
|
83 |
|
84 if f2.a.publish <> 1: |
|
85 raise TestFailed, 'bound method attribute access did not work' |
|
86 |
|
87 if 'publish' not in dir(F.a): |
|
88 raise TestFailed, 'attribute not in dir()' |
|
89 |
|
90 try: |
|
91 f1.a.publish = 0 |
|
92 except (AttributeError, TypeError): pass |
|
93 else: raise TestFailed, 'expected AttributeError or TypeError' |
|
94 |
|
95 # See the comment above about the change in semantics for Python 2.1b1 |
|
96 try: |
|
97 F.a.myclass = F |
|
98 except (AttributeError, TypeError): pass |
|
99 else: raise TestFailed, 'expected AttributeError or TypeError' |
|
100 |
|
101 F.a.im_func.myclass = F |
|
102 |
|
103 f1.a.myclass |
|
104 f2.a.myclass |
|
105 f1.a.myclass |
|
106 F.a.myclass |
|
107 |
|
108 if f1.a.myclass is not f2.a.myclass or \ |
|
109 f1.a.myclass is not F.a.myclass: |
|
110 raise TestFailed, 'attributes were not the same' |
|
111 |
|
112 # try setting __dict__ |
|
113 try: |
|
114 F.a.__dict__ = (1, 2, 3) |
|
115 except (AttributeError, TypeError): pass |
|
116 else: raise TestFailed, 'expected TypeError or AttributeError' |
|
117 |
|
118 F.a.im_func.__dict__ = {'one': 11, 'two': 22, 'three': 33} |
|
119 |
|
120 if f1.a.two <> 22: |
|
121 raise TestFailed, 'setting __dict__' |
|
122 |
|
123 from UserDict import UserDict |
|
124 d = UserDict({'four': 44, 'five': 55}) |
|
125 |
|
126 try: |
|
127 F.a.__dict__ = d |
|
128 except (AttributeError, TypeError): pass |
|
129 else: raise TestFailed |
|
130 |
|
131 if f2.a.one <> f1.a.one <> F.a.one <> 11: |
|
132 raise TestFailed |
|
133 |
|
134 # im_func may not be a Python method! |
|
135 import new |
|
136 F.id = new.instancemethod(id, None, F) |
|
137 |
|
138 eff = F() |
|
139 if eff.id() <> id(eff): |
|
140 raise TestFailed |
|
141 |
|
142 try: |
|
143 F.id.foo |
|
144 except AttributeError: pass |
|
145 else: raise TestFailed |
|
146 |
|
147 try: |
|
148 F.id.foo = 12 |
|
149 except (AttributeError, TypeError): pass |
|
150 else: raise TestFailed |
|
151 |
|
152 try: |
|
153 F.id.foo |
|
154 except AttributeError: pass |
|
155 else: raise TestFailed |
|
156 |
|
157 try: |
|
158 eff.id.foo |
|
159 except AttributeError: pass |
|
160 else: raise TestFailed |
|
161 |
|
162 try: |
|
163 eff.id.foo = 12 |
|
164 except (AttributeError, TypeError): pass |
|
165 else: raise TestFailed |
|
166 |
|
167 try: |
|
168 eff.id.foo |
|
169 except AttributeError: pass |
|
170 else: raise TestFailed |
|
171 |
|
172 # Regression test for a crash in pre-2.1a1 |
|
173 def another(): |
|
174 pass |
|
175 |
|
176 try: |
|
177 del another.__dict__ |
|
178 except TypeError: pass |
|
179 else: raise TestFailed |
|
180 |
|
181 try: |
|
182 del another.func_dict |
|
183 except TypeError: pass |
|
184 else: raise TestFailed |
|
185 |
|
186 try: |
|
187 another.func_dict = None |
|
188 except TypeError: pass |
|
189 else: raise TestFailed |
|
190 |
|
191 try: |
|
192 del another.bar |
|
193 except AttributeError: pass |
|
194 else: raise TestFailed |
|
195 |
|
196 # This isn't specifically related to function attributes, but it does test a |
|
197 # core dump regression in funcobject.c |
|
198 del another.func_defaults |
|
199 |
|
200 def foo(): |
|
201 pass |
|
202 |
|
203 def bar(): |
|
204 pass |
|
205 |
|
206 def temp(): |
|
207 print 1 |
|
208 |
|
209 if foo==bar: |
|
210 raise TestFailed |
|
211 |
|
212 d={} |
|
213 d[foo] = 1 |
|
214 |
|
215 foo.func_code = temp.func_code |
|
216 |
|
217 d[foo] |
|
218 |
|
219 # Test all predefined function attributes systematically |
|
220 |
|
221 def cantset(obj, name, value, exception=(AttributeError, TypeError)): |
|
222 verify(hasattr(obj, name)) # Otherwise it's probably a typo |
|
223 try: |
|
224 setattr(obj, name, value) |
|
225 except exception: |
|
226 pass |
|
227 else: |
|
228 raise TestFailed, "shouldn't be able to set %s to %r" % (name, value) |
|
229 try: |
|
230 delattr(obj, name) |
|
231 except (AttributeError, TypeError): |
|
232 pass |
|
233 else: |
|
234 raise TestFailed, "shouldn't be able to del %s" % name |
|
235 |
|
236 def test_func_closure(): |
|
237 a = 12 |
|
238 def f(): print a |
|
239 c = f.func_closure |
|
240 verify(isinstance(c, tuple)) |
|
241 verify(len(c) == 1) |
|
242 verify(c[0].__class__.__name__ == "cell") # don't have a type object handy |
|
243 cantset(f, "func_closure", c) |
|
244 |
|
245 def test_empty_cell(): |
|
246 def f(): print a |
|
247 try: |
|
248 f.func_closure[0].cell_contents |
|
249 except ValueError: |
|
250 pass |
|
251 else: |
|
252 raise TestFailed, "shouldn't be able to read an empty cell" |
|
253 |
|
254 a = 12 |
|
255 |
|
256 def test_func_doc(): |
|
257 def f(): pass |
|
258 verify(f.__doc__ is None) |
|
259 verify(f.func_doc is None) |
|
260 f.__doc__ = "hello" |
|
261 verify(f.__doc__ == "hello") |
|
262 verify(f.func_doc == "hello") |
|
263 del f.__doc__ |
|
264 verify(f.__doc__ is None) |
|
265 verify(f.func_doc is None) |
|
266 f.func_doc = "world" |
|
267 verify(f.__doc__ == "world") |
|
268 verify(f.func_doc == "world") |
|
269 del f.func_doc |
|
270 verify(f.func_doc is None) |
|
271 verify(f.__doc__ is None) |
|
272 |
|
273 def test_func_globals(): |
|
274 def f(): pass |
|
275 verify(f.func_globals is globals()) |
|
276 cantset(f, "func_globals", globals()) |
|
277 |
|
278 def test_func_name(): |
|
279 def f(): pass |
|
280 verify(f.__name__ == "f") |
|
281 verify(f.func_name == "f") |
|
282 f.__name__ = "g" |
|
283 verify(f.__name__ == "g") |
|
284 verify(f.func_name == "g") |
|
285 f.func_name = "h" |
|
286 verify(f.__name__ == "h") |
|
287 verify(f.func_name == "h") |
|
288 cantset(f, "func_globals", 1) |
|
289 cantset(f, "__name__", 1) |
|
290 # test that you can access func.__name__ in restricted mode |
|
291 s = """def f(): pass\nf.__name__""" |
|
292 exec s in {'__builtins__':{}} |
|
293 |
|
294 |
|
295 def test_func_code(): |
|
296 a = b = 24 |
|
297 def f(): pass |
|
298 def g(): print 12 |
|
299 def f1(): print a |
|
300 def g1(): print b |
|
301 def f2(): print a, b |
|
302 verify(type(f.func_code) is types.CodeType) |
|
303 f.func_code = g.func_code |
|
304 cantset(f, "func_code", None) |
|
305 # can't change the number of free vars |
|
306 cantset(f, "func_code", f1.func_code, exception=ValueError) |
|
307 cantset(f1, "func_code", f.func_code, exception=ValueError) |
|
308 cantset(f1, "func_code", f2.func_code, exception=ValueError) |
|
309 f1.func_code = g1.func_code |
|
310 |
|
311 def 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 |
|
328 def 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 verify(not hasattr(f, "hello")) |
|
339 f.__dict__ = {'world': 'hello'} |
|
340 verify(f.world == "hello") |
|
341 verify(f.__dict__ is f.func_dict == {'world': 'hello'}) |
|
342 cantset(f, "func_dict", None) |
|
343 cantset(f, "__dict__", None) |
|
344 |
|
345 def test_im_class(): |
|
346 class C: |
|
347 def foo(self): pass |
|
348 verify(C.foo.im_class is C) |
|
349 verify(C().foo.im_class is C) |
|
350 cantset(C.foo, "im_class", C) |
|
351 cantset(C().foo, "im_class", C) |
|
352 |
|
353 def test_im_func(): |
|
354 def foo(self): pass |
|
355 class C: |
|
356 pass |
|
357 C.foo = foo |
|
358 verify(C.foo.im_func is foo) |
|
359 verify(C().foo.im_func is foo) |
|
360 cantset(C.foo, "im_func", foo) |
|
361 cantset(C().foo, "im_func", foo) |
|
362 |
|
363 def test_im_self(): |
|
364 class C: |
|
365 def foo(self): pass |
|
366 verify(C.foo.im_self is None) |
|
367 c = C() |
|
368 verify(c.foo.im_self is c) |
|
369 cantset(C.foo, "im_self", None) |
|
370 cantset(c.foo, "im_self", c) |
|
371 |
|
372 def test_im_dict(): |
|
373 class C: |
|
374 def foo(self): pass |
|
375 foo.bar = 42 |
|
376 verify(C.foo.__dict__ == {'bar': 42}) |
|
377 verify(C().foo.__dict__ == {'bar': 42}) |
|
378 cantset(C.foo, "__dict__", C.foo.__dict__) |
|
379 cantset(C().foo, "__dict__", C.foo.__dict__) |
|
380 |
|
381 def test_im_doc(): |
|
382 class C: |
|
383 def foo(self): "hello" |
|
384 verify(C.foo.__doc__ == "hello") |
|
385 verify(C().foo.__doc__ == "hello") |
|
386 cantset(C.foo, "__doc__", "hello") |
|
387 cantset(C().foo, "__doc__", "hello") |
|
388 |
|
389 def test_im_name(): |
|
390 class C: |
|
391 def foo(self): pass |
|
392 verify(C.foo.__name__ == "foo") |
|
393 verify(C().foo.__name__ == "foo") |
|
394 cantset(C.foo, "__name__", "foo") |
|
395 cantset(C().foo, "__name__", "foo") |
|
396 |
|
397 def testmore(): |
|
398 test_func_closure() |
|
399 test_empty_cell() |
|
400 test_func_doc() |
|
401 test_func_globals() |
|
402 test_func_name() |
|
403 test_func_code() |
|
404 test_func_defaults() |
|
405 test_func_dict() |
|
406 # Tests for instance method attributes |
|
407 test_im_class() |
|
408 test_im_func() |
|
409 test_im_self() |
|
410 test_im_dict() |
|
411 test_im_doc() |
|
412 test_im_name() |
|
413 |
|
414 testmore() |