python / python/mypy

dmypy Suggest assertion error in `node_type_from_base`

Abierto
#16,708 6 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

crash topic-daemon
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

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

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con la reproducción de dmypy suggest indicada en el issue y, después, sigue la ruta de llamada reportada a través de mypy/suggestions.py y mypy/typeanal.py, especialmente bind_function_type_variables. Confirma el comportamiento con el crash.py proporcionado y determina cómo se alcanza la aserción durante el análisis de tipos. Se considera terminado cuando dmypy suggest gestiona este caso sin un INTERNAL ERROR ni un bloqueo del daemon.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
devtools
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Tranquilo
Claridad
Bastante claro
Aptitud para principiantes
55/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.