blob: 0d80af44d9f1ffb6b8af1bed54b1c797b4ca919d [file] [log] [blame]
Jeremy Hylton3e0055f2005-10-20 19:59:25 +00001"""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
Neal Norwitz221085d2007-02-25 20:55:47 +00009>>> dump(f.__code__)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000010name: f
11argcount: 1
Pablo Galindo8c77b8c2019-04-29 13:36:57 +010012posonlyargcount: 0
Guido van Rossum4f72a782006-10-27 23:31:49 +000013kwonlyargcount: 0
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000014names: ()
15varnames: ('x', 'g')
16cellvars: ('x',)
17freevars: ()
18nlocals: 2
19flags: 3
Antoine Pitrou86a36b52011-11-25 18:56:07 +010020consts: ('None', '<code object g>', "'f.<locals>.g'")
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000021
Neal Norwitz221085d2007-02-25 20:55:47 +000022>>> dump(f(4).__code__)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000023name: g
24argcount: 1
Pablo Galindo8c77b8c2019-04-29 13:36:57 +010025posonlyargcount: 0
Guido van Rossum4f72a782006-10-27 23:31:49 +000026kwonlyargcount: 0
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000027names: ()
28varnames: ('y',)
29cellvars: ()
30freevars: ('x',)
31nlocals: 1
32flags: 19
33consts: ('None',)
34
35>>> def h(x, y):
36... a = x + y
37... b = x - y
38... c = a * b
39... return c
Tim Peters536cf992005-12-25 23:18:31 +000040...
Guido van Rossum4f72a782006-10-27 23:31:49 +000041
Neal Norwitz221085d2007-02-25 20:55:47 +000042>>> dump(h.__code__)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000043name: h
44argcount: 2
Pablo Galindo8c77b8c2019-04-29 13:36:57 +010045posonlyargcount: 0
Guido van Rossum4f72a782006-10-27 23:31:49 +000046kwonlyargcount: 0
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000047names: ()
48varnames: ('x', 'y', 'a', 'b', 'c')
49cellvars: ()
50freevars: ()
51nlocals: 5
52flags: 67
53consts: ('None',)
54
55>>> def attrs(obj):
Guido van Rossum7131f842007-02-09 20:13:25 +000056... print(obj.attr1)
57... print(obj.attr2)
58... print(obj.attr3)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000059
Neal Norwitz221085d2007-02-25 20:55:47 +000060>>> dump(attrs.__code__)
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000061name: attrs
62argcount: 1
Pablo Galindo8c77b8c2019-04-29 13:36:57 +010063posonlyargcount: 0
Guido van Rossum4f72a782006-10-27 23:31:49 +000064kwonlyargcount: 0
Georg Brandl88fc6642007-02-09 21:28:07 +000065names: ('print', 'attr1', 'attr2', 'attr3')
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000066varnames: ('obj',)
67cellvars: ()
68freevars: ()
69nlocals: 1
70flags: 67
71consts: ('None',)
72
Thomas Wouters0e3f5912006-08-11 14:57:12 +000073>>> def optimize_away():
74... 'doc string'
75... 'not a docstring'
76... 53
Guido van Rossume2a383d2007-01-15 16:59:06 +000077... 0x53
Thomas Wouters0e3f5912006-08-11 14:57:12 +000078
Neal Norwitz221085d2007-02-25 20:55:47 +000079>>> dump(optimize_away.__code__)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000080name: optimize_away
81argcount: 0
Pablo Galindo8c77b8c2019-04-29 13:36:57 +010082posonlyargcount: 0
Guido van Rossum4f72a782006-10-27 23:31:49 +000083kwonlyargcount: 0
Thomas Wouters0e3f5912006-08-11 14:57:12 +000084names: ()
85varnames: ()
86cellvars: ()
87freevars: ()
88nlocals: 0
89flags: 67
90consts: ("'doc string'", 'None')
91
Guido van Rossum4f72a782006-10-27 23:31:49 +000092>>> def keywordonly_args(a,b,*,k1):
93... return a,b,k1
94...
95
Neal Norwitz221085d2007-02-25 20:55:47 +000096>>> dump(keywordonly_args.__code__)
Guido van Rossum4f72a782006-10-27 23:31:49 +000097name: keywordonly_args
98argcount: 2
Pablo Galindo8c77b8c2019-04-29 13:36:57 +010099posonlyargcount: 0
Guido van Rossum4f72a782006-10-27 23:31:49 +0000100kwonlyargcount: 1
101names: ()
102varnames: ('a', 'b', 'k1')
103cellvars: ()
104freevars: ()
105nlocals: 3
106flags: 67
107consts: ('None',)
108
Pablo Galindo8c77b8c2019-04-29 13:36:57 +0100109>>> def posonly_args(a,b,/,c):
110... return a,b,c
111...
112
113>>> dump(posonly_args.__code__)
114name: posonly_args
Pablo Galindocd74e662019-06-01 18:08:04 +0100115argcount: 3
Pablo Galindo8c77b8c2019-04-29 13:36:57 +0100116posonlyargcount: 2
117kwonlyargcount: 0
118names: ()
119varnames: ('a', 'b', 'c')
120cellvars: ()
121freevars: ()
122nlocals: 3
123flags: 67
124consts: ('None',)
125
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000126"""
127
Nick Coghlan078f1812017-12-03 11:12:20 +1000128import inspect
Serhiy Storchaka00a0fc12016-09-30 10:07:26 +0300129import sys
Dino Viehlandf3cffd22017-06-21 14:44:36 -0700130import threading
Alexandre Vassalotti7b82b402009-07-21 04:30:03 +0000131import unittest
Collin Winter4222e9c2010-03-18 22:46:40 +0000132import weakref
Pablo Galindof00828a2019-05-09 16:52:02 +0100133import opcode
Victor Stinnera4b091e2017-06-23 15:08:55 +0200134try:
135 import ctypes
136except ImportError:
137 ctypes = None
Dino Viehlandf3cffd22017-06-21 14:44:36 -0700138from test.support import (run_doctest, run_unittest, cpython_only,
139 check_impl_detail)
Alexandre Vassalotti7b82b402009-07-21 04:30:03 +0000140
Collin Winter4222e9c2010-03-18 22:46:40 +0000141
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000142def consts(t):
143 """Yield a doctest-safe sequence of object reprs."""
144 for elt in t:
145 r = repr(elt)
146 if r.startswith("<code object"):
147 yield "<code object %s>" % elt.co_name
148 else:
149 yield r
150
151def dump(co):
152 """Print out a text representation of a code object."""
Pablo Galindo8c77b8c2019-04-29 13:36:57 +0100153 for attr in ["name", "argcount", "posonlyargcount",
154 "kwonlyargcount", "names", "varnames",
Guido van Rossum4f72a782006-10-27 23:31:49 +0000155 "cellvars", "freevars", "nlocals", "flags"]:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000156 print("%s: %s" % (attr, getattr(co, "co_" + attr)))
157 print("consts:", tuple(consts(co.co_consts)))
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000158
Nick Coghlan078f1812017-12-03 11:12:20 +1000159# Needed for test_closure_injection below
160# Defined at global scope to avoid implicitly closing over __class__
161def external_getitem(self, i):
162 return f"Foreign getitem: {super().__getitem__(i)}"
Alexandre Vassalotti7b82b402009-07-21 04:30:03 +0000163
164class CodeTest(unittest.TestCase):
165
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200166 @cpython_only
Alexandre Vassalotti7b82b402009-07-21 04:30:03 +0000167 def test_newempty(self):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200168 import _testcapi
Alexandre Vassalotti7b82b402009-07-21 04:30:03 +0000169 co = _testcapi.code_newempty("filename", "funcname", 15)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000170 self.assertEqual(co.co_filename, "filename")
171 self.assertEqual(co.co_name, "funcname")
172 self.assertEqual(co.co_firstlineno, 15)
Alexandre Vassalotti7b82b402009-07-21 04:30:03 +0000173
Nick Coghlan078f1812017-12-03 11:12:20 +1000174 @cpython_only
175 def test_closure_injection(self):
176 # From https://bugs.python.org/issue32176
Victor Stinnera9f05d62019-05-24 23:57:23 +0200177 from types import FunctionType
Nick Coghlan078f1812017-12-03 11:12:20 +1000178
179 def create_closure(__class__):
180 return (lambda: __class__).__closure__
181
182 def new_code(c):
183 '''A new code object with a __class__ cell added to freevars'''
Victor Stinnera9f05d62019-05-24 23:57:23 +0200184 return c.replace(co_freevars=c.co_freevars + ('__class__',))
Nick Coghlan078f1812017-12-03 11:12:20 +1000185
186 def add_foreign_method(cls, name, f):
187 code = new_code(f.__code__)
188 assert not f.__closure__
189 closure = create_closure(cls)
190 defaults = f.__defaults__
191 setattr(cls, name, FunctionType(code, globals(), name, defaults, closure))
192
193 class List(list):
194 pass
195
196 add_foreign_method(List, "__getitem__", external_getitem)
197
198 # Ensure the closure injection actually worked
199 function = List.__getitem__
200 class_ref = function.__closure__[0].cell_contents
201 self.assertIs(class_ref, List)
202
203 # Ensure the code correctly indicates it accesses a free variable
204 self.assertFalse(function.__code__.co_flags & inspect.CO_NOFREE,
205 hex(function.__code__.co_flags))
206
207 # Ensure the zero-arg super() call in the injected method works
208 obj = List([1, 2, 3])
209 self.assertEqual(obj[0], "Foreign getitem: 1")
Serhiy Storchaka09f3d082016-10-04 18:17:22 +0300210
Victor Stinnera9f05d62019-05-24 23:57:23 +0200211 def test_constructor(self):
212 def func(): pass
213 co = func.__code__
214 CodeType = type(co)
215
216 # test code constructor
217 return CodeType(co.co_argcount,
218 co.co_posonlyargcount,
219 co.co_kwonlyargcount,
220 co.co_nlocals,
221 co.co_stacksize,
222 co.co_flags,
223 co.co_code,
224 co.co_consts,
225 co.co_names,
226 co.co_varnames,
227 co.co_filename,
228 co.co_name,
229 co.co_firstlineno,
230 co.co_lnotab,
231 co.co_freevars,
232 co.co_cellvars)
233
234 def test_replace(self):
235 def func():
236 x = 1
237 return x
238 code = func.__code__
239
240 # different co_name, co_varnames, co_consts
241 def func2():
242 y = 2
243 return y
244 code2 = func.__code__
245
246 for attr, value in (
247 ("co_argcount", 0),
248 ("co_posonlyargcount", 0),
249 ("co_kwonlyargcount", 0),
250 ("co_nlocals", 0),
251 ("co_stacksize", 0),
252 ("co_flags", code.co_flags | inspect.CO_COROUTINE),
253 ("co_firstlineno", 100),
254 ("co_code", code2.co_code),
255 ("co_consts", code2.co_consts),
256 ("co_names", ("myname",)),
257 ("co_varnames", code2.co_varnames),
258 ("co_freevars", ("freevar",)),
259 ("co_cellvars", ("cellvar",)),
260 ("co_filename", "newfilename"),
261 ("co_name", "newname"),
262 ("co_lnotab", code2.co_lnotab),
263 ):
264 with self.subTest(attr=attr, value=value):
265 new_code = code.replace(**{attr: value})
266 self.assertEqual(getattr(new_code, attr), value)
267
268
Serhiy Storchaka09f3d082016-10-04 18:17:22 +0300269def isinterned(s):
270 return s is sys.intern(('_' + s + '_')[1:-1])
271
Serhiy Storchaka00a0fc12016-09-30 10:07:26 +0300272class CodeConstsTest(unittest.TestCase):
273
274 def find_const(self, consts, value):
275 for v in consts:
276 if v == value:
277 return v
Serhiy Storchaka09f3d082016-10-04 18:17:22 +0300278 self.assertIn(value, consts) # raises an exception
279 self.fail('Should never be reached')
Serhiy Storchaka00a0fc12016-09-30 10:07:26 +0300280
281 def assertIsInterned(self, s):
Serhiy Storchaka09f3d082016-10-04 18:17:22 +0300282 if not isinterned(s):
Serhiy Storchaka00a0fc12016-09-30 10:07:26 +0300283 self.fail('String %r is not interned' % (s,))
284
Serhiy Storchaka09f3d082016-10-04 18:17:22 +0300285 def assertIsNotInterned(self, s):
286 if isinterned(s):
287 self.fail('String %r is interned' % (s,))
288
Serhiy Storchaka00a0fc12016-09-30 10:07:26 +0300289 @cpython_only
290 def test_interned_string(self):
291 co = compile('res = "str_value"', '?', 'exec')
292 v = self.find_const(co.co_consts, 'str_value')
293 self.assertIsInterned(v)
294
295 @cpython_only
296 def test_interned_string_in_tuple(self):
297 co = compile('res = ("str_value",)', '?', 'exec')
298 v = self.find_const(co.co_consts, ('str_value',))
299 self.assertIsInterned(v[0])
300
301 @cpython_only
302 def test_interned_string_in_frozenset(self):
303 co = compile('res = a in {"str_value"}', '?', 'exec')
304 v = self.find_const(co.co_consts, frozenset(('str_value',)))
305 self.assertIsInterned(tuple(v)[0])
306
307 @cpython_only
308 def test_interned_string_default(self):
309 def f(a='str_value'):
310 return a
311 self.assertIsInterned(f())
312
Serhiy Storchaka09f3d082016-10-04 18:17:22 +0300313 @cpython_only
314 def test_interned_string_with_null(self):
315 co = compile(r'res = "str\0value!"', '?', 'exec')
316 v = self.find_const(co.co_consts, 'str\0value!')
317 self.assertIsNotInterned(v)
318
Alexandre Vassalotti7b82b402009-07-21 04:30:03 +0000319
Collin Winter4222e9c2010-03-18 22:46:40 +0000320class CodeWeakRefTest(unittest.TestCase):
321
322 def test_basic(self):
323 # Create a code object in a clean environment so that we know we have
324 # the only reference to it left.
325 namespace = {}
326 exec("def f(): pass", globals(), namespace)
327 f = namespace["f"]
328 del namespace
329
330 self.called = False
331 def callback(code):
332 self.called = True
333
334 # f is now the last reference to the function, and through it, the code
335 # object. While we hold it, check that we can create a weakref and
336 # deref it. Then delete it, and check that the callback gets called and
337 # the reference dies.
338 coderef = weakref.ref(f.__code__, callback)
339 self.assertTrue(bool(coderef()))
340 del f
341 self.assertFalse(bool(coderef()))
342 self.assertTrue(self.called)
343
344
Victor Stinnera4b091e2017-06-23 15:08:55 +0200345if check_impl_detail(cpython=True) and ctypes is not None:
Dino Viehlandf3cffd22017-06-21 14:44:36 -0700346 py = ctypes.pythonapi
347 freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp)
348
349 RequestCodeExtraIndex = py._PyEval_RequestCodeExtraIndex
350 RequestCodeExtraIndex.argtypes = (freefunc,)
351 RequestCodeExtraIndex.restype = ctypes.c_ssize_t
352
353 SetExtra = py._PyCode_SetExtra
354 SetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, ctypes.c_voidp)
355 SetExtra.restype = ctypes.c_int
356
357 GetExtra = py._PyCode_GetExtra
358 GetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t,
359 ctypes.POINTER(ctypes.c_voidp))
360 GetExtra.restype = ctypes.c_int
361
362 LAST_FREED = None
363 def myfree(ptr):
364 global LAST_FREED
365 LAST_FREED = ptr
366
367 FREE_FUNC = freefunc(myfree)
368 FREE_INDEX = RequestCodeExtraIndex(FREE_FUNC)
369
370 class CoExtra(unittest.TestCase):
371 def get_func(self):
372 # Defining a function causes the containing function to have a
373 # reference to the code object. We need the code objects to go
374 # away, so we eval a lambda.
375 return eval('lambda:42')
376
377 def test_get_non_code(self):
378 f = self.get_func()
379
380 self.assertRaises(SystemError, SetExtra, 42, FREE_INDEX,
381 ctypes.c_voidp(100))
382 self.assertRaises(SystemError, GetExtra, 42, FREE_INDEX,
383 ctypes.c_voidp(100))
384
385 def test_bad_index(self):
386 f = self.get_func()
387 self.assertRaises(SystemError, SetExtra, f.__code__,
388 FREE_INDEX+100, ctypes.c_voidp(100))
389 self.assertEqual(GetExtra(f.__code__, FREE_INDEX+100,
390 ctypes.c_voidp(100)), 0)
391
392 def test_free_called(self):
393 # Verify that the provided free function gets invoked
394 # when the code object is cleaned up.
395 f = self.get_func()
396
397 SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(100))
398 del f
399 self.assertEqual(LAST_FREED, 100)
400
401 def test_get_set(self):
402 # Test basic get/set round tripping.
403 f = self.get_func()
404
405 extra = ctypes.c_voidp()
406
407 SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(200))
408 # reset should free...
409 SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(300))
410 self.assertEqual(LAST_FREED, 200)
411
412 extra = ctypes.c_voidp()
413 GetExtra(f.__code__, FREE_INDEX, extra)
414 self.assertEqual(extra.value, 300)
415 del f
416
417 def test_free_different_thread(self):
418 # Freeing a code object on a different thread then
419 # where the co_extra was set should be safe.
420 f = self.get_func()
421 class ThreadTest(threading.Thread):
422 def __init__(self, f, test):
423 super().__init__()
424 self.f = f
425 self.test = test
426 def run(self):
427 del self.f
428 self.test.assertEqual(LAST_FREED, 500)
429
430 SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(500))
431 tt = ThreadTest(f, self)
432 del f
433 tt.start()
434 tt.join()
435 self.assertEqual(LAST_FREED, 500)
436
Pablo Galindof00828a2019-05-09 16:52:02 +0100437 @cpython_only
438 def test_clean_stack_on_return(self):
439
440 def f(x):
441 return x
442
443 code = f.__code__
444 ct = type(f.__code__)
445
446 # Insert an extra LOAD_FAST, this duplicates the value of
447 # 'x' in the stack, leaking it if the frame is not properly
448 # cleaned up upon exit.
449
450 bytecode = list(code.co_code)
451 bytecode.insert(-2, opcode.opmap['LOAD_FAST'])
452 bytecode.insert(-2, 0)
453
454 c = ct(code.co_argcount, code.co_posonlyargcount,
455 code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize+1,
456 code.co_flags, bytes(bytecode),
457 code.co_consts, code.co_names, code.co_varnames,
458 code.co_filename, code.co_name, code.co_firstlineno,
459 code.co_lnotab, code.co_freevars, code.co_cellvars)
460 new_function = type(f)(c, f.__globals__, 'nf', f.__defaults__, f.__closure__)
461
462 class Var:
463 pass
464 the_object = Var()
465 var = weakref.ref(the_object)
466
467 new_function(the_object)
468
469 # Check if the_object is leaked
470 del the_object
471 assert var() is None
472
473
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000474def test_main(verbose=None):
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000475 from test import test_code
476 run_doctest(test_code, verbose)
Dino Viehlandf3cffd22017-06-21 14:44:36 -0700477 tests = [CodeTest, CodeConstsTest, CodeWeakRefTest]
Victor Stinnera4b091e2017-06-23 15:08:55 +0200478 if check_impl_detail(cpython=True) and ctypes is not None:
Dino Viehlandf3cffd22017-06-21 14:44:36 -0700479 tests.append(CoExtra)
480 run_unittest(*tests)
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000481
Collin Winter4222e9c2010-03-18 22:46:40 +0000482if __name__ == "__main__":
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000483 test_main()