Skip to content

types.CodeType regression in Python 3.11 #100316

Closed
@armoha

Description

@armoha

Bug report

# minimal reproducible example
import types
members = [  # 16 members
    "co_argcount", "co_posonlyargcount", "co_kwonlyargcount",
    "co_nlocals", "co_stacksize", "co_flags",
    "co_code", "co_consts", "co_names",
    "co_varnames", "co_filename", "co_name",
    "co_firstlineno", "co_lnotab", "co_freevars",
    "co_cellvars",
]
codeobj = (lambda x: x).__code__
newobj = types.CodeType(*(getattr(codeobj, member) for member in members))
# TypeError: code() argument 13 must be str, not int

I've already asked this on Python user discord server but couldn't get proper answer.

13th argument is codeobj.co_lnotab but putting invalid input (None, "" or b"") does not change the error message, TypeError: code() argument 13 must be str, not int. So I'm guessing there's a mismatch on the order of parameters of types.CodeType and code().

Context

I'm maintaining DSL, which can import Python and vice versa. I need to reconstruct lnotab for correct line numbers for e.g. stacktrace.
I tried using types.CodeType.replace but it does not support co_lnotab.
Original code: https://github.com/armoha/eudplib/blob/master/eudplib/epscript/epsimp.py#L46-L92

def modifyCodeLineno(codeobj, codeMap):
    co_lnotab = codeobj.co_lnotab
    co_firstlineno = codeobj.co_firstlineno

    # Reconstruct code data
    new_lnotab = []
    currentLine = co_firstlineno
    currentMappedLine = codeMap(currentLine)
    for i in range(0, len(co_lnotab), 2):
        bytecodeLen, lineAdvance = co_lnotab[i : i + 2]
        nextLine = currentLine + lineAdvance
        nextMappedLine = codeMap(nextLine)
        newLineAdvance = nextMappedLine - currentMappedLine
        while newLineAdvance >= 0xFF:
            new_lnotab.append(bytes([0, 0xFF]))
            newLineAdvance -= 0xFF
        new_lnotab.append(bytes([bytecodeLen, newLineAdvance]))
        currentLine = nextLine
        currentMappedLine = nextMappedLine

    # For code objects
    new_co_consts = []
    for c in codeobj.co_consts:
        if isinstance(c, types.CodeType):
            c = modifyCodeLineno(c, codeMap)
        new_co_consts.append(c)

    codeobj = types.CodeType(
        codeobj.co_argcount,
        codeobj.co_posonlyargcount,  # python 3.8 support (See PEP 570)
        codeobj.co_kwonlyargcount,
        codeobj.co_nlocals,
        codeobj.co_stacksize,
        codeobj.co_flags,
        codeobj.co_code,
        tuple(new_co_consts),
        codeobj.co_names,
        codeobj.co_varnames,
        codeobj.co_filename,
        codeobj.co_name,
        codeMap(co_firstlineno),  # codeobj.co_firstlineno,
        b"".join(new_lnotab),  # codeobj.co_lnotab,
        codeobj.co_freevars,
        codeobj.co_cellvars,
    )

    return codeobj

Your environment

  • CPython versions tested on: Python 3.11.1 (works fine on Python 3.7~10)
  • Operating system and architecture: Windows amd64

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions