• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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___name__(self):
97        self.assertEqual(self.b.__name__, 'b')
98        self.b.__name__ = 'c'
99        self.assertEqual(self.b.__name__, 'c')
100        self.b.__name__ = 'd'
101        self.assertEqual(self.b.__name__, 'd')
102        # __name__ and __name__ must be a string
103        self.cannot_set_attr(self.b, '__name__', 7, TypeError)
104        # __name__ must be available when in restricted mode. Exec will raise
105        # AttributeError if __name__ is not available on f.
106        s = """def f(): pass\nf.__name__"""
107        exec(s, {'__builtins__': {}})
108        # Test on methods, too
109        self.assertEqual(self.fi.a.__name__, 'a')
110        self.cannot_set_attr(self.fi.a, "__name__", 'a', AttributeError)
111
112    def test___qualname__(self):
113        # PEP 3155
114        self.assertEqual(self.b.__qualname__, 'FuncAttrsTest.setUp.<locals>.b')
115        self.assertEqual(FuncAttrsTest.setUp.__qualname__, 'FuncAttrsTest.setUp')
116        self.assertEqual(global_function.__qualname__, 'global_function')
117        self.assertEqual(global_function().__qualname__,
118                         'global_function.<locals>.<lambda>')
119        self.assertEqual(global_function()().__qualname__,
120                         'global_function.<locals>.inner_function')
121        self.assertEqual(global_function()()().__qualname__,
122                         'global_function.<locals>.inner_function.<locals>.LocalClass')
123        self.assertEqual(inner_global_function.__qualname__, 'inner_global_function')
124        self.assertEqual(inner_global_function().__qualname__, 'inner_global_function.<locals>.inner_function2')
125        self.b.__qualname__ = 'c'
126        self.assertEqual(self.b.__qualname__, 'c')
127        self.b.__qualname__ = 'd'
128        self.assertEqual(self.b.__qualname__, 'd')
129        # __qualname__ must be a string
130        self.cannot_set_attr(self.b, '__qualname__', 7, TypeError)
131
132    def test___code__(self):
133        num_one, num_two = 7, 8
134        def a(): pass
135        def b(): return 12
136        def c(): return num_one
137        def d(): return num_two
138        def e(): return num_one, num_two
139        for func in [a, b, c, d, e]:
140            self.assertEqual(type(func.__code__), types.CodeType)
141        self.assertEqual(c(), 7)
142        self.assertEqual(d(), 8)
143        d.__code__ = c.__code__
144        self.assertEqual(c.__code__, d.__code__)
145        self.assertEqual(c(), 7)
146        # self.assertEqual(d(), 7)
147        try:
148            b.__code__ = c.__code__
149        except ValueError:
150            pass
151        else:
152            self.fail("__code__ with different numbers of free vars should "
153                      "not be possible")
154        try:
155            e.__code__ = d.__code__
156        except ValueError:
157            pass
158        else:
159            self.fail("__code__ with different numbers of free vars should "
160                      "not be possible")
161
162    def test_blank_func_defaults(self):
163        self.assertEqual(self.b.__defaults__, None)
164        del self.b.__defaults__
165        self.assertEqual(self.b.__defaults__, None)
166
167    def test_func_default_args(self):
168        def first_func(a, b):
169            return a+b
170        def second_func(a=1, b=2):
171            return a+b
172        self.assertEqual(first_func.__defaults__, None)
173        self.assertEqual(second_func.__defaults__, (1, 2))
174        first_func.__defaults__ = (1, 2)
175        self.assertEqual(first_func.__defaults__, (1, 2))
176        self.assertEqual(first_func(), 3)
177        self.assertEqual(first_func(3), 5)
178        self.assertEqual(first_func(3, 5), 8)
179        del second_func.__defaults__
180        self.assertEqual(second_func.__defaults__, None)
181        try:
182            second_func()
183        except TypeError:
184            pass
185        else:
186            self.fail("__defaults__ does not update; deleting it does not "
187                      "remove requirement")
188
189
190class InstancemethodAttrTest(FuncAttrsTest):
191
192    def test___class__(self):
193        self.assertEqual(self.fi.a.__self__.__class__, self.F)
194        self.cannot_set_attr(self.fi.a, "__class__", self.F, TypeError)
195
196    def test___func__(self):
197        self.assertEqual(self.fi.a.__func__, self.F.a)
198        self.cannot_set_attr(self.fi.a, "__func__", self.F.a, AttributeError)
199
200    def test___self__(self):
201        self.assertEqual(self.fi.a.__self__, self.fi)
202        self.cannot_set_attr(self.fi.a, "__self__", self.fi, AttributeError)
203
204    def test___func___non_method(self):
205        # Behavior should be the same when a method is added via an attr
206        # assignment
207        self.fi.id = types.MethodType(id, self.fi)
208        self.assertEqual(self.fi.id(), id(self.fi))
209        # Test usage
210        try:
211            self.fi.id.unknown_attr
212        except AttributeError:
213            pass
214        else:
215            self.fail("using unknown attributes should raise AttributeError")
216        # Test assignment and deletion
217        self.cannot_set_attr(self.fi.id, 'unknown_attr', 2, AttributeError)
218
219
220class ArbitraryFunctionAttrTest(FuncAttrsTest):
221    def test_set_attr(self):
222        self.b.known_attr = 7
223        self.assertEqual(self.b.known_attr, 7)
224        try:
225            self.fi.a.known_attr = 7
226        except AttributeError:
227            pass
228        else:
229            self.fail("setting attributes on methods should raise error")
230
231    def test_delete_unknown_attr(self):
232        try:
233            del self.b.unknown_attr
234        except AttributeError:
235            pass
236        else:
237            self.fail("deleting unknown attribute should raise TypeError")
238
239    def test_unset_attr(self):
240        for func in [self.b, self.fi.a]:
241            try:
242                func.non_existent_attr
243            except AttributeError:
244                pass
245            else:
246                self.fail("using unknown attributes should raise "
247                          "AttributeError")
248
249
250class FunctionDictsTest(FuncAttrsTest):
251    def test_setting_dict_to_invalid(self):
252        self.cannot_set_attr(self.b, '__dict__', None, TypeError)
253        from collections import UserDict
254        d = UserDict({'known_attr': 7})
255        self.cannot_set_attr(self.fi.a.__func__, '__dict__', d, TypeError)
256
257    def test_setting_dict_to_valid(self):
258        d = {'known_attr': 7}
259        self.b.__dict__ = d
260        # Test assignment
261        self.assertIs(d, self.b.__dict__)
262        # ... and on all the different ways of referencing the method's func
263        self.F.a.__dict__ = d
264        self.assertIs(d, self.fi.a.__func__.__dict__)
265        self.assertIs(d, self.fi.a.__dict__)
266        # Test value
267        self.assertEqual(self.b.known_attr, 7)
268        self.assertEqual(self.b.__dict__['known_attr'], 7)
269        # ... and again, on all the different method's names
270        self.assertEqual(self.fi.a.__func__.known_attr, 7)
271        self.assertEqual(self.fi.a.known_attr, 7)
272
273    def test_delete___dict__(self):
274        try:
275            del self.b.__dict__
276        except TypeError:
277            pass
278        else:
279            self.fail("deleting function dictionary should raise TypeError")
280
281    def test_unassigned_dict(self):
282        self.assertEqual(self.b.__dict__, {})
283
284    def test_func_as_dict_key(self):
285        value = "Some string"
286        d = {}
287        d[self.b] = value
288        self.assertEqual(d[self.b], value)
289
290
291class FunctionDocstringTest(FuncAttrsTest):
292    def test_set_docstring_attr(self):
293        self.assertEqual(self.b.__doc__, None)
294        docstr = "A test method that does nothing"
295        self.b.__doc__ = docstr
296        self.F.a.__doc__ = docstr
297        self.assertEqual(self.b.__doc__, docstr)
298        self.assertEqual(self.fi.a.__doc__, docstr)
299        self.cannot_set_attr(self.fi.a, "__doc__", docstr, AttributeError)
300
301    def test_delete_docstring(self):
302        self.b.__doc__ = "The docstring"
303        del self.b.__doc__
304        self.assertEqual(self.b.__doc__, None)
305
306
307def cell(value):
308    """Create a cell containing the given value."""
309    def f():
310        print(a)
311    a = value
312    return f.__closure__[0]
313
314def empty_cell(empty=True):
315    """Create an empty cell."""
316    def f():
317        print(a)
318    # the intent of the following line is simply "if False:";  it's
319    # spelt this way to avoid the danger that a future optimization
320    # might simply remove an "if False:" code block.
321    if not empty:
322        a = 1729
323    return f.__closure__[0]
324
325
326class CellTest(unittest.TestCase):
327    def test_comparison(self):
328        # These tests are here simply to exercise the comparison code;
329        # their presence should not be interpreted as providing any
330        # guarantees about the semantics (or even existence) of cell
331        # comparisons in future versions of CPython.
332        self.assertTrue(cell(2) < cell(3))
333        self.assertTrue(empty_cell() < cell('saturday'))
334        self.assertTrue(empty_cell() == empty_cell())
335        self.assertTrue(cell(-36) == cell(-36.0))
336        self.assertTrue(cell(True) > empty_cell())
337
338
339class StaticMethodAttrsTest(unittest.TestCase):
340    def test_func_attribute(self):
341        def f():
342            pass
343
344        c = classmethod(f)
345        self.assertTrue(c.__func__ is f)
346
347        s = staticmethod(f)
348        self.assertTrue(s.__func__ is f)
349
350
351class BuiltinFunctionPropertiesTest(unittest.TestCase):
352    # XXX Not sure where this should really go since I can't find a
353    # test module specifically for builtin_function_or_method.
354
355    def test_builtin__qualname__(self):
356        import time
357
358        # builtin function:
359        self.assertEqual(len.__qualname__, 'len')
360        self.assertEqual(time.time.__qualname__, 'time')
361
362        # builtin classmethod:
363        self.assertEqual(dict.fromkeys.__qualname__, 'dict.fromkeys')
364        self.assertEqual(float.__getformat__.__qualname__,
365                         'float.__getformat__')
366
367        # builtin staticmethod:
368        self.assertEqual(str.maketrans.__qualname__, 'str.maketrans')
369        self.assertEqual(bytes.maketrans.__qualname__, 'bytes.maketrans')
370
371        # builtin bound instance method:
372        self.assertEqual([1, 2, 3].append.__qualname__, 'list.append')
373        self.assertEqual({'foo': 'bar'}.pop.__qualname__, 'dict.pop')
374
375
376if __name__ == "__main__":
377    unittest.main()
378