mypy icon indicating copy to clipboard operation
mypy copied to clipboard

no-overload-impl false positive with typevar inside

Open trim21 opened this issue 1 year ago • 1 comments

Bug Report

TypeVar after overload cause mypy raise a warning about missing impl and redef

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

To Reproduce

from typing import Iterable, Sequence, TypeVar, overload


@overload
def chunks(c: str, n) -> Iterable[str]: ...


@overload
def chunks(c: bytes, n) -> Iterable[bytes]: ...


_T = TypeVar("_T")


def chunks(c: Sequence[_T], n) -> Iterable[Sequence[_T]]:
    # looping till length l
    for i in range(0, len(c), n):
        yield c[i : i + n]

Expected Behavior

should not report errors

Actual Behavior

a.py:4: error: An overloaded function outside a stub file must have an implementation [no-overload-impl] a.py:15: error: Name "chunks" already defined on line 4 [no-redef]

Your Environment

  • Mypy version used: 1.9.0
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.10

[tool.mypy]
allow_redefinition = true
ignore_missing_imports = true
check_untyped_defs = true
warn_no_return = false

trim21 avatar Apr 24 '24 18:04 trim21

Try moving the TypeVar definition above the overloads. That will resolve the errors.

cdce8p avatar Apr 24 '24 19:04 cdce8p

Same here. What's in between the overload and the implementation does not matter. I can reproduce with _sentinel = object() instead of _T = TypeVar("_T").

I find it surprising that Mypy would depend on the structure of the file itself. I would expect it to see that I have an implementation, even if it's a thousand lines lower, with many other things in between, as long as it's in the same scope.

@cdce8p's suggestion works, but shows brittle behavior IMO :thinking:

pawamoy avatar Jul 11 '24 12:07 pawamoy

@cdce8p could you elaborate why you closed as not planned :slightly_smiling_face:? I'm curious: is it hard to fix? Does Mypy really depend on the order it finds nodes in the AST or something?

pawamoy avatar Sep 21 '24 10:09 pawamoy

@cdce8p could you elaborate why you closed as not planned :slightly_smiling_face:? I'm curious: is it hard to fix? Does Mypy really depend on the order it finds nodes in the AST or something?

It's defined that way in the typing spec. To quote the relevant section here

In regular modules, a series of @overload-decorated definitions must be followed by exactly one non-@overload-decorated definition (for the same function/method).

https://typing.readthedocs.io/en/latest/spec/overload.html

cdce8p avatar Sep 21 '24 11:09 cdce8p

But that doesn't mean that the implementation must appear right after the last overload, or that overloads should appear one after the other for that matter. I read this as "there must be an implementation, and there must be only one". Doesn't say where this implementation should appear :thinking:

pawamoy avatar Sep 21 '24 14:09 pawamoy

I read this as "there must be an implementation, and there must be only one". Doesn't say where this implementation should appear 🤔

That might be true, however I'd argue that it makes the most sense for the implementation to be directly below the overloads (that's also what I've seen in code so far). AFAIK the mypy check literally looks for the next statement (after the overloads) and if that isn't the implementation, the error is emitted. Feel free to disable it / add a type: ignore[no-overload-impl] comment though. Type checking should work regardless.

Anyway, I don't believe there is a motivation to change that behavior and as such I closed it with not planned.

cdce8p avatar Sep 21 '24 16:09 cdce8p

Sure, but the warnings are very confusing: redef and no overload impl while there is an implementation and no redefinition. And I suppose ignoring these two warnings prevents further type-checking on the overloads and implementation, which isn't great. Anyway, that's fine, thanks for your answers 😊

pawamoy avatar Sep 21 '24 17:09 pawamoy