Home | History | Annotate | Download | only in test
      1 """This module includes tests of the code object representation.
      2 
      3 >>> def f(x):
      4 ...     def g(y):
      5 ...         return x + y
      6 ...     return g
      7 ...
      8 
      9 >>> dump(f.__code__)
     10 name: f
     11 argcount: 1
     12 kwonlyargcount: 0
     13 names: ()
     14 varnames: ('x', 'g')
     15 cellvars: ('x',)
     16 freevars: ()
     17 nlocals: 2
     18 flags: 3
     19 consts: ('None', '<code object g>', "'f.<locals>.g'")
     20 
     21 >>> dump(f(4).__code__)
     22 name: g
     23 argcount: 1
     24 kwonlyargcount: 0
     25 names: ()
     26 varnames: ('y',)
     27 cellvars: ()
     28 freevars: ('x',)
     29 nlocals: 1
     30 flags: 19
     31 consts: ('None',)
     32 
     33 >>> def h(x, y):
     34 ...     a = x + y
     35 ...     b = x - y
     36 ...     c = a * b
     37 ...     return c
     38 ...
     39 
     40 >>> dump(h.__code__)
     41 name: h
     42 argcount: 2
     43 kwonlyargcount: 0
     44 names: ()
     45 varnames: ('x', 'y', 'a', 'b', 'c')
     46 cellvars: ()
     47 freevars: ()
     48 nlocals: 5
     49 flags: 67
     50 consts: ('None',)
     51 
     52 >>> def attrs(obj):
     53 ...     print(obj.attr1)
     54 ...     print(obj.attr2)
     55 ...     print(obj.attr3)
     56 
     57 >>> dump(attrs.__code__)
     58 name: attrs
     59 argcount: 1
     60 kwonlyargcount: 0
     61 names: ('print', 'attr1', 'attr2', 'attr3')
     62 varnames: ('obj',)
     63 cellvars: ()
     64 freevars: ()
     65 nlocals: 1
     66 flags: 67
     67 consts: ('None',)
     68 
     69 >>> def optimize_away():
     70 ...     'doc string'
     71 ...     'not a docstring'
     72 ...     53
     73 ...     0x53
     74 
     75 >>> dump(optimize_away.__code__)
     76 name: optimize_away
     77 argcount: 0
     78 kwonlyargcount: 0
     79 names: ()
     80 varnames: ()
     81 cellvars: ()
     82 freevars: ()
     83 nlocals: 0
     84 flags: 67
     85 consts: ("'doc string'", 'None')
     86 
     87 >>> def keywordonly_args(a,b,*,k1):
     88 ...     return a,b,k1
     89 ...
     90 
     91 >>> dump(keywordonly_args.__code__)
     92 name: keywordonly_args
     93 argcount: 2
     94 kwonlyargcount: 1
     95 names: ()
     96 varnames: ('a', 'b', 'k1')
     97 cellvars: ()
     98 freevars: ()
     99 nlocals: 3
    100 flags: 67
    101 consts: ('None',)
    102 
    103 """
    104 
    105 import sys
    106 import unittest
    107 import weakref
    108 from test.support import run_doctest, run_unittest, cpython_only
    109 
    110 
    111 def consts(t):
    112     """Yield a doctest-safe sequence of object reprs."""
    113     for elt in t:
    114         r = repr(elt)
    115         if r.startswith("<code object"):
    116             yield "<code object %s>" % elt.co_name
    117         else:
    118             yield r
    119 
    120 def dump(co):
    121     """Print out a text representation of a code object."""
    122     for attr in ["name", "argcount", "kwonlyargcount", "names", "varnames",
    123                  "cellvars", "freevars", "nlocals", "flags"]:
    124         print("%s: %s" % (attr, getattr(co, "co_" + attr)))
    125     print("consts:", tuple(consts(co.co_consts)))
    126 
    127 
    128 class CodeTest(unittest.TestCase):
    129 
    130     @cpython_only
    131     def test_newempty(self):
    132         import _testcapi
    133         co = _testcapi.code_newempty("filename", "funcname", 15)
    134         self.assertEqual(co.co_filename, "filename")
    135         self.assertEqual(co.co_name, "funcname")
    136         self.assertEqual(co.co_firstlineno, 15)
    137 
    138 
    139 def isinterned(s):
    140     return s is sys.intern(('_' + s + '_')[1:-1])
    141 
    142 class CodeConstsTest(unittest.TestCase):
    143 
    144     def find_const(self, consts, value):
    145         for v in consts:
    146             if v == value:
    147                 return v
    148         self.assertIn(value, consts)  # raises an exception
    149         self.fail('Should never be reached')
    150 
    151     def assertIsInterned(self, s):
    152         if not isinterned(s):
    153             self.fail('String %r is not interned' % (s,))
    154 
    155     def assertIsNotInterned(self, s):
    156         if isinterned(s):
    157             self.fail('String %r is interned' % (s,))
    158 
    159     @cpython_only
    160     def test_interned_string(self):
    161         co = compile('res = "str_value"', '?', 'exec')
    162         v = self.find_const(co.co_consts, 'str_value')
    163         self.assertIsInterned(v)
    164 
    165     @cpython_only
    166     def test_interned_string_in_tuple(self):
    167         co = compile('res = ("str_value",)', '?', 'exec')
    168         v = self.find_const(co.co_consts, ('str_value',))
    169         self.assertIsInterned(v[0])
    170 
    171     @cpython_only
    172     def test_interned_string_in_frozenset(self):
    173         co = compile('res = a in {"str_value"}', '?', 'exec')
    174         v = self.find_const(co.co_consts, frozenset(('str_value',)))
    175         self.assertIsInterned(tuple(v)[0])
    176 
    177     @cpython_only
    178     def test_interned_string_default(self):
    179         def f(a='str_value'):
    180             return a
    181         self.assertIsInterned(f())
    182 
    183     @cpython_only
    184     def test_interned_string_with_null(self):
    185         co = compile(r'res = "str\0value!"', '?', 'exec')
    186         v = self.find_const(co.co_consts, 'str\0value!')
    187         self.assertIsNotInterned(v)
    188 
    189 
    190 class CodeWeakRefTest(unittest.TestCase):
    191 
    192     def test_basic(self):
    193         # Create a code object in a clean environment so that we know we have
    194         # the only reference to it left.
    195         namespace = {}
    196         exec("def f(): pass", globals(), namespace)
    197         f = namespace["f"]
    198         del namespace
    199 
    200         self.called = False
    201         def callback(code):
    202             self.called = True
    203 
    204         # f is now the last reference to the function, and through it, the code
    205         # object.  While we hold it, check that we can create a weakref and
    206         # deref it.  Then delete it, and check that the callback gets called and
    207         # the reference dies.
    208         coderef = weakref.ref(f.__code__, callback)
    209         self.assertTrue(bool(coderef()))
    210         del f
    211         self.assertFalse(bool(coderef()))
    212         self.assertTrue(self.called)
    213 
    214 
    215 def test_main(verbose=None):
    216     from test import test_code
    217     run_doctest(test_code, verbose)
    218     run_unittest(CodeTest, CodeConstsTest, CodeWeakRefTest)
    219 
    220 
    221 if __name__ == "__main__":
    222     test_main()
    223