Bug 2488363 - python-executing fails to build with Python 3.15: executing._exceptions.VerifierFailure: ast.Name is not created from CALL
Summary: python-executing fails to build with Python 3.15: executing._exceptions.Verif...
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: python-executing
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Paul Wouters
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks: PYTHON3.15 F45FTBFS, RAWHIDEFTBFS
TreeView+ depends on / blocked
 
Reported: 2026-06-12 14:37 UTC by Karolina Surma
Modified: 2026-06-13 17:14 UTC (History)
5 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2026-06-13 17:14:45 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Karolina Surma 2026-06-12 14:37:23 UTC
python-executing fails to build with Python 3.15.0b2.

16 tests failed:

_________________________ TestFiles.test_module_files __________________________
self = <tests.test_main.TestFiles object at 0x7fa12c007d10>
    def test_module_files(self):
        self.start_time = time.time()
    
        modules = list(sys.modules.values())
        shuffle(modules)
        for module in modules:
            try:
                filename = inspect.getsourcefile(module)
            except TypeError:
                continue
    
            except AttributeError as error:
                if str(error)== "'_SixMetaPathImporter' object has no attribute '_path'":
                    # work around for https://github.com/benjaminp/six/issues/376
                    continue
                raise
    
            if not filename:
                continue
    
            filename = os.path.abspath(filename)
    
            if (
                    # The sentinel actually appearing in code messes things up
                    'executing' in filename
                    # because of: {t[0] for t in lines2} - {t[0] for t in lines1}
                    or 'pytester.py' in filename
                    # A file that's particularly slow
                    or 'errorcodes.py' in filename
                    # Contains unreachable code which pypy removes
                    or PYPY and (
                        'sysconfig.py' in filename
                        or 'pyparsing.py' in filename
                        or 'enum' in filename
                    )
                    or sys.version_info < (3,11) and (
                        'python.py' in filename
                    )
            ):
                continue
    
            with open(filename) as source:
                source_text = source.read()
                if PYPY and "__debug__" in source_text:
                    continue
    
    
            try:
>               self.check_filename(filename, check_names=False)
tests/test_main.py:823: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/test_main.py:885: in check_filename
    result = list(self.check_code(code, nodes, decorators, check_names=check_names))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/test_main.py:1462: in check_code
    for x in self.check_code(inst.argval, nodes, decorators, check_names=check_names):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/test_main.py:1462: in check_code
    for x in self.check_code(inst.argval, nodes, decorators, check_names=check_names):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/test_main.py:1241: in check_code
    ex = Source.executing(frame)
         ^^^^^^^^^^^^^^^^^^^^^^^
executing/executing.py:233: in executing
    node_finder = NodeFinder(frame, stmts, tree, lasti, source)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
executing/_position_node_finder.py:128: in __init__
    self.verify(self.result, instruction)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <executing._position_node_finder.PositionNodeFinder object at 0x7fa126722190>
node = Name(id='self', ctx=Load())
instruction = Instruction(opname='CALL', opcode=50, arg=3, argval=3, argrepr='', offset=378, start_offset=378, starts_line=False, li... col_offset=17, end_col_offset=21), cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')])
    def verify(self, node: EnhancedAST, instruction: dis.Instruction) -> None:
        """
        checks if this node could gererate this instruction
        """
    
        op_name = instruction.opname
        extra_filter: Callable[[EnhancedAST], bool] = lambda e: True
        ctx: Type = type(None)
    
        def inst_match(opnames: Union[str, Sequence[str]], **kwargs: Any) -> bool:
            """
            match instruction
    
            Parameters:
                opnames: (str|Seq[str]): inst.opname has to be equal to or in `opname`
                **kwargs: every arg has to match inst.arg
    
            Returns:
                True if all conditions match the instruction
    
            """
    
            if isinstance(opnames, str):
                opnames = [opnames]
            return instruction.opname in opnames and kwargs == {
                k: getattr(instruction, k) for k in kwargs
            }
    
        def node_match(node_type: Union[Type, Tuple[Type, ...]], **kwargs: Any) -> bool:
            """
            match the ast-node
    
            Parameters:
                node_type: type of the node
                **kwargs: every `arg` has to be equal `node.arg`
                        or `node.arg` has to be an instance of `arg` if it is a type.
            """
            return isinstance(node, node_type) and all(
                isinstance(getattr(node, k), v)
                if isinstance(v, type)
                else getattr(node, k) == v
                for k, v in kwargs.items()
            )
    
        if op_name == "CACHE":
            return
    
        if inst_match("CALL") and node_match((ast.With, ast.AsyncWith)):
            # call to context.__exit__
            return
    
        if inst_match(("CALL", "LOAD_FAST","LOAD_FAST_BORROW")) and node_match(
            (ast.ListComp, ast.GeneratorExp, ast.SetComp, ast.DictComp)
        ):
            # call to the generator function
            return
    
        if (
            sys.version_info >= (3, 12)
            and inst_match(("LOAD_FAST_AND_CLEAR", "STORE_FAST"))
            and node_match((ast.ListComp, ast.SetComp, ast.DictComp))
        ):
            return
    
        if inst_match(("CALL", "CALL_FUNCTION_EX")) and node_match(
            (ast.ClassDef, ast.Call)
        ):
            return
    
        if inst_match(("COMPARE_OP", "IS_OP", "CONTAINS_OP")) and node_match(
            ast.Compare
        ):
            return
    
        if inst_match("LOAD_NAME", argval="__annotations__") and node_match(
            ast.AnnAssign
        ):
            return
    
        if (
            (
                inst_match("LOAD_METHOD", argval="join")
                or inst_match("LOAD_ATTR", argval="join")  # 3.12
                or inst_match(("CALL", "BUILD_STRING"))
            )
            and node_match(ast.BinOp, left=ast.Constant, op=ast.Mod)
            and isinstance(cast(ast.Constant, cast(ast.BinOp, node).left).value, str)
        ):
            # "..."%(...) uses "".join
            return
    
        if inst_match("STORE_SUBSCR") and node_match(ast.AnnAssign):
            # data: int
            return
    
    
        if inst_match(("DELETE_NAME", "DELETE_FAST")) and node_match(
            ast.Name, id=instruction.argval, ctx=ast.Del
        ):
            return
    
        if inst_match("BUILD_STRING") and (
            node_match(ast.JoinedStr) or node_match(ast.BinOp, op=ast.Mod)
        ):
            return
    
        if inst_match(("BEFORE_WITH","WITH_EXCEPT_START")) and node_match(ast.With):
            return
    
        if inst_match(("STORE_NAME", "STORE_GLOBAL"), argval="__doc__") and node_match(
            ast.Constant
        ):
            # store docstrings
            return
    
        if (
            inst_match(("STORE_NAME", "STORE_FAST", "STORE_GLOBAL", "STORE_DEREF"))
            and node_match(ast.ExceptHandler)
            and instruction.argval == mangled_name(node)
        ):
            # store exception in variable
            return
    
        if (
            inst_match(("STORE_NAME", "STORE_FAST", "STORE_DEREF", "STORE_GLOBAL"))
            and node_match((ast.Import, ast.ImportFrom))
            and any(mangled_name(cast(EnhancedAST, alias)) == instruction.argval for alias in cast(ast.Import, node).names)
        ):
            # store imported module in variable
            return
    
        if (
            inst_match(("STORE_FAST", "STORE_DEREF", "STORE_NAME", "STORE_GLOBAL"))
            and (
                node_match((ast.FunctionDef, ast.ClassDef, ast.AsyncFunctionDef))
                or node_match(
                    ast.Name,
                    ctx=ast.Store,
                )
            )
            and instruction.argval == mangled_name(node)
        ):
            return
    
        if False:
            # TODO: match expressions are not supported for now
            if inst_match(("STORE_FAST", "STORE_NAME")) and node_match(
                ast.MatchAs, name=instruction.argval
            ):
                return
    
            if inst_match("COMPARE_OP", argval="==") and node_match(ast.MatchSequence):
                return
    
            if inst_match("COMPARE_OP", argval="==") and node_match(ast.MatchValue):
                return
    
        if inst_match("BINARY_OP"):
            arg=instruction.argrepr.removesuffix("=")
    
            if arg!="[]" and node_match( ast.AugAssign, op=op_type_map[arg]):
                # a+=5
                return
    
        if node_match(ast.Attribute, ctx=ast.Del) and inst_match(
            "DELETE_ATTR", argval=mangled_name(node)
        ):
            return
    
        if inst_match(
            (
                "JUMP_IF_TRUE_OR_POP",
                "JUMP_IF_FALSE_OR_POP",
                "POP_JUMP_IF_TRUE",
                "POP_JUMP_IF_FALSE",
            )
        ) and node_match(ast.BoolOp):
            # and/or short circuit
            return
    
        if inst_match("DELETE_SUBSCR") and node_match(ast.Subscript, ctx=ast.Del):
            return
    
        if (
            node_match(ast.Name, ctx=ast.Load)
            or (
                node_match(ast.Name, ctx=ast.Store)
                and isinstance(node.parent, ast.AugAssign)
            )
        ) and inst_match(
            (
                "LOAD_NAME",
                "LOAD_FAST",
                "LOAD_FAST_CHECK",
                "LOAD_FAST_BORROW",
                "LOAD_GLOBAL",
                "LOAD_DEREF",
                "LOAD_FROM_DICT_OR_DEREF",
                "LOAD_FAST_BORROW_LOAD_FAST_BORROW",
            ),
        ) and (
            mangled_name(node) in instruction.argval if isinstance(instruction.argval,tuple)
            else instruction.argval == mangled_name(node)
        ):
            return
    
        if node_match(ast.Name, ctx=ast.Del) and inst_match(
            ("DELETE_NAME", "DELETE_GLOBAL", "DELETE_DEREF"), argval=mangled_name(node)
        ):
            return
    
        if node_match(ast.Constant) and inst_match(
            ("LOAD_CONST","LOAD_SMALL_INT"), argval=cast(ast.Constant, node).value
        ):
            return
    
        if node_match(
            (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp, ast.For)
        ) and inst_match(("GET_ITER", "FOR_ITER")):
            return
    
        if sys.version_info >= (3, 12):
            if node_match(ast.UnaryOp, op=ast.UAdd) and inst_match(
                "CALL_INTRINSIC_1", argrepr="INTRINSIC_UNARY_POSITIVE"
            ):
                return
    
            if node_match(ast.Subscript) and inst_match("BINARY_SLICE"):
                return
    
            if node_match(ast.ImportFrom) and inst_match(
                "CALL_INTRINSIC_1", argrepr="INTRINSIC_IMPORT_STAR"
            ):
                return
    
            if (
                node_match(ast.Yield) or isinstance(node.parent, ast.GeneratorExp)
            ) and inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_ASYNC_GEN_WRAP"):
                return
    
            if node_match(ast.Name) and inst_match("LOAD_DEREF",argval="__classdict__"):
                return
    
            if node_match(ast.TypeVar) and (
                inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_TYPEVAR")
                or inst_match(
                    "CALL_INTRINSIC_2", argrepr="INTRINSIC_TYPEVAR_WITH_BOUND"
                )
                or inst_match(
                    "CALL_INTRINSIC_2", argrepr="INTRINSIC_TYPEVAR_WITH_CONSTRAINTS"
                )
                or inst_match(("STORE_FAST", "STORE_DEREF"), argrepr=mangled_name(node))
            ):
                return
    
            if node_match(ast.TypeVarTuple) and (
                inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_TYPEVARTUPLE")
                or inst_match(("STORE_FAST", "STORE_DEREF"), argrepr=node.name)
            ):
                return
    
            if node_match(ast.ParamSpec) and (
                inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_PARAMSPEC")
    
                or inst_match(("STORE_FAST", "STORE_DEREF"), argrepr=node.name)):
                return
    
    
            if node_match(ast.TypeAlias):
                if(
                    inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_TYPEALIAS")
                    or inst_match(
                        ("STORE_NAME", "STORE_FAST", "STORE_DEREF","STORE_GLOBAL"), argrepr=node.name.id
                    )
                    or inst_match("CALL")
                ):
                    return
    
    
            if node_match(ast.ClassDef) and node.type_params:
                if inst_match(
                    ("STORE_DEREF", "LOAD_DEREF", "LOAD_FROM_DICT_OR_DEREF"),
                    argrepr=".type_params",
                ):
                    return
    
                if inst_match(("STORE_FAST", "LOAD_FAST"), argrepr=".generic_base"):
                    return
    
                if inst_match(
                    "CALL_INTRINSIC_1", argrepr="INTRINSIC_SUBSCRIPT_GENERIC"
                ):
                    return
    
                if inst_match("LOAD_DEREF",argval="__classdict__"):
                    return
    
            if node_match((ast.FunctionDef,ast.AsyncFunctionDef)) and node.type_params:
                if inst_match("CALL"):
                    return
    
                if inst_match(
                    "CALL_INTRINSIC_2", argrepr="INTRINSIC_SET_FUNCTION_TYPE_PARAMS"
                ):
                    return
    
                if inst_match("LOAD_FAST",argval=".defaults"):
                    return
    
                if inst_match("LOAD_FAST",argval=".kwdefaults"):
                    return
    
                if sys.version_info >= (3, 14):
                    if inst_match("LOAD_FAST_BORROW_LOAD_FAST_BORROW",argval=(".defaults",".kwdefaults")):
                        return
    
            if inst_match("STORE_NAME", argval="__classdictcell__"):
                # this is a general thing
                return
    
    
            # f-strings
    
            if node_match(ast.JoinedStr) and (
                inst_match("LOAD_ATTR", argval="join")
                or inst_match(("LIST_APPEND", "CALL"))
            ):
                return
    
            if node_match(ast.FormattedValue) and inst_match("FORMAT_VALUE"):
                return
    
        if sys.version_info >= (3, 13):
    
            if inst_match("NOP"):
                return
    
            if inst_match("TO_BOOL") and node_match(ast.BoolOp):
                return
    
            if inst_match("CALL_KW") and node_match((ast.Call, ast.ClassDef)):
                return
    
            if inst_match("LOAD_FAST", argval=".type_params"):
                return
    
            if inst_match("LOAD_FAST", argval="__classdict__"):
                return
    
            if inst_match(("LOAD_FAST","LOAD_FAST_BORROW")) and node_match(
                (
                    ast.FunctionDef,
                    ast.ClassDef,
                    ast.TypeAlias,
                    ast.TypeVar,
                    ast.Lambda,
                    ast.AsyncFunctionDef,
                )
            ):
                # These are loads for closure variables.
                # It is difficult to check that this is actually closure variable, see:
                # https://github.com/alexmojaki/executing/pull/80#discussion_r1716027317
                return
    
            if (
                inst_match("LOAD_FAST")
                and node_match(ast.TypeAlias)
                and node.name.id == instruction.argval
            ):
                return
    
            if inst_match("STORE_NAME",argval="__static_attributes__"):
                # the node is the first node in the body
                return
    
            if inst_match(("LOAD_FAST","LOAD_FAST_BORROW")) and isinstance(node.parent,ast.TypeVar):
                return
    
            if inst_match("CALL_INTRINSIC_2",argrepr="INTRINSIC_SET_TYPEPARAM_DEFAULT") and node_match((ast.TypeVar,ast.ParamSpec,ast.TypeVarTuple)):
                return
    
        if sys.version_info >= (3, 14):
            if inst_match("BINARY_OP",argrepr="[]") and node_match(ast.Subscript):
                return
            if inst_match("LOAD_FAST_BORROW", argval="__classdict__"):
                return
            if inst_match(("STORE_NAME","LOAD_NAME"), argval="__conditional_annotations__"):
                return
    
            if inst_match("LOAD_FAST_BORROW_LOAD_FAST_BORROW") and node_match(ast.Name) and node.id in instruction.argval:
                return
    
        if sys.version_info >= (3, 15):
            if (
                inst_match(("LOAD_FAST", "LOAD_FAST_BORROW"), argval=".0")
                and isinstance(node.parent, ast.comprehension)
                and node is node.parent.iter
            ):
                # In Python 3.15, the LOAD_FAST/LOAD_FAST_BORROW .0 instruction
                # (which loads the hidden iterator parameter in comprehensions/generator
                # expressions) has source positions that match the iterator expression
                return
    
    
        # old verifier
    
        typ: Type = type(None)
        op_type: Type = type(None)
    
        if op_name.startswith(("BINARY_SUBSCR", "SLICE+")):
            typ = ast.Subscript
            ctx = ast.Load
        elif op_name.startswith("BINARY_"):
            typ = ast.BinOp
            op_type = op_type_map[instruction.argrepr]
            extra_filter = lambda e: isinstance(cast(ast.BinOp, e).op, op_type)
        elif op_name.startswith("UNARY_"):
            typ = ast.UnaryOp
            op_type = dict(
                UNARY_POSITIVE=ast.UAdd,
                UNARY_NEGATIVE=ast.USub,
                UNARY_NOT=ast.Not,
                UNARY_INVERT=ast.Invert,
            )[op_name]
            extra_filter = lambda e: isinstance(cast(ast.UnaryOp, e).op, op_type)
        elif op_name in ("LOAD_ATTR", "LOAD_METHOD", "LOOKUP_METHOD","LOAD_SUPER_ATTR"):
            typ = ast.Attribute
            ctx = ast.Load
            extra_filter = lambda e: mangled_name(e) == instruction.argval
        elif op_name in (
            "LOAD_NAME",
            "LOAD_GLOBAL",
            "LOAD_FAST",
            "LOAD_DEREF",
            "LOAD_CLASSDEREF",
        ):
            typ = ast.Name
            ctx = ast.Load
            extra_filter = lambda e: cast(ast.Name, e).id == instruction.argval
        elif op_name in ("COMPARE_OP", "IS_OP", "CONTAINS_OP"):
            typ = ast.Compare
            extra_filter = lambda e: len(cast(ast.Compare, e).ops) == 1
        elif op_name.startswith(("STORE_SLICE", "STORE_SUBSCR")):
            ctx = ast.Store
            typ = ast.Subscript
        elif op_name.startswith("STORE_ATTR"):
            ctx = ast.Store
            typ = ast.Attribute
            extra_filter = lambda e: mangled_name(e) == instruction.argval
    
        node_ctx = getattr(node, "ctx", None)
    
        ctx_match = (
            ctx is not type(None)
            or not hasattr(node, "ctx")
            or isinstance(node_ctx, ctx)
        )
    
        # check for old verifier
        if isinstance(node, typ) and ctx_match and extra_filter(node):
            return
    
        # generate error
    
        title = "ast.%s is not created from %s" % (
            type(node).__name__,
            instruction.opname,
        )
    
>       raise VerifierFailure(title, node, instruction)
E       executing._exceptions.VerifierFailure: ast.Name is not created from CALL
executing/_position_node_finder.py:1003: VerifierFailure
----------------------------- Captured stdout call -----------------------------
check /usr/lib64/python3.15/json/__init__.py
check /usr/lib64/python3.15/abc.py
check /usr/lib64/python3.15/asyncio/timeouts.py
check /usr/lib64/python3.15/annotationlib.py
check /usr/lib64/python3.15/re/__init__.py
check /usr/lib64/python3.15/keyword.py
check /usr/lib/python3.15/site-packages/_pytest/_py/error.py
check /usr/lib64/python3.15/xml/__init__.py
check /usr/lib64/python3.15/bz2.py
check /usr/lib64/python3.15/asyncio/sslproto.py
check /usr/lib64/python3.15/posixpath.py
check /usr/lib64/python3.15/re/_casefix.py
check /usr/lib64/python3.15/__future__.py
check /usr/lib64/python3.15/importlib/resources/abc.py
check /usr/lib/python3.15/site-packages/_pytest/_py/error.py
check /usr/lib64/python3.15/argparse.py
check /usr/lib64/python3.15/unittest/case.py
VerifierFailure:
ast.Name is not created from CALL
instruction:      CALL                     3
node: Name(id='self', lineno=244, col_offset=17, end_lineno=244, end_col_offset=21)
parent node: withitem
source code:
 240:             try:
 241:                 self.obj_name = callable_obj.__name__
 242:             except AttributeError:
 243:                 self.obj_name = str(callable_obj)
 244:             with self:
 245:                 callable_obj(*args, **kwargs)
 246:         finally:
 247:             # bpo-23890: manually break a reference cycle
 248:             self = None
 249: 
None
bytecode:
https://docs.python.org/3.15/whatsnew/3.15.html

For our attempts to build python-executing with Python 3.15, see:
https://koji.fedoraproject.org/koji/search?terms=python-executing&type=package&match=exact

Let us know here if you have any questions.

Python 3.15 is planned to be included in Fedora 45.
To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.15.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires),
so if this package is required a lot, it's important for us to get it fixed soon.

We'd appreciate help from the people who know this package best,
but if you don't want to work on this now, let us know so we can try to work around it on our side.


Note You need to log in before you can comment on or make changes to this bug.