blob: f4ee329e75e1d6fe0c6f4987cb55064fea3b714f [file] [log] [blame]
Guido van Rossumd9d1d4a2001-09-17 23:46:56 +00001from test_support import verbose, TestFailed, verify
2import types
Barry Warsaw4a420a02001-01-15 20:30:15 +00003
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
Barry Warsaw033daa42001-08-14 18:28:28 +000015except AttributeError: pass
16else: raise TestFailed, 'expected AttributeError'
Barry Warsaw4a420a02001-01-15 20:30:15 +000017
Barry Warsaw033daa42001-08-14 18:28:28 +000018if b.__dict__ <> {}:
19 raise TestFailed, 'expected unassigned func.__dict__ to be {}'
Barry Warsawc1e100f2001-02-26 18:07:26 +000020
Barry Warsaw4a420a02001-01-15 20:30:15 +000021b.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
Barry Warsaw033daa42001-08-14 18:28:28 +000033try:
34 del b.__dict__
35except TypeError: pass
36else: raise TestFailed, 'del func.__dict__ expected TypeError'
Barry Warsawc1e100f2001-02-26 18:07:26 +000037
38b.publish = 1
Barry Warsaw033daa42001-08-14 18:28:28 +000039try:
40 b.__dict__ = None
41except TypeError: pass
42else: raise TestFailed, 'func.__dict__ = None expected TypeError'
Barry Warsawc1e100f2001-02-26 18:07:26 +000043
Barry Warsaw033daa42001-08-14 18:28:28 +000044d = {'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'
Barry Warsawc1e100f2001-02-26 18:07:26 +000050
Barry Warsaw4a420a02001-01-15 20:30:15 +000051f1 = F()
52f2 = F()
53
54try:
55 F.a.publish
Barry Warsaw033daa42001-08-14 18:28:28 +000056except AttributeError: pass
57else: raise TestFailed, 'expected AttributeError'
Barry Warsaw4a420a02001-01-15 20:30:15 +000058
59try:
60 f1.a.publish
Barry Warsaw033daa42001-08-14 18:28:28 +000061except AttributeError: pass
62else: raise TestFailed, 'expected AttributeError'
Barry Warsaw4a420a02001-01-15 20:30:15 +000063
Barry Warsawc1e100f2001-02-26 18:07:26 +000064# 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
Barry Warsaw033daa42001-08-14 18:28:28 +000068except TypeError: pass
69else: raise TestFailed, 'expected TypeError'
Barry Warsaw4a420a02001-01-15 20:30:15 +000070
Barry Warsawc1e100f2001-02-26 18:07:26 +000071# But setting it explicitly on the underlying function object is okay.
72F.a.im_func.publish = 1
73
Barry Warsaw4a420a02001-01-15 20:30:15 +000074if 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
Barry Warsaw033daa42001-08-14 18:28:28 +000088except TypeError: pass
89else: raise TestFailed, 'expected TypeError'
Barry Warsaw4a420a02001-01-15 20:30:15 +000090
Barry Warsawc1e100f2001-02-26 18:07:26 +000091# See the comment above about the change in semantics for Python 2.1b1
92try:
93 F.a.myclass = F
Barry Warsaw033daa42001-08-14 18:28:28 +000094except TypeError: pass
95else: raise TestFailed, 'expected TypeError'
Barry Warsawc1e100f2001-02-26 18:07:26 +000096
97F.a.im_func.myclass = F
98
Barry Warsaw4a420a02001-01-15 20:30:15 +000099f1.a.myclass
100f2.a.myclass
101f1.a.myclass
102F.a.myclass
103
104if f1.a.myclass is not f2.a.myclass or \
Barry Warsaw033daa42001-08-14 18:28:28 +0000105 f1.a.myclass is not F.a.myclass:
Barry Warsaw4a420a02001-01-15 20:30:15 +0000106 raise TestFailed, 'attributes were not the same'
107
108# try setting __dict__
109try:
110 F.a.__dict__ = (1, 2, 3)
Barry Warsaw033daa42001-08-14 18:28:28 +0000111except TypeError: pass
112else: raise TestFailed, 'expected TypeError'
Barry Warsaw4a420a02001-01-15 20:30:15 +0000113
Barry Warsawc1e100f2001-02-26 18:07:26 +0000114F.a.im_func.__dict__ = {'one': 11, 'two': 22, 'three': 33}
115
Barry Warsaw4a420a02001-01-15 20:30:15 +0000116if 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
Barry Warsaw033daa42001-08-14 18:28:28 +0000124except TypeError: pass
125else: raise TestFailed
Barry Warsaw4a420a02001-01-15 20:30:15 +0000126
127if f2.a.one <> f1.a.one <> F.a.one <> 11:
128 raise TestFailed
Barry Warsaw534c60f2001-01-15 21:00:02 +0000129
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
Barry Warsaw2e9b3962001-01-19 19:55:12 +0000167
168# Regression test for a crash in pre-2.1a1
169def another():
170 pass
Barry Warsaw033daa42001-08-14 18:28:28 +0000171
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
Barry Warsaw2e9b3962001-01-19 19:55:12 +0000186
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
Moshe Zadka497671e2001-01-29 06:21:17 +0000195
196def foo():
Tim Peters10fb3862001-02-09 20:17:14 +0000197 pass
Moshe Zadka497671e2001-01-29 06:21:17 +0000198
199def bar():
Tim Peters10fb3862001-02-09 20:17:14 +0000200 pass
Moshe Zadka497671e2001-01-29 06:21:17 +0000201
202def temp():
Tim Peters10fb3862001-02-09 20:17:14 +0000203 print 1
Moshe Zadka497671e2001-01-29 06:21:17 +0000204
Barry Warsaw033daa42001-08-14 18:28:28 +0000205if foo==bar:
206 raise TestFailed
Moshe Zadka497671e2001-01-29 06:21:17 +0000207
208d={}
209d[foo] = 1
210
211foo.func_code = temp.func_code
212
213d[foo]
Guido van Rossumd9d1d4a2001-09-17 23:46:56 +0000214
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()