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