Crash with variadic type variable

Đang mở
#21,778 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
python
Lĩnh vực
compilers, devtools

Hướng nghiên cứu

Tái hiện test.py được cung cấp bằng mypy --show-traceback, sau đó lần theo đường đi của lỗi từ checker.py:check_with_item qua checkexpr.py:visit_call_expr và visit_call_expr_inner. Traceback và báo cáo xác định đường đi của sự cố; hoàn tất khi ví dụ kiểu variadic này không còn tạo ra INTERNAL ERROR hoặc traceback.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

crash topic-pep-646

Crash Report

I was writing some code in Colab and INTERNAL_ERROR showed up

This is the code:
%%mypy
from collections.abc import Callable, Mapping, MutableMapping, Iterator, Iterable
from typing import Any, Self, NoReturn, Concatenate, overload, TYPE_CHECKING, cast, TypeVar, final, Literal, Protocol
from typing_extensions import disjoint_base, TypeForm
from functools import wraps
from types import MethodType as method, TracebackType
import sys

@disjoint_base
class cached[**P, R]:
slots = ("_f", "_c")
def init(self, func: Callable[P, R]) -> None:
if not hasattr(self, "_f"):
self._f = func
self._c = {} # type: ignore[var-annotated]

@property
def cache(self) -> dict[tuple[tuple, frozenset[tuple[str, Any]]], R]:
return self._c

def call(self, *args: P.args, **kwargs: P.kwargs) -> R:
compd = (args, frozenset(kwargs.items()))
if compd in self._c:
return self._c[compd]

else:
  result = self._f(*args, **kwargs)
  self._c[compd] = result
  return result

def repr(self) -> str:
return self._f.name

@disjoint_base
class cached_method[T, **P, R]:
slots = ("_f", "_c")
def init(self, func: Callable[Concatenate[T, P], R]) -> None:
if not hasattr(self, "_f"):
self._f = func
self._c = {} # type: ignore[var-annotated]

@property
def cache(self) -> dict[tuple[T, tuple[Any, ...], frozenset[tuple[str, Any]]], R]:
return self._c

def call(self, instance: T, /, *args: P.args, **kwargs: P.kwargs) -> R:
compd = (instance, args, frozenset(kwargs.items()))
if compd in self._c:
return self._c[compd]

else:
  result = self._f(instance, *args, **kwargs)
  self._c[compd] = result
  return result

def repr(self) -> str:
return self._f.name

@overload
def get(self, instance: None, owner: type[T]) -> Self: ...
@overload
def get(self, instance: T, owner: type[T]) -> cached: ...
def get(self, instance: T | None, owner: type[T]):
@cached
def _cached_method_get(self, instance, owner):
if instance is None:
return self

  else:
    return cached(method(self._f, instance))

return _cached_method_get(self, instance, owner)

def notimplemented[**P](func: Callable[P, Any]) -> Callable[P, NoReturn]:
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> NoReturn:
raise NotImplementedError

return wrapper

type _BinaryMethod[T, N] = Callable[[T, N], bool]
def typeguard[T](cls: type[T]) -> Callable[[_BinaryMethod[T, T]], BinaryMethod[T, object]]:
def dec(method
: _BinaryMethod[T, T]) -> BinaryMethod[T, object]:
@wraps(method
)
def wrapper(self_param, other: object) -> bool:
if not isinstance(other, cls):
return NotImplemented

  else:
    return method_(self_param, other)

return wrapper

return dec

@disjoint_base
class immutabledict[K, V]:
slots = ("_data",)
_data: dict[K, V]

def new(cls, dict_: Mapping[K, V] = {}, /) -> Self:
self = object.new(cls)
self.data = dict(dict)
return self

@property
def data(self, /) -> dict[K, V]:
return self._data

def contains(self, item: object) -> bool:
return self._data.contains(item)

def eq(self, other: object, /) -> bool:
@typeguard(immutabledict)
def wrapper(self_param, other: immutabledict, /) -> bool:
return self_param._data == other._data

return wrapper(self, other)

def getitem(self, item: K, /) -> V:
return self._data.getitem(item)

def hash(self, /) -> int:
return hash((frozenset(self._data.items()), 23*len(self), type)) ^ 2**20

def iter(self, /) -> Iterator[K]:
return iter(self._data)

def len(self, /) -> int:
return self._data.len()

def or(self, other: "immutabledict", /) -> Self:
return type(self)(self._data.or(other._data))

def reduce(self, /) -> tuple[type[Self], tuple[dict[K, V]]]:
return (type(self), (self._data,))

def repr(self, /) -> str:
return f"{type(self).name}({self._data!r})"

def reversed(self, /) -> Iterator[K]:
return self._data.reversed()

ror = or

def str(self) -> str:
return f"{type(self).name}({self._data})"

def copy(self, /) -> Self:
return self

@classmethod
def fromkeys(cls, iterable: Iterable[K], value: V, /) -> Self:
return cls(dict.fromkeys(iterable, value))

def get[_T](self, key: K, default: _T) -> V | _T:
if key in self._data:
return self._data.getitem(key)

else:
  return default

def items(self, /) -> "immutabledict_items[K, V]":
return immutabledict_items(frozenset(self._data.items()))

def keys(self, /) -> "immutabledict_keys[K]":
return immutabledict_keys(frozenset(self._data.keys()))

def values(self, /) -> "immutabledict_values[V]":
return immutabledict_values(frozenset(self._data.values()))

@disjoint_base
class _immutabledict_view[T]:
slots = ("_data",)
_data: frozenset[T]

def new(cls, fset: frozenset[T], /) -> Self:
self = object.new(cls)
self._data = fset
return self

@property
def data(self) -> frozenset[T]:
return self._data

def and(self, other: Iterable, /) -> frozenset[T]:
return self._data & frozenset(other)

def contains(self, item: object, /):
return self._data.contains(item)

def eq(self, other: object, /) -> bool:
if isinstance(other, _immutabledict_view):
return self._data == other._data

else:
  return NotImplemented

def hash(self, /) -> int:
return hash((frozenset(self._data), 34, len(self), object)) ^ 2**20

def len(self, /) -> int:
return self._data.len()

def iter(self, /) -> Iterator[T]:
return self._data.iter()

def or[_T](self, other: Iterable[_T], /) -> frozenset[T | _T]:
return self._data.or(frozenset(other))

rand = and

def repr(self) -> str:
return f"{type(self).name}({self._data!r})"

def rsub(self, other: Iterable, /) -> frozenset[T]:
return self._data.sub(frozenset(other))

def rxor[_T](self, other: Iterable[_T], /) -> frozenset[T | _T]:
return self._data.xor(frozenset(other))

ror = or
sub = rsub
xor = rxor

class immutabledict_items[K, V](_immutabledict_view[tuple[K, V]]):
pass

class immutabledict_keysK:
pass

class immutabledict_valuesV:
pass

class _exitE: BaseException, R:
@overload
def call(self, exc_tp: type[BaseException], exc: BaseException, tb: TracebackType, result: R, /) -> bool: ...

@overload
def call(self, exc_tp: None, exc: None, tb: None, result: R, /) -> bool: ...

@final
class contextmanager[**P, R]:
slots = ("_func", "exit")
_func: Callable[P, R]
exit: _exit[BaseException, R]

def new(cls, func: Callable[P, R]) -> Self:
self = object.new(cls)
self._func = func

def _exit_inner(
    exc_tp: type[BaseException] | None,
    exc: BaseException | None,
    tb: TracebackType | None,
    result: R,
    /
) -> bool:
  return False

self._exit_ = _exit_inner
return self

def call(self, *args: P.args, **kwargs: P.kwargs) -> "_contextmanager_cls[P, R]":
return _contextmanager_cls(self.exit, self._func(*args, **kwargs))

def exit(self, func: _exit[BaseException, R]) -> Self:
self.exit = func
return self

class _contextmanager_cls[**P, R]:
slots = ("_value", "exit")
_value: R
exit: _exit[BaseException, R]

def new(cls, exit: _exit[BaseException, R], value: R) -> Self:
self = object.new(cls)
self._value = value
self.exit = exit
return self

def enter(self) -> R:
return self._value

def exit(self, exc_tp: type[BaseException], exc: BaseException, tb: TracebackType) -> bool:
return self.exit(exc_tp, exc, tb, self._value)

Float = TypeVar("Float", int, float)
Complex = TypeVar("Complex", int, float, complex)

@contextmanager
def print_args[*Ts](*args: *Ts) -> tuple[*Ts]:
print("Function called with:", *args)
return args

@print_args.exit
def _(exc_tp, exc, tb, result):
if exc is not None:
print(f"Exception suppressed: {exc_tp.name}({exc})")
return True

with print_args(2) as n:
print(n, "in with block")
raise ValueError("hi")

Traceback

test.py:301: 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: 2.4.0+dev.722047e369657c936851a349ebba6b4c5504b8e2
Traceback (most recent call last):
File "/usr/local/bin/mypy", line 8, in
sys.exit(console_entry())
File "/usr/local/lib/python3.12/dist-packages/mypy/main.py", line 16, in console_entry
main()
File "/usr/local/lib/python3.12/dist-packages/mypy/main.py", line 154, in main
res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
File "/usr/local/lib/python3.12/dist-packages/mypy/main.py", line 244, in run_build
res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
File "/usr/local/lib/python3.12/dist-packages/mypy/build.py", line 422, in build
result = build_inner(
File "/usr/local/lib/python3.12/dist-packages/mypy/build.py", line 537, in build_inner
graph = dispatch(sources, manager, stdout, connect_threads)
File "/usr/local/lib/python3.12/dist-packages/mypy/build.py", line 4150, in dispatch
process_graph(graph, manager)
File "/usr/local/lib/python3.12/dist-packages/mypy/build.py", line 4618, in process_graph
done, still_working, results = manager.wait_for_done(graph)
File "/usr/local/lib/python3.12/dist-packages/mypy/build.py", line 1484, in wait_for_done
process_stale_scc(graph, next_scc, self)
File "/usr/local/lib/python3.12/dist-packages/mypy/build.py", line 4793, in process_stale_scc
graph[id].type_check_first_pass()
File "/usr/local/lib/python3.12/dist-packages/mypy/build.py", line 3410, in type_check_first_pass
self.type_checker().check_first_pass(recurse_into_functions=recurse_into_functions)
File "/usr/local/lib/python3.12/dist-packages/mypy/checker.py", line 618, in check_first_pass
self.accept(d)
File "/usr/local/lib/python3.12/dist-packages/mypy/checker.py", line 765, in accept
stmt.accept(self)
File "/usr/local/lib/python3.12/dist-packages/mypy/nodes.py", line 2185, in accept
return visitor.visit_with_stmt(self)
File "/usr/local/lib/python3.12/dist-packages/mypy/checker.py", line 5902, in visit_with_stmt
exit_ret_type = self.check_with_item(expr, target, s.unanalyzed_type is None)
File "/usr/local/lib/python3.12/dist-packages/mypy/checker.py", line 5963, in check_with_item
ctx = echk.accept(expr)
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 6220, in accept
typ = self.accept_maybe_cache(node, type_context=type_context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 6255, in accept_maybe_cache
typ = node.accept(self)
^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/nodes.py", line 2545, in accept
return visitor.visit_call_expr(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 499, in visit_call_expr
return self.visit_call_expr_inner(e, allow_none_return=allow_none_return)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 630, in visit_call_expr_inner
ret_type = self.check_call_expr_with_callee_type(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 1498, in check_call_expr_with_callee_type
ret_type, callee_type = self.check_call(
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 1626, in check_call
result = self.check_call(
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 1591, in check_call
return self.check_callable_call(
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 1793, in check_callable_call
callee = self.infer_function_type_arguments(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 2286, in infer_function_type_arguments
return self.apply_inferred_arguments(callee_type, inferred_args, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 2421, in apply_inferred_arguments
return self.apply_generic_arguments(callee_type, inferred_args, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/checkexpr.py", line 3424, in apply_generic_arguments
return applytype.apply_generic_arguments(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/applytype.py", line 147, in apply_generic_arguments
callable = expand_type(callable, id_to_type)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 70, in expand_type
return typ.accept(ExpandTypeVisitor(env))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/types.py", line 2361, in accept
return visitor.visit_callable_type(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 495, in visit_callable_type
ret_type=t.ret_type.accept(self),
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/types.py", line 1684, in accept
return visitor.visit_instance(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 217, in visit_instance
args = self.expand_type_tuple_with_unpack(t.args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 531, in expand_type_tuple_with_unpack
items.append(item.accept(self))
^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/types.py", line 2073, in accept
return visitor.visit_parameters(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 403, in visit_parameters
return t.copy_modified(arg_types=self.expand_types(t.arg_types))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 616, in expand_types
a.append(t.accept(self))
^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/types.py", line 1248, in accept
return visitor.visit_unpack_type(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 380, in visit_unpack_type
return UnpackType(t.type.accept(self))
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/types.py", line 1007, in accept
return visitor.visit_type_var_tuple(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/mypy/expandtype.py", line 368, in visit_type_var_tuple
raise NotImplementedError
NotImplementedError

test.py:301: note: use --pdb to drop into pdb

To Reproduce

Setup:
!pip install git+https://github.com/python/mypy.git
from IPython.core.magic import register_cell_magic
from IPython import get_ipython
from mypy import api

@register_cell_magic
def mypy(line, cell):

mypy.api.run returns (stdout, stderr, exit_code)

stdout, stderr, exit_code = api.run(['-c', '\n' + cell] + line.split())

if stderr:
# If there's anything in stderr, it's usually an internal mypy error or argument error
raise TypeError(f"Mypy stderr:\n{stderr}")

if exit_code != 0:
# Mypy found type errors or exited with a non-zero status
if stdout:
raise TypeError(f"Mypy type errors:\n{stdout}")
else:
raise TypeError(f"Mypy exited with code {exit_code} but no output.")

If exit_code is 0 and no stderr, mypy passed, then run the cell

get_ipython().run_cell(cell)

Your Environment

Google colab, python 3.12

Ngôn ngữ chính
Python
Star
20.6k
Fork
3.3k
Merge trung bình
1 ngày 18 giờ
Pull request đã merge (30 ngày)
54

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của python/mypy

Tất cả issue của python/mypy

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.