dmypy Suggest assertion error in `node_type_from_base`
Open
Nobody has claimed this yet.
crash
topic-daemon
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
Crash Report
Mypy Daemon crashed attempting to generate type suggestions for __reduce__ function in class with nonstandard __new__. (re-creating #15823)
Traceback
dmypy suggest crash.py:64: 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.8.0
dmypy suggest crash.py: 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.8.0
Daemon crashed!
Traceback (most recent call last):
File "mypy/dmypy_server.py", line 236, in serve
File "mypy/dmypy_server.py", line 285, in run_command
File "mypy/dmypy_server.py", line 972, in cmd_suggest
File "mypy/suggestions.py", line 267, in suggest
File "mypy/suggestions.py", line 502, in get_suggestion
File "mypy/suggestions.py", line 444, in find_best
File "mypy/suggestions.py", line 675, in try_type
File "mypy/server/update.py", line 314, in trigger
File "mypy/server/update.py", line 881, in propagate_changes_using_dependencies
File "mypy/server/update.py", line 1010, in reprocess_nodes
File "mypy/semanal_main.py", line 144, in semantic_analysis_for_targets
File "mypy/semanal_main.py", line 291, in process_top_level_function
File "mypy/semanal_main.py", line 349, in semantic_analyze_target
File "mypy/semanal.py", line 600, in refresh_partial
File "mypy/semanal.py", line 6541, in accept
File "mypy/errors.py", line 1261, in report_internal_error
File "mypy/semanal.py", line 6539, in accept
File "mypy/nodes.py", line 787, in accept
File "mypy/semanal.py", line 833, in visit_func_def
File "mypy/semanal.py", line 865, in analyze_func_def
File "mypy/typeanal.py", line 1031, in visit_callable_type
File "mypy/typeanal.py", line 1684, in anal_type
File "mypy/types.py", line 2400, in accept
File "mypy/typeanal.py", line 1133, in visit_tuple_type
File "mypy/typeanal.py", line 1659, in anal_array
File "mypy/typeanal.py", line 1684, in anal_type
File "mypy/types.py", line 1970, in accept
File "mypy/typeanal.py", line 980, in visit_callable_type
File "mypy/typeanal.py", line 1614, in bind_function_type_variables
AssertionError
To Reproduce
dmypy suggest crash.py:
from __future__ import annotations
from collections.abc import Iterable, Callable
from typing import TYPE_CHECKING, TypeVar, Any, cast
import sys
if sys.version_info < (3, 11):
from exceptiongroup import ExceptionGroup, BaseExceptionGroup
if TYPE_CHECKING:
from types import TracebackType
from typing_extensions import Self
NonBaseMultiError = ExceptionGroup
class MultiError(BaseExceptionGroup[BaseException]):
def __init__(
self, exceptions: list[BaseException], *, _collapse: bool = True
) -> None:
self.collapse = _collapse
# Avoid double initialization when _collapse is True and exceptions[0] returned
# by __new__() happens to be a MultiError and subsequently __init__() is called.
if _collapse and getattr(self, "exceptions", None) is not None:
# This exception was already initialized.
return
super().__init__("multiple tasks failed", exceptions)
def __new__(
cls, exceptions: Iterable[BaseException], *, _collapse: bool = True
) -> MultiError | NonBaseMultiError[Exception] | Self:
exceptions_union: list[BaseException | Exception] = list(exceptions)
for exc in exceptions_union:
if not isinstance(exc, BaseException):
raise TypeError(f"Expected an exception object, not {exc!r}")
class_sub: type[Self | NonBaseMultiError[Exception]] = cls
if _collapse and len(exceptions_union) == 1:
# If this lone object happens to itself be a MultiError, then
# Python will implicitly call our __init__ on it again. See
# special handling in __init__.
single = exceptions_union[0]
assert isinstance(single, MultiError)
return single
else:
# The base class __new__() implicitly invokes our __init__, which
# is what we want.
#
# In an earlier version of the code, we didn't define __init__ and
# simply set the `exceptions` attribute directly on the new object.
# However, linters expect attributes to be initialized in __init__.
if all(isinstance(exc, Exception) for exc in exceptions_union):
exceptions_arg_one = cast("list[Exception]", exceptions_union)
return super().__new__(
NonBaseMultiError, "multiple tasks failed", exceptions_arg_one
)
else:
exceptions_arg_two = cast("list[BaseException]", exceptions_union)
return super().__new__(cls, "multiple tasks failed", exceptions_arg_two)
def __reduce__(self):
return (
self.__new__,
(self.__class__, list(self.exceptions)),
{"collapse": self.collapse},
)
Run:
dmypy --status-file="<user path>/dmypy.json" run --timeout=1800 --log-file="<user path>/log.txt" --export-types "<user path>/dmypy suggest crash.py" -- --no-implicit-reexport --disallow-untyped-defs --show-error-codes --strict --warn-redundant-casts --cache-dir="<user path>" --show-error-end --no-color-output --no-error-summary --show-column-numbers --warn-unreachable --disallow-untyped-calls --warn-unused-ignores --cache-fine-grained --soft-error-limit=-1 --show-traceback --hide-error-context --show-absolute-path
dmypy --status-file="<user path>/dmypy.json" suggest "<user path>/dmypy suggest crash.py:65"
Your Environment
- Mypy version used: dmypy 1.8.0
- Mypy command-line flags: See above
- Mypy configuration options from
mypy.ini(and other config files): See above - Python version used: Python 3.12.0 (main, Oct 4 2023, 06:27:34) [GCC 13.2.0] on linux
- Operating system and version: 64 bit Linux Ubuntu Budgie 10.8 (Ubuntu 23.10) Linux 6.5.0-14-generic
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the dmypy suggest reproduction in the issue, then trace the reported call path through mypy/suggestions.py and mypy/typeanal.py, especially bind_function_type_variables. Confirm the behavior on the supplied crash.py and determine how the assertion is reached during type analysis. Done means dmypy suggest handles this case without an INTERNAL ERROR or daemon crash.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100