Skip to content

Complex paraspec handling cause Internal error (IndexError: list index out of range) at check_override #20059

@Taiquan-Liu

Description

@Taiquan-Liu

Crash Report

Traceback

# mypy --show-traceback app/utils/testing/test_client.py
app/utils/testing/test_client.py:24: 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.18.2
Traceback (most recent call last):
  File "mypy/checker.py", line 641, in accept
  File "mypy/nodes.py", line 1122, in accept
  File "mypy/checker.py", line 5414, in visit_decorator
  File "mypy/checker.py", line 5470, in visit_decorator_inner
  File "mypy/checker.py", line 2208, in check_method_override
  File "mypy/checker.py", line 2246, in check_method_or_accessor_override_for_base
  File "mypy/checker.py", line 2388, in check_method_override_for_base_with_name
  File "mypy/checker.py", line 2579, in check_override
IndexError: list index out of range
app/utils/testing/test_client.py:24: : note: use --pdb to drop into pdb

To Reproduce

We have a helper decorator like this:

def infer_signature(f: Callable[P, R]) -> Callable[[InferredFunction], Callable[P, R]]:
    """
    When overriding a method from a base class it's sometimes not practical to copy
    its full signature to the subclass — especially in cases where the overriding method
    doesn't rely on the actual signature. It would be very inconvenient to update the
    overriding method signature every time the overriden method is updated.

    This decorator helps with being able to use `*args, **kwargs` as the signature but
    still being able to use IDE code completion for the overriden method.

    Example:
    >>> class BaseClass:
    >>>     def method(self, very: int, long: str, signature: float):
    >>>         ...
    >>>
    >>> class Subclass(BaseClass):
    >>>     @infer_signature(BaseClass.method)
    >>>     def method(self, *args, **kwargs):  # type: ignore[no-untyped-def]
    >>>         print(args, kwargs)
    >>>         return super(*args, **kwargs)
    """
    return lambda _: _  # type: ignore[return-value]

which is used like this

from starlette.testclient import TestClient
from app.utils.typing import infer_signature

class CustomTestClient(TestClient):
    @infer_signature(TestClient.get)
    def get(self, *args, **kwargs):  # type: ignore[no-untyped-def]
        kwargs.pop("json", None)
        kwargs.pop("data", None)
        return super().get(*args, **kwargs)

    @infer_signature(TestClient.delete)
    def delete(self, *args, **kwargs):  # type: ignore[no-untyped-def]
        kwargs.pop("json", None)
        kwargs.pop("data", None)
        return super().delete(*args, **kwargs)

And the mypy error happens in the latter example.

Your Environment

  • Mypy version used: 1.18.2
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
[mypy]
plugins = pydantic.mypy, sqlalchemy.ext.mypy.plugin
disallow_any_generics = True
disallow_any_unimported = False
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_decorators = True
no_implicit_optional = True
warn_redundant_casts = True
warn_unused_ignores = True
implicit_reexport = True
strict_equality = True
show_error_codes = True
  • Python version used: 3.13.8
  • Operating system and version:
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions