10000 bpo-37032: Add CodeType.replace() method (GH-13542) · python/cpython@a9f05d6 · GitHub
[go: up one dir, main page]

Skip to content

Commit a9f05d6

Browse files
authored
bpo-37032: Add CodeType.replace() method (GH-13542)
1 parent 561612d commit a9f05d6

File tree

8 files changed

+401
-33
lines changed
  • Doc/whatsnew
  • Lib
  • Misc/NEWS.d/next/Core and Builtins
  • Objects
  • 8 files changed

    +401
    -33
    lines changed

    Doc/whatsnew/3.8.rst

    Lines changed: 5 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -240,6 +240,9 @@ Other Language Changes
    240240
    and Windows use this to properly terminate scripts in interactive sessions.
    241241
    (Contributed by Google via Gregory P. Smith in :issue:`1054041`.)
    242242

    243+
    * Added new ``replace()`` method to the code type (:class:`types.CodeType`).
    244+
    (Contributed by Victor Stinner in :issue:`37032`.)
    245+
    243246

    244247
    New Modules
    245248
    ===========
    @@ -1051,7 +1054,8 @@ Changes in the Python API
    10511054

    10521055
    * :class:`types.CodeType` has a new parameter in the second position of the
    10531056
    constructor (*posonlyargcount*) to support positional-only arguments defined
    1054-
    in :pep:`570`.
    1057+
    in :pep:`570`. A new ``replace()`` method of :class:`types.CodeType` can be
    1058+
    used to make the code future-proof.
    10551059

    10561060

    10571061
    Changes in the C API

    Lib/modulefinder.py

    Lines changed: 1 addition & 7 deletions
    Original file line numberDiff line numberDiff line change
    @@ -619,13 +619,7 @@ def replace_paths_in_code(self, co):
    619619
    if isinstance(consts[i], type(co)):
    620620
    consts[i] = self.replace_paths_in_code(consts[i])
    621621

    622-
    return types.CodeType(co.co_argcount, co.co_posonlyargcount,
    623-
    co.co_kwonlyargcount, co.co_nlocals,
    624-
    co.co_stacksize, co.co_flags,
    625-
    co.co_code, tuple(consts), co.co_names,
    626-
    co.co_varnames, new_filename, co.co_name,
    627-
    co.co_firstlineno, co.co_lnotab, co.co_freevars,
    628-
    co.co_cellvars)
    622+
    return co.replace(co_consts=tuple(consts), co_filename=new_filename)
    629623

    630624

    631625
    def test():

    Lib/test/test_code.py

    Lines changed: 60 additions & 6 deletions
    Original file line numberDiff line numberDiff line change
    @@ -174,18 +174,14 @@ def test_newempty(self):
    174174
    @cpython_only
    175175
    def test_closure_injection(self):
    176176
    # From https://bugs.python.org/issue32176
    177-
    from types import FunctionType, CodeType
    177+
    from types import FunctionType
    178178

    179179
    def create_closure(__class__):
    180180
    return (lambda: __class__).__closure__
    181181

    182182
    def new_code(c):
    183183
    '''A new code object with a __class__ cell added to freevars'''
    184-
    return CodeType(
    185-
    c.co_argcount, c.co_posonlyargcount, c.co_kwonlyargcount, c.co_nlocals,
    186-
    c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names,
    187-
    c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno,
    188-
    c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)
    184+
    return c.replace(co_freevars=c.co_freevars + ('__class__',))
    189185

    190186
    def add_foreign_method(cls, name, f):
    191187
    code = new_code(f.__code__)
    @@ -212,6 +208,64 @@ class List(list):
    212208
    obj = List([1, 2, 3])
    213209
    self.assertEqual(obj[0], "Foreign getitem: 1")
    214210

    211+
    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+
    215269
    def isinterned(s):
    216270
    return s is sys.intern(('_' + s + '_')[1:-1])
    217271

    Lib/test/test_import/__init__.py

    Lines changed: 1 addition & 7 deletions
    Original file line numberDiff line numberDiff line change
    @@ -674,13 +674,7 @@ def test_foreign_code(self):
    674674
    foreign_code = importlib.import_module.__code__
    675675
    pos = constants.index(1)
    676676
    constants[pos] = foreign_code
    677-
    code = type(code)(code.co_argcount, code.co_posonlyargcount,
    678-
    code.co_kwonlyargcount,
    679-
    code.co_nlocals, code.co_stacksize,
    680-
    code.co_flags, code.co_code, tuple(constants),
    681-
    code.co_names, code.co_varnames, code.co_filename,
    682-
    code.co_name, code.co_firstlineno, code.co_lnotab,
    683-
    code.co_freevars, code.co_cellvars)
    677+
    code = code.replace(co_consts=tuple(constants))
    684678
    with open(self.compiled_name, "wb") as f:
    685679
    f.write(header)
    686680
    marshal.dump(code, f)

    Lib/types.py

    Lines changed: 2 additions & 8 deletions
    Original file line numberDiff line numberDiff line change
    @@ -262,14 +262,8 @@ def coroutine(func):
    262262
    if co_flags & 0x20:
    263263
    # TODO: Implement this in C.
    264264
    co = func.__code__
    265-
    func.__code__ = CodeType(
    266-
    co.co_argcount, co.co_posonlyargcount, co.co_kwonlyargcount, co.co_nlocals,
    267-
    co.co_stacksize,
    268-
    co.co_flags | 0x100, # 0x100 == CO_ITERABLE_COROUTINE
    269-
    co.co_code,
    270-
    co.co_consts, co.co_names, co.co_varnames, co.co_filename,
    271-
    co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars,
    272-
    co.co_cellvars)
    265+
    # 0x100 == CO_ITERABLE_COROUTINE
    266+
    func.__code__ = co.replace(co_flags=co.co_flags | 0x100)
    273267
    return func
    274268

    275269
    # The following code is primarily to support functions that
    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1 @@
    1+
    Added new ``replace()`` method to the code type (:class:`types.CodeType`).

    0 commit comments

    Comments
     (0)
    0