xref: /third_party/python/Lib/test/test_code.py (revision 7db96d56)
17db96d56Sopenharmony_ci"""This module includes tests of the code object representation.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci>>> def f(x):
47db96d56Sopenharmony_ci...     def g(y):
57db96d56Sopenharmony_ci...         return x + y
67db96d56Sopenharmony_ci...     return g
77db96d56Sopenharmony_ci...
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci>>> dump(f.__code__)
107db96d56Sopenharmony_ciname: f
117db96d56Sopenharmony_ciargcount: 1
127db96d56Sopenharmony_ciposonlyargcount: 0
137db96d56Sopenharmony_cikwonlyargcount: 0
147db96d56Sopenharmony_cinames: ()
157db96d56Sopenharmony_civarnames: ('x', 'g')
167db96d56Sopenharmony_cicellvars: ('x',)
177db96d56Sopenharmony_cifreevars: ()
187db96d56Sopenharmony_cinlocals: 2
197db96d56Sopenharmony_ciflags: 3
207db96d56Sopenharmony_ciconsts: ('None', '<code object g>')
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci>>> dump(f(4).__code__)
237db96d56Sopenharmony_ciname: g
247db96d56Sopenharmony_ciargcount: 1
257db96d56Sopenharmony_ciposonlyargcount: 0
267db96d56Sopenharmony_cikwonlyargcount: 0
277db96d56Sopenharmony_cinames: ()
287db96d56Sopenharmony_civarnames: ('y',)
297db96d56Sopenharmony_cicellvars: ()
307db96d56Sopenharmony_cifreevars: ('x',)
317db96d56Sopenharmony_cinlocals: 1
327db96d56Sopenharmony_ciflags: 19
337db96d56Sopenharmony_ciconsts: ('None',)
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci>>> def h(x, y):
367db96d56Sopenharmony_ci...     a = x + y
377db96d56Sopenharmony_ci...     b = x - y
387db96d56Sopenharmony_ci...     c = a * b
397db96d56Sopenharmony_ci...     return c
407db96d56Sopenharmony_ci...
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci>>> dump(h.__code__)
437db96d56Sopenharmony_ciname: h
447db96d56Sopenharmony_ciargcount: 2
457db96d56Sopenharmony_ciposonlyargcount: 0
467db96d56Sopenharmony_cikwonlyargcount: 0
477db96d56Sopenharmony_cinames: ()
487db96d56Sopenharmony_civarnames: ('x', 'y', 'a', 'b', 'c')
497db96d56Sopenharmony_cicellvars: ()
507db96d56Sopenharmony_cifreevars: ()
517db96d56Sopenharmony_cinlocals: 5
527db96d56Sopenharmony_ciflags: 3
537db96d56Sopenharmony_ciconsts: ('None',)
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci>>> def attrs(obj):
567db96d56Sopenharmony_ci...     print(obj.attr1)
577db96d56Sopenharmony_ci...     print(obj.attr2)
587db96d56Sopenharmony_ci...     print(obj.attr3)
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci>>> dump(attrs.__code__)
617db96d56Sopenharmony_ciname: attrs
627db96d56Sopenharmony_ciargcount: 1
637db96d56Sopenharmony_ciposonlyargcount: 0
647db96d56Sopenharmony_cikwonlyargcount: 0
657db96d56Sopenharmony_cinames: ('print', 'attr1', 'attr2', 'attr3')
667db96d56Sopenharmony_civarnames: ('obj',)
677db96d56Sopenharmony_cicellvars: ()
687db96d56Sopenharmony_cifreevars: ()
697db96d56Sopenharmony_cinlocals: 1
707db96d56Sopenharmony_ciflags: 3
717db96d56Sopenharmony_ciconsts: ('None',)
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci>>> def optimize_away():
747db96d56Sopenharmony_ci...     'doc string'
757db96d56Sopenharmony_ci...     'not a docstring'
767db96d56Sopenharmony_ci...     53
777db96d56Sopenharmony_ci...     0x53
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci>>> dump(optimize_away.__code__)
807db96d56Sopenharmony_ciname: optimize_away
817db96d56Sopenharmony_ciargcount: 0
827db96d56Sopenharmony_ciposonlyargcount: 0
837db96d56Sopenharmony_cikwonlyargcount: 0
847db96d56Sopenharmony_cinames: ()
857db96d56Sopenharmony_civarnames: ()
867db96d56Sopenharmony_cicellvars: ()
877db96d56Sopenharmony_cifreevars: ()
887db96d56Sopenharmony_cinlocals: 0
897db96d56Sopenharmony_ciflags: 3
907db96d56Sopenharmony_ciconsts: ("'doc string'", 'None')
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ci>>> def keywordonly_args(a,b,*,k1):
937db96d56Sopenharmony_ci...     return a,b,k1
947db96d56Sopenharmony_ci...
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci>>> dump(keywordonly_args.__code__)
977db96d56Sopenharmony_ciname: keywordonly_args
987db96d56Sopenharmony_ciargcount: 2
997db96d56Sopenharmony_ciposonlyargcount: 0
1007db96d56Sopenharmony_cikwonlyargcount: 1
1017db96d56Sopenharmony_cinames: ()
1027db96d56Sopenharmony_civarnames: ('a', 'b', 'k1')
1037db96d56Sopenharmony_cicellvars: ()
1047db96d56Sopenharmony_cifreevars: ()
1057db96d56Sopenharmony_cinlocals: 3
1067db96d56Sopenharmony_ciflags: 3
1077db96d56Sopenharmony_ciconsts: ('None',)
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci>>> def posonly_args(a,b,/,c):
1107db96d56Sopenharmony_ci...     return a,b,c
1117db96d56Sopenharmony_ci...
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci>>> dump(posonly_args.__code__)
1147db96d56Sopenharmony_ciname: posonly_args
1157db96d56Sopenharmony_ciargcount: 3
1167db96d56Sopenharmony_ciposonlyargcount: 2
1177db96d56Sopenharmony_cikwonlyargcount: 0
1187db96d56Sopenharmony_cinames: ()
1197db96d56Sopenharmony_civarnames: ('a', 'b', 'c')
1207db96d56Sopenharmony_cicellvars: ()
1217db96d56Sopenharmony_cifreevars: ()
1227db96d56Sopenharmony_cinlocals: 3
1237db96d56Sopenharmony_ciflags: 3
1247db96d56Sopenharmony_ciconsts: ('None',)
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_ci"""
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ciimport inspect
1297db96d56Sopenharmony_ciimport sys
1307db96d56Sopenharmony_ciimport threading
1317db96d56Sopenharmony_ciimport doctest
1327db96d56Sopenharmony_ciimport unittest
1337db96d56Sopenharmony_ciimport textwrap
1347db96d56Sopenharmony_ciimport weakref
1357db96d56Sopenharmony_ciimport dis
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_citry:
1387db96d56Sopenharmony_ci    import ctypes
1397db96d56Sopenharmony_ciexcept ImportError:
1407db96d56Sopenharmony_ci    ctypes = None
1417db96d56Sopenharmony_cifrom test.support import (cpython_only,
1427db96d56Sopenharmony_ci                          check_impl_detail, requires_debug_ranges,
1437db96d56Sopenharmony_ci                          gc_collect)
1447db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_ok
1457db96d56Sopenharmony_cifrom test.support import threading_helper
1467db96d56Sopenharmony_cifrom opcode import opmap
1477db96d56Sopenharmony_ciCOPY_FREE_VARS = opmap['COPY_FREE_VARS']
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_cidef consts(t):
1517db96d56Sopenharmony_ci    """Yield a doctest-safe sequence of object reprs."""
1527db96d56Sopenharmony_ci    for elt in t:
1537db96d56Sopenharmony_ci        r = repr(elt)
1547db96d56Sopenharmony_ci        if r.startswith("<code object"):
1557db96d56Sopenharmony_ci            yield "<code object %s>" % elt.co_name
1567db96d56Sopenharmony_ci        else:
1577db96d56Sopenharmony_ci            yield r
1587db96d56Sopenharmony_ci
1597db96d56Sopenharmony_cidef dump(co):
1607db96d56Sopenharmony_ci    """Print out a text representation of a code object."""
1617db96d56Sopenharmony_ci    for attr in ["name", "argcount", "posonlyargcount",
1627db96d56Sopenharmony_ci                 "kwonlyargcount", "names", "varnames",
1637db96d56Sopenharmony_ci                 "cellvars", "freevars", "nlocals", "flags"]:
1647db96d56Sopenharmony_ci        print("%s: %s" % (attr, getattr(co, "co_" + attr)))
1657db96d56Sopenharmony_ci    print("consts:", tuple(consts(co.co_consts)))
1667db96d56Sopenharmony_ci
1677db96d56Sopenharmony_ci# Needed for test_closure_injection below
1687db96d56Sopenharmony_ci# Defined at global scope to avoid implicitly closing over __class__
1697db96d56Sopenharmony_cidef external_getitem(self, i):
1707db96d56Sopenharmony_ci    return f"Foreign getitem: {super().__getitem__(i)}"
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ciclass CodeTest(unittest.TestCase):
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    @cpython_only
1757db96d56Sopenharmony_ci    def test_newempty(self):
1767db96d56Sopenharmony_ci        import _testcapi
1777db96d56Sopenharmony_ci        co = _testcapi.code_newempty("filename", "funcname", 15)
1787db96d56Sopenharmony_ci        self.assertEqual(co.co_filename, "filename")
1797db96d56Sopenharmony_ci        self.assertEqual(co.co_name, "funcname")
1807db96d56Sopenharmony_ci        self.assertEqual(co.co_firstlineno, 15)
1817db96d56Sopenharmony_ci        #Empty code object should raise, but not crash the VM
1827db96d56Sopenharmony_ci        with self.assertRaises(Exception):
1837db96d56Sopenharmony_ci            exec(co)
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci    @cpython_only
1867db96d56Sopenharmony_ci    def test_closure_injection(self):
1877db96d56Sopenharmony_ci        # From https://bugs.python.org/issue32176
1887db96d56Sopenharmony_ci        from types import FunctionType
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ci        def create_closure(__class__):
1917db96d56Sopenharmony_ci            return (lambda: __class__).__closure__
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_ci        def new_code(c):
1947db96d56Sopenharmony_ci            '''A new code object with a __class__ cell added to freevars'''
1957db96d56Sopenharmony_ci            return c.replace(co_freevars=c.co_freevars + ('__class__',), co_code=bytes([COPY_FREE_VARS, 1])+c.co_code)
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ci        def add_foreign_method(cls, name, f):
1987db96d56Sopenharmony_ci            code = new_code(f.__code__)
1997db96d56Sopenharmony_ci            assert not f.__closure__
2007db96d56Sopenharmony_ci            closure = create_closure(cls)
2017db96d56Sopenharmony_ci            defaults = f.__defaults__
2027db96d56Sopenharmony_ci            setattr(cls, name, FunctionType(code, globals(), name, defaults, closure))
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ci        class List(list):
2057db96d56Sopenharmony_ci            pass
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ci        add_foreign_method(List, "__getitem__", external_getitem)
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci        # Ensure the closure injection actually worked
2107db96d56Sopenharmony_ci        function = List.__getitem__
2117db96d56Sopenharmony_ci        class_ref = function.__closure__[0].cell_contents
2127db96d56Sopenharmony_ci        self.assertIs(class_ref, List)
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci        # Ensure the zero-arg super() call in the injected method works
2157db96d56Sopenharmony_ci        obj = List([1, 2, 3])
2167db96d56Sopenharmony_ci        self.assertEqual(obj[0], "Foreign getitem: 1")
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci    def test_constructor(self):
2197db96d56Sopenharmony_ci        def func(): pass
2207db96d56Sopenharmony_ci        co = func.__code__
2217db96d56Sopenharmony_ci        CodeType = type(co)
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ci        # test code constructor
2247db96d56Sopenharmony_ci        CodeType(co.co_argcount,
2257db96d56Sopenharmony_ci                        co.co_posonlyargcount,
2267db96d56Sopenharmony_ci                        co.co_kwonlyargcount,
2277db96d56Sopenharmony_ci                        co.co_nlocals,
2287db96d56Sopenharmony_ci                        co.co_stacksize,
2297db96d56Sopenharmony_ci                        co.co_flags,
2307db96d56Sopenharmony_ci                        co.co_code,
2317db96d56Sopenharmony_ci                        co.co_consts,
2327db96d56Sopenharmony_ci                        co.co_names,
2337db96d56Sopenharmony_ci                        co.co_varnames,
2347db96d56Sopenharmony_ci                        co.co_filename,
2357db96d56Sopenharmony_ci                        co.co_name,
2367db96d56Sopenharmony_ci                        co.co_qualname,
2377db96d56Sopenharmony_ci                        co.co_firstlineno,
2387db96d56Sopenharmony_ci                        co.co_linetable,
2397db96d56Sopenharmony_ci                        co.co_exceptiontable,
2407db96d56Sopenharmony_ci                        co.co_freevars,
2417db96d56Sopenharmony_ci                        co.co_cellvars)
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    def test_qualname(self):
2447db96d56Sopenharmony_ci        self.assertEqual(
2457db96d56Sopenharmony_ci            CodeTest.test_qualname.__code__.co_qualname,
2467db96d56Sopenharmony_ci            CodeTest.test_qualname.__qualname__
2477db96d56Sopenharmony_ci        )
2487db96d56Sopenharmony_ci
2497db96d56Sopenharmony_ci    def test_replace(self):
2507db96d56Sopenharmony_ci        def func():
2517db96d56Sopenharmony_ci            x = 1
2527db96d56Sopenharmony_ci            return x
2537db96d56Sopenharmony_ci        code = func.__code__
2547db96d56Sopenharmony_ci
2557db96d56Sopenharmony_ci        # different co_name, co_varnames, co_consts
2567db96d56Sopenharmony_ci        def func2():
2577db96d56Sopenharmony_ci            y = 2
2587db96d56Sopenharmony_ci            z = 3
2597db96d56Sopenharmony_ci            return y
2607db96d56Sopenharmony_ci        code2 = func2.__code__
2617db96d56Sopenharmony_ci
2627db96d56Sopenharmony_ci        for attr, value in (
2637db96d56Sopenharmony_ci            ("co_argcount", 0),
2647db96d56Sopenharmony_ci            ("co_posonlyargcount", 0),
2657db96d56Sopenharmony_ci            ("co_kwonlyargcount", 0),
2667db96d56Sopenharmony_ci            ("co_nlocals", 1),
2677db96d56Sopenharmony_ci            ("co_stacksize", 0),
2687db96d56Sopenharmony_ci            ("co_flags", code.co_flags | inspect.CO_COROUTINE),
2697db96d56Sopenharmony_ci            ("co_firstlineno", 100),
2707db96d56Sopenharmony_ci            ("co_code", code2.co_code),
2717db96d56Sopenharmony_ci            ("co_consts", code2.co_consts),
2727db96d56Sopenharmony_ci            ("co_names", ("myname",)),
2737db96d56Sopenharmony_ci            ("co_varnames", ('spam',)),
2747db96d56Sopenharmony_ci            ("co_freevars", ("freevar",)),
2757db96d56Sopenharmony_ci            ("co_cellvars", ("cellvar",)),
2767db96d56Sopenharmony_ci            ("co_filename", "newfilename"),
2777db96d56Sopenharmony_ci            ("co_name", "newname"),
2787db96d56Sopenharmony_ci            ("co_linetable", code2.co_linetable),
2797db96d56Sopenharmony_ci        ):
2807db96d56Sopenharmony_ci            with self.subTest(attr=attr, value=value):
2817db96d56Sopenharmony_ci                new_code = code.replace(**{attr: value})
2827db96d56Sopenharmony_ci                self.assertEqual(getattr(new_code, attr), value)
2837db96d56Sopenharmony_ci
2847db96d56Sopenharmony_ci        new_code = code.replace(co_varnames=code2.co_varnames,
2857db96d56Sopenharmony_ci                                co_nlocals=code2.co_nlocals)
2867db96d56Sopenharmony_ci        self.assertEqual(new_code.co_varnames, code2.co_varnames)
2877db96d56Sopenharmony_ci        self.assertEqual(new_code.co_nlocals, code2.co_nlocals)
2887db96d56Sopenharmony_ci
2897db96d56Sopenharmony_ci    def test_nlocals_mismatch(self):
2907db96d56Sopenharmony_ci        def func():
2917db96d56Sopenharmony_ci            x = 1
2927db96d56Sopenharmony_ci            return x
2937db96d56Sopenharmony_ci        co = func.__code__
2947db96d56Sopenharmony_ci        assert co.co_nlocals > 0;
2957db96d56Sopenharmony_ci
2967db96d56Sopenharmony_ci        # First we try the constructor.
2977db96d56Sopenharmony_ci        CodeType = type(co)
2987db96d56Sopenharmony_ci        for diff in (-1, 1):
2997db96d56Sopenharmony_ci            with self.assertRaises(ValueError):
3007db96d56Sopenharmony_ci                CodeType(co.co_argcount,
3017db96d56Sopenharmony_ci                         co.co_posonlyargcount,
3027db96d56Sopenharmony_ci                         co.co_kwonlyargcount,
3037db96d56Sopenharmony_ci                         # This is the only change.
3047db96d56Sopenharmony_ci                         co.co_nlocals + diff,
3057db96d56Sopenharmony_ci                         co.co_stacksize,
3067db96d56Sopenharmony_ci                         co.co_flags,
3077db96d56Sopenharmony_ci                         co.co_code,
3087db96d56Sopenharmony_ci                         co.co_consts,
3097db96d56Sopenharmony_ci                         co.co_names,
3107db96d56Sopenharmony_ci                         co.co_varnames,
3117db96d56Sopenharmony_ci                         co.co_filename,
3127db96d56Sopenharmony_ci                         co.co_name,
3137db96d56Sopenharmony_ci                         co.co_qualname,
3147db96d56Sopenharmony_ci                         co.co_firstlineno,
3157db96d56Sopenharmony_ci                         co.co_linetable,
3167db96d56Sopenharmony_ci                         co.co_exceptiontable,
3177db96d56Sopenharmony_ci                         co.co_freevars,
3187db96d56Sopenharmony_ci                         co.co_cellvars,
3197db96d56Sopenharmony_ci                         )
3207db96d56Sopenharmony_ci        # Then we try the replace method.
3217db96d56Sopenharmony_ci        with self.assertRaises(ValueError):
3227db96d56Sopenharmony_ci            co.replace(co_nlocals=co.co_nlocals - 1)
3237db96d56Sopenharmony_ci        with self.assertRaises(ValueError):
3247db96d56Sopenharmony_ci            co.replace(co_nlocals=co.co_nlocals + 1)
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci    def test_shrinking_localsplus(self):
3277db96d56Sopenharmony_ci        # Check that PyCode_NewWithPosOnlyArgs resizes both
3287db96d56Sopenharmony_ci        # localsplusnames and localspluskinds, if an argument is a cell.
3297db96d56Sopenharmony_ci        def func(arg):
3307db96d56Sopenharmony_ci            return lambda: arg
3317db96d56Sopenharmony_ci        code = func.__code__
3327db96d56Sopenharmony_ci        newcode = code.replace(co_name="func")  # Should not raise SystemError
3337db96d56Sopenharmony_ci        self.assertEqual(code, newcode)
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ci    def test_empty_linetable(self):
3367db96d56Sopenharmony_ci        def func():
3377db96d56Sopenharmony_ci            pass
3387db96d56Sopenharmony_ci        new_code = code = func.__code__.replace(co_linetable=b'')
3397db96d56Sopenharmony_ci        self.assertEqual(list(new_code.co_lines()), [])
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci    @requires_debug_ranges()
3427db96d56Sopenharmony_ci    def test_co_positions_artificial_instructions(self):
3437db96d56Sopenharmony_ci        import dis
3447db96d56Sopenharmony_ci
3457db96d56Sopenharmony_ci        namespace = {}
3467db96d56Sopenharmony_ci        exec(textwrap.dedent("""\
3477db96d56Sopenharmony_ci        try:
3487db96d56Sopenharmony_ci            1/0
3497db96d56Sopenharmony_ci        except Exception as e:
3507db96d56Sopenharmony_ci            exc = e
3517db96d56Sopenharmony_ci        """), namespace)
3527db96d56Sopenharmony_ci
3537db96d56Sopenharmony_ci        exc = namespace['exc']
3547db96d56Sopenharmony_ci        traceback = exc.__traceback__
3557db96d56Sopenharmony_ci        code = traceback.tb_frame.f_code
3567db96d56Sopenharmony_ci
3577db96d56Sopenharmony_ci        artificial_instructions = []
3587db96d56Sopenharmony_ci        for instr, positions in zip(
3597db96d56Sopenharmony_ci            dis.get_instructions(code, show_caches=True),
3607db96d56Sopenharmony_ci            code.co_positions(),
3617db96d56Sopenharmony_ci            strict=True
3627db96d56Sopenharmony_ci        ):
3637db96d56Sopenharmony_ci            # If any of the positions is None, then all have to
3647db96d56Sopenharmony_ci            # be None as well for the case above. There are still
3657db96d56Sopenharmony_ci            # some places in the compiler, where the artificial instructions
3667db96d56Sopenharmony_ci            # get assigned the first_lineno but they don't have other positions.
3677db96d56Sopenharmony_ci            # There is no easy way of inferring them at that stage, so for now
3687db96d56Sopenharmony_ci            # we don't support it.
3697db96d56Sopenharmony_ci            self.assertIn(positions.count(None), [0, 3, 4])
3707db96d56Sopenharmony_ci
3717db96d56Sopenharmony_ci            if not any(positions):
3727db96d56Sopenharmony_ci                artificial_instructions.append(instr)
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci        self.assertEqual(
3757db96d56Sopenharmony_ci            [
3767db96d56Sopenharmony_ci                (instruction.opname, instruction.argval)
3777db96d56Sopenharmony_ci                for instruction in artificial_instructions
3787db96d56Sopenharmony_ci            ],
3797db96d56Sopenharmony_ci            [
3807db96d56Sopenharmony_ci                ("PUSH_EXC_INFO", None),
3817db96d56Sopenharmony_ci                ("LOAD_CONST", None), # artificial 'None'
3827db96d56Sopenharmony_ci                ("STORE_NAME", "e"),  # XX: we know the location for this
3837db96d56Sopenharmony_ci                ("DELETE_NAME", "e"),
3847db96d56Sopenharmony_ci                ("RERAISE", 1),
3857db96d56Sopenharmony_ci                ("COPY", 3),
3867db96d56Sopenharmony_ci                ("POP_EXCEPT", None),
3877db96d56Sopenharmony_ci                ("RERAISE", 1)
3887db96d56Sopenharmony_ci            ]
3897db96d56Sopenharmony_ci        )
3907db96d56Sopenharmony_ci
3917db96d56Sopenharmony_ci    def test_endline_and_columntable_none_when_no_debug_ranges(self):
3927db96d56Sopenharmony_ci        # Make sure that if `-X no_debug_ranges` is used, there is
3937db96d56Sopenharmony_ci        # minimal debug info
3947db96d56Sopenharmony_ci        code = textwrap.dedent("""
3957db96d56Sopenharmony_ci            def f():
3967db96d56Sopenharmony_ci                pass
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_ci            positions = f.__code__.co_positions()
3997db96d56Sopenharmony_ci            for line, end_line, column, end_column in positions:
4007db96d56Sopenharmony_ci                assert line == end_line
4017db96d56Sopenharmony_ci                assert column is None
4027db96d56Sopenharmony_ci                assert end_column is None
4037db96d56Sopenharmony_ci            """)
4047db96d56Sopenharmony_ci        assert_python_ok('-X', 'no_debug_ranges', '-c', code)
4057db96d56Sopenharmony_ci
4067db96d56Sopenharmony_ci    def test_endline_and_columntable_none_when_no_debug_ranges_env(self):
4077db96d56Sopenharmony_ci        # Same as above but using the environment variable opt out.
4087db96d56Sopenharmony_ci        code = textwrap.dedent("""
4097db96d56Sopenharmony_ci            def f():
4107db96d56Sopenharmony_ci                pass
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ci            positions = f.__code__.co_positions()
4137db96d56Sopenharmony_ci            for line, end_line, column, end_column in positions:
4147db96d56Sopenharmony_ci                assert line == end_line
4157db96d56Sopenharmony_ci                assert column is None
4167db96d56Sopenharmony_ci                assert end_column is None
4177db96d56Sopenharmony_ci            """)
4187db96d56Sopenharmony_ci        assert_python_ok('-c', code, PYTHONNODEBUGRANGES='1')
4197db96d56Sopenharmony_ci
4207db96d56Sopenharmony_ci    # co_positions behavior when info is missing.
4217db96d56Sopenharmony_ci
4227db96d56Sopenharmony_ci    @requires_debug_ranges()
4237db96d56Sopenharmony_ci    def test_co_positions_empty_linetable(self):
4247db96d56Sopenharmony_ci        def func():
4257db96d56Sopenharmony_ci            x = 1
4267db96d56Sopenharmony_ci        new_code = func.__code__.replace(co_linetable=b'')
4277db96d56Sopenharmony_ci        positions = new_code.co_positions()
4287db96d56Sopenharmony_ci        for line, end_line, column, end_column in positions:
4297db96d56Sopenharmony_ci            self.assertIsNone(line)
4307db96d56Sopenharmony_ci            self.assertEqual(end_line, new_code.co_firstlineno + 1)
4317db96d56Sopenharmony_ci
4327db96d56Sopenharmony_ci    def test_code_equality(self):
4337db96d56Sopenharmony_ci        def f():
4347db96d56Sopenharmony_ci            try:
4357db96d56Sopenharmony_ci                a()
4367db96d56Sopenharmony_ci            except:
4377db96d56Sopenharmony_ci                b()
4387db96d56Sopenharmony_ci            else:
4397db96d56Sopenharmony_ci                c()
4407db96d56Sopenharmony_ci            finally:
4417db96d56Sopenharmony_ci                d()
4427db96d56Sopenharmony_ci        code_a = f.__code__
4437db96d56Sopenharmony_ci        code_b = code_a.replace(co_linetable=b"")
4447db96d56Sopenharmony_ci        code_c = code_a.replace(co_exceptiontable=b"")
4457db96d56Sopenharmony_ci        code_d = code_b.replace(co_exceptiontable=b"")
4467db96d56Sopenharmony_ci        self.assertNotEqual(code_a, code_b)
4477db96d56Sopenharmony_ci        self.assertNotEqual(code_a, code_c)
4487db96d56Sopenharmony_ci        self.assertNotEqual(code_a, code_d)
4497db96d56Sopenharmony_ci        self.assertNotEqual(code_b, code_c)
4507db96d56Sopenharmony_ci        self.assertNotEqual(code_b, code_d)
4517db96d56Sopenharmony_ci        self.assertNotEqual(code_c, code_d)
4527db96d56Sopenharmony_ci
4537db96d56Sopenharmony_ci
4547db96d56Sopenharmony_cidef isinterned(s):
4557db96d56Sopenharmony_ci    return s is sys.intern(('_' + s + '_')[1:-1])
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ciclass CodeConstsTest(unittest.TestCase):
4587db96d56Sopenharmony_ci
4597db96d56Sopenharmony_ci    def find_const(self, consts, value):
4607db96d56Sopenharmony_ci        for v in consts:
4617db96d56Sopenharmony_ci            if v == value:
4627db96d56Sopenharmony_ci                return v
4637db96d56Sopenharmony_ci        self.assertIn(value, consts)  # raises an exception
4647db96d56Sopenharmony_ci        self.fail('Should never be reached')
4657db96d56Sopenharmony_ci
4667db96d56Sopenharmony_ci    def assertIsInterned(self, s):
4677db96d56Sopenharmony_ci        if not isinterned(s):
4687db96d56Sopenharmony_ci            self.fail('String %r is not interned' % (s,))
4697db96d56Sopenharmony_ci
4707db96d56Sopenharmony_ci    def assertIsNotInterned(self, s):
4717db96d56Sopenharmony_ci        if isinterned(s):
4727db96d56Sopenharmony_ci            self.fail('String %r is interned' % (s,))
4737db96d56Sopenharmony_ci
4747db96d56Sopenharmony_ci    @cpython_only
4757db96d56Sopenharmony_ci    def test_interned_string(self):
4767db96d56Sopenharmony_ci        co = compile('res = "str_value"', '?', 'exec')
4777db96d56Sopenharmony_ci        v = self.find_const(co.co_consts, 'str_value')
4787db96d56Sopenharmony_ci        self.assertIsInterned(v)
4797db96d56Sopenharmony_ci
4807db96d56Sopenharmony_ci    @cpython_only
4817db96d56Sopenharmony_ci    def test_interned_string_in_tuple(self):
4827db96d56Sopenharmony_ci        co = compile('res = ("str_value",)', '?', 'exec')
4837db96d56Sopenharmony_ci        v = self.find_const(co.co_consts, ('str_value',))
4847db96d56Sopenharmony_ci        self.assertIsInterned(v[0])
4857db96d56Sopenharmony_ci
4867db96d56Sopenharmony_ci    @cpython_only
4877db96d56Sopenharmony_ci    def test_interned_string_in_frozenset(self):
4887db96d56Sopenharmony_ci        co = compile('res = a in {"str_value"}', '?', 'exec')
4897db96d56Sopenharmony_ci        v = self.find_const(co.co_consts, frozenset(('str_value',)))
4907db96d56Sopenharmony_ci        self.assertIsInterned(tuple(v)[0])
4917db96d56Sopenharmony_ci
4927db96d56Sopenharmony_ci    @cpython_only
4937db96d56Sopenharmony_ci    def test_interned_string_default(self):
4947db96d56Sopenharmony_ci        def f(a='str_value'):
4957db96d56Sopenharmony_ci            return a
4967db96d56Sopenharmony_ci        self.assertIsInterned(f())
4977db96d56Sopenharmony_ci
4987db96d56Sopenharmony_ci    @cpython_only
4997db96d56Sopenharmony_ci    def test_interned_string_with_null(self):
5007db96d56Sopenharmony_ci        co = compile(r'res = "str\0value!"', '?', 'exec')
5017db96d56Sopenharmony_ci        v = self.find_const(co.co_consts, 'str\0value!')
5027db96d56Sopenharmony_ci        self.assertIsNotInterned(v)
5037db96d56Sopenharmony_ci
5047db96d56Sopenharmony_ci
5057db96d56Sopenharmony_ciclass CodeWeakRefTest(unittest.TestCase):
5067db96d56Sopenharmony_ci
5077db96d56Sopenharmony_ci    def test_basic(self):
5087db96d56Sopenharmony_ci        # Create a code object in a clean environment so that we know we have
5097db96d56Sopenharmony_ci        # the only reference to it left.
5107db96d56Sopenharmony_ci        namespace = {}
5117db96d56Sopenharmony_ci        exec("def f(): pass", globals(), namespace)
5127db96d56Sopenharmony_ci        f = namespace["f"]
5137db96d56Sopenharmony_ci        del namespace
5147db96d56Sopenharmony_ci
5157db96d56Sopenharmony_ci        self.called = False
5167db96d56Sopenharmony_ci        def callback(code):
5177db96d56Sopenharmony_ci            self.called = True
5187db96d56Sopenharmony_ci
5197db96d56Sopenharmony_ci        # f is now the last reference to the function, and through it, the code
5207db96d56Sopenharmony_ci        # object.  While we hold it, check that we can create a weakref and
5217db96d56Sopenharmony_ci        # deref it.  Then delete it, and check that the callback gets called and
5227db96d56Sopenharmony_ci        # the reference dies.
5237db96d56Sopenharmony_ci        coderef = weakref.ref(f.__code__, callback)
5247db96d56Sopenharmony_ci        self.assertTrue(bool(coderef()))
5257db96d56Sopenharmony_ci        del f
5267db96d56Sopenharmony_ci        gc_collect()  # For PyPy or other GCs.
5277db96d56Sopenharmony_ci        self.assertFalse(bool(coderef()))
5287db96d56Sopenharmony_ci        self.assertTrue(self.called)
5297db96d56Sopenharmony_ci
5307db96d56Sopenharmony_ci# Python implementation of location table parsing algorithm
5317db96d56Sopenharmony_cidef read(it):
5327db96d56Sopenharmony_ci    return next(it)
5337db96d56Sopenharmony_ci
5347db96d56Sopenharmony_cidef read_varint(it):
5357db96d56Sopenharmony_ci    b = read(it)
5367db96d56Sopenharmony_ci    val = b & 63;
5377db96d56Sopenharmony_ci    shift = 0;
5387db96d56Sopenharmony_ci    while b & 64:
5397db96d56Sopenharmony_ci        b = read(it)
5407db96d56Sopenharmony_ci        shift += 6
5417db96d56Sopenharmony_ci        val |= (b&63) << shift
5427db96d56Sopenharmony_ci    return val
5437db96d56Sopenharmony_ci
5447db96d56Sopenharmony_cidef read_signed_varint(it):
5457db96d56Sopenharmony_ci    uval = read_varint(it)
5467db96d56Sopenharmony_ci    if uval & 1:
5477db96d56Sopenharmony_ci        return -(uval >> 1)
5487db96d56Sopenharmony_ci    else:
5497db96d56Sopenharmony_ci        return uval >> 1
5507db96d56Sopenharmony_ci
5517db96d56Sopenharmony_cidef parse_location_table(code):
5527db96d56Sopenharmony_ci    line = code.co_firstlineno
5537db96d56Sopenharmony_ci    it = iter(code.co_linetable)
5547db96d56Sopenharmony_ci    while True:
5557db96d56Sopenharmony_ci        try:
5567db96d56Sopenharmony_ci            first_byte = read(it)
5577db96d56Sopenharmony_ci        except StopIteration:
5587db96d56Sopenharmony_ci            return
5597db96d56Sopenharmony_ci        code = (first_byte >> 3) & 15
5607db96d56Sopenharmony_ci        length = (first_byte & 7) + 1
5617db96d56Sopenharmony_ci        if code == 15:
5627db96d56Sopenharmony_ci            yield (code, length, None, None, None, None)
5637db96d56Sopenharmony_ci        elif code == 14:
5647db96d56Sopenharmony_ci            line_delta = read_signed_varint(it)
5657db96d56Sopenharmony_ci            line += line_delta
5667db96d56Sopenharmony_ci            end_line = line + read_varint(it)
5677db96d56Sopenharmony_ci            col = read_varint(it)
5687db96d56Sopenharmony_ci            if col == 0:
5697db96d56Sopenharmony_ci                col = None
5707db96d56Sopenharmony_ci            else:
5717db96d56Sopenharmony_ci                col -= 1
5727db96d56Sopenharmony_ci            end_col = read_varint(it)
5737db96d56Sopenharmony_ci            if end_col == 0:
5747db96d56Sopenharmony_ci                end_col = None
5757db96d56Sopenharmony_ci            else:
5767db96d56Sopenharmony_ci                end_col -= 1
5777db96d56Sopenharmony_ci            yield (code, length, line, end_line, col, end_col)
5787db96d56Sopenharmony_ci        elif code == 13: # No column
5797db96d56Sopenharmony_ci            line_delta = read_signed_varint(it)
5807db96d56Sopenharmony_ci            line += line_delta
5817db96d56Sopenharmony_ci            yield (code, length, line, line, None, None)
5827db96d56Sopenharmony_ci        elif code in (10, 11, 12): # new line
5837db96d56Sopenharmony_ci            line_delta = code - 10
5847db96d56Sopenharmony_ci            line += line_delta
5857db96d56Sopenharmony_ci            column = read(it)
5867db96d56Sopenharmony_ci            end_column = read(it)
5877db96d56Sopenharmony_ci            yield (code, length, line, line, column, end_column)
5887db96d56Sopenharmony_ci        else:
5897db96d56Sopenharmony_ci            assert (0 <= code < 10)
5907db96d56Sopenharmony_ci            second_byte = read(it)
5917db96d56Sopenharmony_ci            column = code << 3 | (second_byte >> 4)
5927db96d56Sopenharmony_ci            yield (code, length, line, line, column, column + (second_byte & 15))
5937db96d56Sopenharmony_ci
5947db96d56Sopenharmony_cidef positions_from_location_table(code):
5957db96d56Sopenharmony_ci    for _, length, line, end_line, col, end_col in parse_location_table(code):
5967db96d56Sopenharmony_ci        for _ in range(length):
5977db96d56Sopenharmony_ci            yield (line, end_line, col, end_col)
5987db96d56Sopenharmony_ci
5997db96d56Sopenharmony_cidef dedup(lst, prev=object()):
6007db96d56Sopenharmony_ci    for item in lst:
6017db96d56Sopenharmony_ci        if item != prev:
6027db96d56Sopenharmony_ci            yield item
6037db96d56Sopenharmony_ci            prev = item
6047db96d56Sopenharmony_ci
6057db96d56Sopenharmony_cidef lines_from_postions(positions):
6067db96d56Sopenharmony_ci    return dedup(l for (l, _, _, _) in positions)
6077db96d56Sopenharmony_ci
6087db96d56Sopenharmony_cidef misshappen():
6097db96d56Sopenharmony_ci    """
6107db96d56Sopenharmony_ci
6117db96d56Sopenharmony_ci
6127db96d56Sopenharmony_ci
6137db96d56Sopenharmony_ci
6147db96d56Sopenharmony_ci
6157db96d56Sopenharmony_ci    """
6167db96d56Sopenharmony_ci    x = (
6177db96d56Sopenharmony_ci
6187db96d56Sopenharmony_ci
6197db96d56Sopenharmony_ci        4
6207db96d56Sopenharmony_ci
6217db96d56Sopenharmony_ci        +
6227db96d56Sopenharmony_ci
6237db96d56Sopenharmony_ci        y
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ci    )
6267db96d56Sopenharmony_ci    y = (
6277db96d56Sopenharmony_ci        a
6287db96d56Sopenharmony_ci        +
6297db96d56Sopenharmony_ci            b
6307db96d56Sopenharmony_ci                +
6317db96d56Sopenharmony_ci
6327db96d56Sopenharmony_ci                d
6337db96d56Sopenharmony_ci        )
6347db96d56Sopenharmony_ci    return q if (
6357db96d56Sopenharmony_ci
6367db96d56Sopenharmony_ci        x
6377db96d56Sopenharmony_ci
6387db96d56Sopenharmony_ci        ) else p
6397db96d56Sopenharmony_ci
6407db96d56Sopenharmony_cidef bug93662():
6417db96d56Sopenharmony_ci    example_report_generation_message= (
6427db96d56Sopenharmony_ci            """
6437db96d56Sopenharmony_ci            """
6447db96d56Sopenharmony_ci    ).strip()
6457db96d56Sopenharmony_ci    raise ValueError()
6467db96d56Sopenharmony_ci
6477db96d56Sopenharmony_ci
6487db96d56Sopenharmony_ciclass CodeLocationTest(unittest.TestCase):
6497db96d56Sopenharmony_ci
6507db96d56Sopenharmony_ci    def check_positions(self, func):
6517db96d56Sopenharmony_ci        pos1 = list(func.__code__.co_positions())
6527db96d56Sopenharmony_ci        pos2 = list(positions_from_location_table(func.__code__))
6537db96d56Sopenharmony_ci        for l1, l2 in zip(pos1, pos2):
6547db96d56Sopenharmony_ci            self.assertEqual(l1, l2)
6557db96d56Sopenharmony_ci        self.assertEqual(len(pos1), len(pos2))
6567db96d56Sopenharmony_ci
6577db96d56Sopenharmony_ci    def test_positions(self):
6587db96d56Sopenharmony_ci        self.check_positions(parse_location_table)
6597db96d56Sopenharmony_ci        self.check_positions(misshappen)
6607db96d56Sopenharmony_ci        self.check_positions(bug93662)
6617db96d56Sopenharmony_ci
6627db96d56Sopenharmony_ci    def check_lines(self, func):
6637db96d56Sopenharmony_ci        co = func.__code__
6647db96d56Sopenharmony_ci        lines1 = list(dedup(l for (_, _, l) in co.co_lines()))
6657db96d56Sopenharmony_ci        lines2 = list(lines_from_postions(positions_from_location_table(co)))
6667db96d56Sopenharmony_ci        for l1, l2 in zip(lines1, lines2):
6677db96d56Sopenharmony_ci            self.assertEqual(l1, l2)
6687db96d56Sopenharmony_ci        self.assertEqual(len(lines1), len(lines2))
6697db96d56Sopenharmony_ci
6707db96d56Sopenharmony_ci    def test_lines(self):
6717db96d56Sopenharmony_ci        self.check_lines(parse_location_table)
6727db96d56Sopenharmony_ci        self.check_lines(misshappen)
6737db96d56Sopenharmony_ci        self.check_lines(bug93662)
6747db96d56Sopenharmony_ci
6757db96d56Sopenharmony_ci    @cpython_only
6767db96d56Sopenharmony_ci    def test_code_new_empty(self):
6777db96d56Sopenharmony_ci        # If this test fails, it means that the construction of PyCode_NewEmpty
6787db96d56Sopenharmony_ci        # needs to be modified! Please update this test *and* PyCode_NewEmpty,
6797db96d56Sopenharmony_ci        # so that they both stay in sync.
6807db96d56Sopenharmony_ci        def f():
6817db96d56Sopenharmony_ci            pass
6827db96d56Sopenharmony_ci        PY_CODE_LOCATION_INFO_NO_COLUMNS = 13
6837db96d56Sopenharmony_ci        f.__code__ = f.__code__.replace(
6847db96d56Sopenharmony_ci            co_firstlineno=42,
6857db96d56Sopenharmony_ci            co_code=bytes(
6867db96d56Sopenharmony_ci                [
6877db96d56Sopenharmony_ci                    dis.opmap["RESUME"], 0,
6887db96d56Sopenharmony_ci                    dis.opmap["LOAD_ASSERTION_ERROR"], 0,
6897db96d56Sopenharmony_ci                    dis.opmap["RAISE_VARARGS"], 1,
6907db96d56Sopenharmony_ci                ]
6917db96d56Sopenharmony_ci            ),
6927db96d56Sopenharmony_ci            co_linetable=bytes(
6937db96d56Sopenharmony_ci                [
6947db96d56Sopenharmony_ci                    (1 << 7)
6957db96d56Sopenharmony_ci                    | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3)
6967db96d56Sopenharmony_ci                    | (3 - 1),
6977db96d56Sopenharmony_ci                    0,
6987db96d56Sopenharmony_ci                ]
6997db96d56Sopenharmony_ci            ),
7007db96d56Sopenharmony_ci        )
7017db96d56Sopenharmony_ci        self.assertRaises(AssertionError, f)
7027db96d56Sopenharmony_ci        self.assertEqual(
7037db96d56Sopenharmony_ci            list(f.__code__.co_positions()),
7047db96d56Sopenharmony_ci            3 * [(42, 42, None, None)],
7057db96d56Sopenharmony_ci        )
7067db96d56Sopenharmony_ci
7077db96d56Sopenharmony_ci
7087db96d56Sopenharmony_ciif check_impl_detail(cpython=True) and ctypes is not None:
7097db96d56Sopenharmony_ci    py = ctypes.pythonapi
7107db96d56Sopenharmony_ci    freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp)
7117db96d56Sopenharmony_ci
7127db96d56Sopenharmony_ci    RequestCodeExtraIndex = py._PyEval_RequestCodeExtraIndex
7137db96d56Sopenharmony_ci    RequestCodeExtraIndex.argtypes = (freefunc,)
7147db96d56Sopenharmony_ci    RequestCodeExtraIndex.restype = ctypes.c_ssize_t
7157db96d56Sopenharmony_ci
7167db96d56Sopenharmony_ci    SetExtra = py._PyCode_SetExtra
7177db96d56Sopenharmony_ci    SetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, ctypes.c_voidp)
7187db96d56Sopenharmony_ci    SetExtra.restype = ctypes.c_int
7197db96d56Sopenharmony_ci
7207db96d56Sopenharmony_ci    GetExtra = py._PyCode_GetExtra
7217db96d56Sopenharmony_ci    GetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t,
7227db96d56Sopenharmony_ci                         ctypes.POINTER(ctypes.c_voidp))
7237db96d56Sopenharmony_ci    GetExtra.restype = ctypes.c_int
7247db96d56Sopenharmony_ci
7257db96d56Sopenharmony_ci    LAST_FREED = None
7267db96d56Sopenharmony_ci    def myfree(ptr):
7277db96d56Sopenharmony_ci        global LAST_FREED
7287db96d56Sopenharmony_ci        LAST_FREED = ptr
7297db96d56Sopenharmony_ci
7307db96d56Sopenharmony_ci    FREE_FUNC = freefunc(myfree)
7317db96d56Sopenharmony_ci    FREE_INDEX = RequestCodeExtraIndex(FREE_FUNC)
7327db96d56Sopenharmony_ci
7337db96d56Sopenharmony_ci    class CoExtra(unittest.TestCase):
7347db96d56Sopenharmony_ci        def get_func(self):
7357db96d56Sopenharmony_ci            # Defining a function causes the containing function to have a
7367db96d56Sopenharmony_ci            # reference to the code object.  We need the code objects to go
7377db96d56Sopenharmony_ci            # away, so we eval a lambda.
7387db96d56Sopenharmony_ci            return eval('lambda:42')
7397db96d56Sopenharmony_ci
7407db96d56Sopenharmony_ci        def test_get_non_code(self):
7417db96d56Sopenharmony_ci            f = self.get_func()
7427db96d56Sopenharmony_ci
7437db96d56Sopenharmony_ci            self.assertRaises(SystemError, SetExtra, 42, FREE_INDEX,
7447db96d56Sopenharmony_ci                              ctypes.c_voidp(100))
7457db96d56Sopenharmony_ci            self.assertRaises(SystemError, GetExtra, 42, FREE_INDEX,
7467db96d56Sopenharmony_ci                              ctypes.c_voidp(100))
7477db96d56Sopenharmony_ci
7487db96d56Sopenharmony_ci        def test_bad_index(self):
7497db96d56Sopenharmony_ci            f = self.get_func()
7507db96d56Sopenharmony_ci            self.assertRaises(SystemError, SetExtra, f.__code__,
7517db96d56Sopenharmony_ci                              FREE_INDEX+100, ctypes.c_voidp(100))
7527db96d56Sopenharmony_ci            self.assertEqual(GetExtra(f.__code__, FREE_INDEX+100,
7537db96d56Sopenharmony_ci                              ctypes.c_voidp(100)), 0)
7547db96d56Sopenharmony_ci
7557db96d56Sopenharmony_ci        def test_free_called(self):
7567db96d56Sopenharmony_ci            # Verify that the provided free function gets invoked
7577db96d56Sopenharmony_ci            # when the code object is cleaned up.
7587db96d56Sopenharmony_ci            f = self.get_func()
7597db96d56Sopenharmony_ci
7607db96d56Sopenharmony_ci            SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(100))
7617db96d56Sopenharmony_ci            del f
7627db96d56Sopenharmony_ci            self.assertEqual(LAST_FREED, 100)
7637db96d56Sopenharmony_ci
7647db96d56Sopenharmony_ci        def test_get_set(self):
7657db96d56Sopenharmony_ci            # Test basic get/set round tripping.
7667db96d56Sopenharmony_ci            f = self.get_func()
7677db96d56Sopenharmony_ci
7687db96d56Sopenharmony_ci            extra = ctypes.c_voidp()
7697db96d56Sopenharmony_ci
7707db96d56Sopenharmony_ci            SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(200))
7717db96d56Sopenharmony_ci            # reset should free...
7727db96d56Sopenharmony_ci            SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(300))
7737db96d56Sopenharmony_ci            self.assertEqual(LAST_FREED, 200)
7747db96d56Sopenharmony_ci
7757db96d56Sopenharmony_ci            extra = ctypes.c_voidp()
7767db96d56Sopenharmony_ci            GetExtra(f.__code__, FREE_INDEX, extra)
7777db96d56Sopenharmony_ci            self.assertEqual(extra.value, 300)
7787db96d56Sopenharmony_ci            del f
7797db96d56Sopenharmony_ci
7807db96d56Sopenharmony_ci        @threading_helper.requires_working_threading()
7817db96d56Sopenharmony_ci        def test_free_different_thread(self):
7827db96d56Sopenharmony_ci            # Freeing a code object on a different thread then
7837db96d56Sopenharmony_ci            # where the co_extra was set should be safe.
7847db96d56Sopenharmony_ci            f = self.get_func()
7857db96d56Sopenharmony_ci            class ThreadTest(threading.Thread):
7867db96d56Sopenharmony_ci                def __init__(self, f, test):
7877db96d56Sopenharmony_ci                    super().__init__()
7887db96d56Sopenharmony_ci                    self.f = f
7897db96d56Sopenharmony_ci                    self.test = test
7907db96d56Sopenharmony_ci                def run(self):
7917db96d56Sopenharmony_ci                    del self.f
7927db96d56Sopenharmony_ci                    self.test.assertEqual(LAST_FREED, 500)
7937db96d56Sopenharmony_ci
7947db96d56Sopenharmony_ci            SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(500))
7957db96d56Sopenharmony_ci            tt = ThreadTest(f, self)
7967db96d56Sopenharmony_ci            del f
7977db96d56Sopenharmony_ci            tt.start()
7987db96d56Sopenharmony_ci            tt.join()
7997db96d56Sopenharmony_ci            self.assertEqual(LAST_FREED, 500)
8007db96d56Sopenharmony_ci
8017db96d56Sopenharmony_ci
8027db96d56Sopenharmony_cidef load_tests(loader, tests, pattern):
8037db96d56Sopenharmony_ci    tests.addTest(doctest.DocTestSuite())
8047db96d56Sopenharmony_ci    return tests
8057db96d56Sopenharmony_ci
8067db96d56Sopenharmony_ci
8077db96d56Sopenharmony_ciif __name__ == "__main__":
8087db96d56Sopenharmony_ci    unittest.main()
809