Commit 0f09a132 authored by Mike Hommey's avatar Mike Hommey
Browse files

Bug 1839263 - Fix python configure lint on python >= 3.10....

Bug 1839263 - Fix python configure lint on python >= 3.10. r=firefox-build-system-reviewers,ahochheiden,sergesanspaille, a=test-only DONTBUILD

Python 3.10 added some more arguments to the CodeTypes constructor. It
also changed co_lnotab to co_linetables.

We were using co_lnotab to simulate a function with a def at a specific
line and a raise at a specific other line. I'm not sure how I ended up
with this particular requirement (this may have been related to python 2
still being used back then), but as of now, it doesn't seem we need the
def to be at a specific location, so we can avoid needing to generate
a co_linetables/co_lnotab, relying instead on the raise expression being
on the co_firstlineno+1 in the thrower function.

As for the extra arguments, it turns out python 3.8 also introduced a
CodeType.replace method that can be used to derive a CodeType object
from another, which is certainly simpler than calling its construtor
with the right set of arguments.

Differential Revision: https://phabricator.services.mozilla.com/D181424
parent 141fbc80
Loading
Loading
Loading
Loading
+35 −32
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@

import inspect
import re
import sys
import types
from dis import Bytecode
from functools import wraps
@@ -23,6 +24,30 @@ from . import (
from .help import HelpFormatter


def code_replace(code, co_filename, co_name, co_firstlineno):
    if sys.version_info < (3, 8):
        codetype_args = [
            code.co_argcount,
            code.co_kwonlyargcount,
            code.co_nlocals,
            code.co_stacksize,
            code.co_flags,
            code.co_code,
            code.co_consts,
            code.co_names,
            code.co_varnames,
            co_filename,
            co_name,
            co_firstlineno,
            code.co_lnotab,
        ]
        return types.CodeType(*codetype_args)
    else:
        return code.replace(
            co_filename=co_filename, co_name=co_name, co_firstlineno=co_firstlineno
        )


class LintSandbox(ConfigureSandbox):
    def __init__(self, environ=None, argv=None, stdout=None, stderr=None):
        out = StringIO()
@@ -68,49 +93,27 @@ class LintSandbox(ConfigureSandbox):
            funcname = obj.__name__
            filename = obj.__code__.co_filename
            firstline = obj.__code__.co_firstlineno
            line += firstline
            line += firstline - 1
        elif inspect.isframe(obj):
            funcname = obj.f_code.co_name
            filename = obj.f_code.co_filename
            firstline = obj.f_code.co_firstlineno
            line = obj.f_lineno
            line = obj.f_lineno - 1
        else:
            # Don't know how to handle the given location, still raise the
            # exception.
            raise exception

        # Create a new function from the above thrower that pretends
        # the `def` line is on the first line of the function given as
        # argument, and the `raise` line is on the line given as argument.

        offset = line - firstline
        # co_lnotab is a string where each pair of consecutive character is
        # (chr(byte_increment), chr(line_increment)), mapping bytes in co_code
        # to line numbers relative to co_firstlineno.
        # If the offset we need to encode is larger than what fits in a 8-bit
        # signed integer, we need to split it.
        co_lnotab = bytes([0, 127] * (offset // 127) + [0, offset % 127])
        code = thrower.__code__
        codetype_args = [
            code.co_argcount,
            code.co_kwonlyargcount,
            code.co_nlocals,
            code.co_stacksize,
            code.co_flags,
            code.co_code,
            code.co_consts,
            code.co_names,
            code.co_varnames,
            filename,
            funcname,
            firstline,
            co_lnotab,
        ]
        if hasattr(code, "co_posonlyargcount"):
            # co_posonlyargcount was introduced in Python 3.8.
            codetype_args.insert(1, code.co_posonlyargcount)
        # the `raise` line is on the line given as argument.

        code = code_replace(
            thrower.__code__,
            co_filename=filename,
            co_name=funcname,
            co_firstlineno=line,
        )

        code = types.CodeType(*codetype_args)
        thrower = types.FunctionType(
            code,
            thrower.__globals__,