Skip to content

"An implementation for an overloaded function is not allowed in a stub file" for overloaded type hint #19128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kylebarron opened this issue May 21, 2025 · 7 comments
Labels
bug mypy got something wrong

Comments

@kylebarron
Copy link

Bug Report

I'm documenting a compiled extension module written in Rust. I write docstrings in my .pyi file so that IDEs and API documentation can automatically pick up those docstrings.

Docstrings are allowed in functions but this errors when a function is overloaded.

To Reproduce

# tmp.pyi

from typing import overload

def fn1() -> None:
    """Call this function."""

@overload
def fn2(a: str) -> str: ...
@overload
def fn2(a: int) -> int: ...
def fn2(a: int | str) -> int | str:
    """Call this function."""
uv run mypy tmp.pyi

gives:

tmp.pyi:10: error: An implementation for an overloaded function is not allowed in a stub file  [misc]

Note that this does not error on line 3 for the non-overloaded function.

Expected Behavior

Expected mypy to not error when a docstring is included on a function that has overloads.

Actual Behavior

tmp.pyi:10: error: An implementation for an overloaded function is not allowed in a stub file  [misc]
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used:

    > uv run mypy --version
    mypy 1.15.0 (compiled: yes)
    
  • Mypy command-line flags: None, just uv run mypy tmp.pyi

  • Mypy configuration options from mypy.ini (and other config files): None

  • Python version used:

    > uv run python --version
    Python 3.9.21
    
@kylebarron kylebarron added the bug mypy got something wrong label May 21, 2025
@kylebarron
Copy link
Author

It turns out I actually get this error even without a docstring:

# tmp.pyi

from typing import overload

def fn1() -> None:
    """Call this function."""

@overload
def fn2(a: str) -> str: ...
@overload
def fn2(a: int) -> int: ...
def fn2(a: int | str) -> int | str: ...

this still gives an error of

An implementation for an overloaded function is not allowed in a stub file

@kylebarron kylebarron changed the title "An implementation for an overloaded function is not allowed in a stub file" for overloaded type hint with docstring (but no implementation) "An implementation for an overloaded function is not allowed in a stub file" for overloaded type hint May 21, 2025
@JelleZijlstra
Copy link
Member

JelleZijlstra commented May 21, 2025

That error is correct and your code does exactly what the error tells you not to.

A docstring might be a good use case for doing this though, so maybe we should relax the check.

@kylebarron
Copy link
Author

kylebarron commented May 21, 2025

I'm sorry, I don't understand what the difference is between fn1 and fn2 here

def fn1() -> None:
    """Call this function."""

@overload
def fn2(a: str) -> str: ...
@overload
def fn2(a: int) -> int: ...
def fn2(a: int | str) -> int | str:
    """Call this function."""

Why would mypy allow one but not the other?

In the mypy stubs documentation it also says

It is also acceptable for the function body to contain a docstring

@JelleZijlstra
Copy link
Member

The error is "An implementation for an overloaded function is not allowed in a stub file". The second one is an overloaded function, the first one isn't.

@kylebarron
Copy link
Author

kylebarron commented May 22, 2025

Sorry, the part I'm confused about is not "overloaded function" it's "implementation".

Neither of the two definitions are associated with any code body, so I wouldn't have expected either of them to be considered to have "an implementation".

And especially because the first doesn't error, to a user the definition of "having an implementation" seems inconsistent.

@sterliakov
Copy link
Collaborator

Overloaded function implementation refers to the whole def not marked with @overload. Stubs are different, the typical usage (enforced by mypy here) for overload in stubs looks like this:

@overload
def fn2(a: str) -> str: ...
@overload
def fn2(a: int) -> int: ...

There's no point in adding the final signature to stub code, it is ignored when checking foreign calls and only affects checking the body of the implementation.

@aatle
Copy link
Contributor

aatle commented May 26, 2025

I'm having a similar issue for documenting a C extension module.

The error is expected; overloaded functions typically don't need an implementation definition inside stub files.
But then, where does the docstring go?
If it's placed inside an implementation definition in the stub file, then mypy errors.

Should it be placed inside only the last overload then?
One linter complains about this, pydocstyle, used in ruff, https://docs.astral.sh/ruff/rules/overload-with-docstring/, though no reasoning is given why it's bad and many tools support per-overload docstrings.
But then, these tools might assume that there is no docstring for the previous overloads. I tested 2 LSPs: for Pylance, an overload with no dosctring will inherit it from the first overload that does, but Jedi makes no attempt to share docstrings and so the first few overloads would have no docstrings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

4 participants