mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Crash on `run_in_executor`

Open michaeljpeters opened this issue 10 months ago • 0 comments

Mypy crashes on loop.run_in_executor with the message "Parameters cannot be constrained to"

(A clear and concise description of what the bug is.)

Run mypy aio_processes.py

aio_processes.py:

import asyncio
import typing as tp
from concurrent.futures import ProcessPoolExecutor

P = tp.ParamSpec("P")
R = tp.TypeVar("R")


# additional wrapper since run_in_executor doesn't accept kwargs
def _call(
    func: tp.Callable[..., R],
    args: tp.Any,
    kwargs: tp.Any,
) -> R:
    return func(*args, **kwargs)


async def to_process(func: tp.Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R:
    """
    execute a function in a subprocess managed by asyncio

    WARNING: args and kwargs will be pickled to be sent to the subprocess
             this can be expensive, especially if you are sending large data structures (i.e. DataFrames)

    NOTE:    asyncio provides a similar function, `to_thread`, which is useful to take advantage of
             the event loop for IO-bound code, without needing to pickle args and kwargs
    """
    with ProcessPoolExecutor(max_workers=1) as ppe:
        loop = asyncio.get_running_loop()
        result = await loop.run_in_executor(ppe, _call, func, args, kwargs)
    return result

Expected Behavior

Mypy type-checks the file

Actual Behavior

Mypy crashes

$ mypy aio_processes.py --show-traceback
aio_processes.py:30: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 1.10.0+dev.e2fc1f28935806ca04b18fab277217f583b51594
Traceback (most recent call last):
  File "/home/peters/src-me/proc_aio_mypy/venv/bin/mypy", line 8, in <module>
    sys.exit(console_entry())
  File "/home/peters/src-others/mypy/mypy/__main__.py", line 15, in console_entry
    main()
  File "/home/peters/src-others/mypy/mypy/main.py", line 100, in main
    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
  File "/home/peters/src-others/mypy/mypy/main.py", line 182, in run_build
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File "/home/peters/src-others/mypy/mypy/build.py", line 192, in build
    result = _build(
  File "/home/peters/src-others/mypy/mypy/build.py", line 266, in _build
    graph = dispatch(sources, manager, stdout)
  File "/home/peters/src-others/mypy/mypy/build.py", line 2942, in dispatch
    process_graph(graph, manager)
  File "/home/peters/src-others/mypy/mypy/build.py", line 3340, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/home/peters/src-others/mypy/mypy/build.py", line 3441, in process_stale_scc
    graph[id].type_check_first_pass()
  File "/home/peters/src-others/mypy/mypy/build.py", line 2310, in type_check_first_pass
    self.type_checker().check_first_pass()
  File "/home/peters/src-others/mypy/mypy/checker.py", line 481, in check_first_pass
    self.accept(d)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 589, in accept
    stmt.accept(self)
  File "/home/peters/src-others/mypy/mypy/nodes.py", line 787, in accept
    return visitor.visit_func_def(self)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 1000, in visit_func_def
    self._visit_func_def(defn)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 1004, in _visit_func_def
    self.check_func_item(defn, name=defn.name)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 1077, in check_func_item
    self.check_func_def(defn, typ, name, allow_empty)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 1309, in check_func_def
    self.accept(item.body)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 589, in accept
    stmt.accept(self)
  File "/home/peters/src-others/mypy/mypy/nodes.py", line 1223, in accept
    return visitor.visit_block(self)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 2802, in visit_block
    self.accept(s)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 589, in accept
    stmt.accept(self)
  File "/home/peters/src-others/mypy/mypy/nodes.py", line 1579, in accept
    return visitor.visit_with_stmt(self)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 5033, in visit_with_stmt
    self.accept(s.body)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 589, in accept
    stmt.accept(self)
  File "/home/peters/src-others/mypy/mypy/nodes.py", line 1223, in accept
    return visitor.visit_block(self)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 2802, in visit_block
    self.accept(s)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 589, in accept
    stmt.accept(self)
  File "/home/peters/src-others/mypy/mypy/nodes.py", line 1310, in accept
    return visitor.visit_assignment_stmt(self)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 2850, in visit_assignment_stmt
    self.check_assignment(s.lvalues[-1], s.rvalue, s.type is None, s.new_syntax)
  File "/home/peters/src-others/mypy/mypy/checker.py", line 3058, in check_assignment
    rvalue_type = self.expr_checker.accept(rvalue, type_context=type_context)
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 5760, in accept
    typ = node.accept(self)
  File "/home/peters/src-others/mypy/mypy/nodes.py", line 2763, in accept
    return visitor.visit_await_expr(self)
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 5893, in visit_await_expr
    actual_type = get_proper_type(self.accept(e.expr, expected_type))
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 5760, in accept
    typ = node.accept(self)
          ^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/nodes.py", line 1907, in accept
    return visitor.visit_call_expr(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 476, in visit_call_expr
    return self.visit_call_expr_inner(e, allow_none_return=allow_none_return)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 605, in visit_call_expr_inner
    ret_type = self.check_call_expr_with_callee_type(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 1456, in check_call_expr_with_callee_type
    ret_type, callee_type = self.check_call(
                            ^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 1550, in check_call
    return self.check_callable_call(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 1735, in check_callable_call
    callee = self.infer_function_type_arguments(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/checkexpr.py", line 2123, in infer_function_type_arguments
    poly_inferred_args, free_vars = infer_function_type_arguments(
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/infer.py", line 62, in infer_function_type_arguments
    return solve_constraints(type_vars, constraints, strict, allow_polymorphic)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/solve.py", line 84, in solve_constraints
    solutions, free_vars = solve_with_dependent(
                           ^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/solve.py", line 144, in solve_with_dependent
    graph, lowers, uppers = transitive_closure(vars, constraints)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/solve.py", line 446, in transitive_closure
    add_secondary_constraints(remaining, lt, c.target)
  File "/home/peters/src-others/mypy/mypy/solve.py", line 470, in add_secondary_constraints
    cs.update(set(infer_constraints(upper, lower, SUPERTYPE_OF)))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/constraints.py", line 314, in infer_constraints
    return _infer_constraints(template, actual, direction, skip_neg_op)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/constraints.py", line 407, in _infer_constraints
    return template.accept(ConstraintBuilderVisitor(actual, direction, skip_neg_op))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/types.py", line 1730, in accept
    return visitor.visit_parameters(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peters/src-others/mypy/mypy/constraints.py", line 698, in visit_parameters
    raise RuntimeError("Parameters cannot be constrained to")
RuntimeError: Parameters cannot be constrained to
aio_processes.py:30: : note: use --pdb to drop into pdb

Your Environment

$ pip freeze
-e file:///.../mypy
mypy-extensions==1.0.0
typing-extensions==4.11.0
  • Mypy version used: mypy 1.10.0+dev.e2fc1f28935806ca04b18fab277217f583b51594 (compiled: no)
    • This also fails on 1.9.0
  • Mypy command-line flags: --show-traceback
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.11.4

michaeljpeters avatar Apr 12 '24 17:04 michaeljpeters