Skip to content
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

typing.overload and contextlib.contextmanager don't work together #11373

Closed
bentheiii opened this issue Oct 21, 2021 · 6 comments
Closed

typing.overload and contextlib.contextmanager don't work together #11373

bentheiii opened this issue Oct 21, 2021 · 6 comments
Labels
bug mypy got something wrong

Comments

@bentheiii
Copy link

Bug Report

The following example:

from contextlib import contextmanager
from typing import *

T = TypeVar('T')

@overload
def foo(a:int)->ContextManager[int]:...

@overload
def foo(a:str)->ContextManager[str]:...


@contextmanager
def foo(a: T)->Iterator[T]:
    yield a

f: ContextManager[int] = foo(1)

produces the following typing errors:

main.py:10: error: Overloaded function implementation cannot produce return type of signature 1
main.py:10: error: Overloaded function implementation cannot produce return type of signature 2
Found 2 errors in 1 file (checked 1 source file)

without the overloadings, mypy recognizes that foo(1) returns a ContextManager[int]

To Reproduce

  1. copy the above snipped
  2. run mypy, note the error
  3. comment out the overloads and their functions
  4. run mypy again, and note no errors

Expected Behavior

since the overload is correct for the implementation, mypy should pass in both cases.

Actual Behavior

mypy fails for the first case but passes for the second.

Your Environment

reproduced on current mypy-playground

  • Mypy version used: 0.910
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.10
  • Operating system and version: mypy-playground
@bentheiii bentheiii added the bug mypy got something wrong label Oct 21, 2021
@TilmanK
Copy link

TilmanK commented Dec 19, 2021

I can confirm that issue with mypy 0.920 and Python 3.9.

@bartfeenstra
Copy link

This bug is still present in MyPy 0.941

@pranavrajpal
Copy link
Contributor

The reason for the error is that, after applying the contextmanager decorator, the return type of the implementation is _GeneratorContextManager[T], which is a subclass of ContextManager[T]. mypy is showing an error because the return type of the implementation is a subtype of the return type of the overloads, but mypy is expecting the opposite because overloads are usually used to specify more specific return types than the implementation.

I think the bug here is the overload return type checking being too strict. There's no inherent unsafety in making the implementation return type a subtype of the overload return type because any code expecting the more generic overload return type will handle the implementation's more specific type correctly. The check should probably be changed to accept either the overload return type being a subtype of the implementation return type (the current check) or the implementation return type being a subtype of the overload return type.

@DetachHead
Copy link
Contributor

DetachHead commented Mar 24, 2022

i think the issue is that mypy doesn't allow overloads with return types that are wider than the implementation's return type, even though it's completely safe:

from typing import overload

@overload
def baz(a: int) -> int: ...

@overload
def baz(a: object) -> object: ...

def baz(a: object) -> int: ... # error: Overloaded function implementation cannot produce return type of signature 2

@KotlinIsland
Copy link
Contributor

KotlinIsland commented Mar 24, 2022

@DetachHead I agree. Your scenario is completely valid in overrides, so should also be valid in overloads:

from typing import overload

class A:
    def foo(a: object) -> object: ...
    
class B(A):
    def foo(a: object) -> int: ...  # no error
    
@overload
def foo(a: int) -> int: ...

@overload
def foo(a: object) -> object: ...

def foo(a: object) -> int: ...  # error: Overloaded function implementation cannot produce return type of signature 2

@JukkaL
Copy link
Collaborator

JukkaL commented Mar 24, 2022

Fixed in #12435, will be included in 0.942.

@JukkaL JukkaL closed this as completed Mar 24, 2022
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

7 participants