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

1.7.0: Overloaded function with decorator using ParamSpec does not type check #16474

Closed
thomascellerier opened this issue Nov 13, 2023 · 3 comments
Labels
bug mypy got something wrong topic-paramspec PEP 612, ParamSpec, Concatenate

Comments

@thomascellerier
Copy link

thomascellerier commented Nov 13, 2023

Bug Report

Code with overloads with a decorator using a ParamSpec was typechecking fine with mypy 1.6.1 but not with mypy 1.7.0.

To Reproduce

See the following reproducer loosely based on an API client library where I hit this problem.
The library allows optionally parsing the response body into a model class

test_overload.py

import typing

P = typing.ParamSpec("P")
R = typing.TypeVar("R")


def handle_exception(
    func: typing.Callable[P, typing.Awaitable[R]]
) -> typing.Callable[P, typing.Awaitable[R]]:
    return func


class Response:
    pass


class ResponseModel:
    pass


ResponseT = typing.TypeVar("ResponseT", bound=ResponseModel)


@typing.overload
async def request(response_model: type[ResponseT]) -> ResponseT:
    ...

@typing.overload
async def request(response_model: None = ...) -> Response:
    ...


@handle_exception
async def request(
    response_model: type[ResponseT] | None = None,
) -> ResponseT | Response:
    raise NotImplementedError()

It can be reproduced without async too.

test_overload_sync.py

import typing

P = typing.ParamSpec("P")
R = typing.TypeVar("R")


def handle_exception(
    func: typing.Callable[P, R]
) -> typing.Callable[P, R]:
    return func


class Response:
    pass


class ResponseModel:
    pass


ResponseT = typing.TypeVar("ResponseT", bound=ResponseModel)


@typing.overload
def request(response_model: type[ResponseT]) -> ResponseT:
    ...

@typing.overload
def request(response_model: None = ...) -> Response:
    ...


@handle_exception
def request(
    response_model: type[ResponseT] | None = None,
) -> ResponseT | Response:
    raise NotImplementedError()

Expected Behavior

No mypy errors.

This works with 1.6.1:

$ mypy --version
mypy 1.6.1 (compiled: yes)
$ mypy test_overload.py 
Success: no issues found in 1 source file

Actual Behavior

It fails to type check:

$ mypy test_overload.py 
test_overload.py:33: error: Argument 1 to "handle_exception" has incompatible type "Callable[[type[ResponseT] | None], Coroutine[Any, Any, ResponseT | Response]]"; expected "Callable[[VarArg(Never), KwArg(Never)], Awaitable[Never]]"  [arg-type]
test_overload.py:33: error: Overloaded function implementation does not accept all possible arguments of signature 1  [misc]
test_overload.py:33: error: Overloaded function implementation cannot produce return type of signature 1  [misc]
test_overload.py:33: error: Overloaded function implementation does not accept all possible arguments of signature 2  [misc]
test_overload.py:33: error: Overloaded function implementation cannot produce return type of signature 2  [misc]
Found 5 errors in 1 file (checked 1 source file)

Sync version:

$ python3 -m mypy test_overload_sync.py 
test_overload.py:33: error: Argument 1 to "handle_exception" has incompatible type "Callable[[type[ResponseT] | None], ResponseT | Response]"; expected "Callable[[VarArg(Never), KwArg(Never)], Never]"  [arg-type]
test_overload.py:33: error: Overloaded function implementation does not accept all possible arguments of signature 1  [misc]
test_overload.py:33: error: Overloaded function implementation does not accept all possible arguments of signature 2  [misc]

Your Environment

  • Mypy version used: 1.7.0 (compiled)
  • Mypy command-line flags: mypy test_overload.py, tried with and without a clean cache
  • Python version: 3.10.2, 3.11.6
@thomascellerier thomascellerier added the bug mypy got something wrong label Nov 13, 2023
@AlexWaygood AlexWaygood added the topic-paramspec PEP 612, ParamSpec, Concatenate label Nov 13, 2023
@ilevkivskyi
Copy link
Member

This is likely a duplicate of #16451. It should be fixed on latest master (merged few minutes ago). Could you please double-check and re-open if needed?

@ilevkivskyi ilevkivskyi closed this as not planned Won't fix, can't repro, duplicate, stale Nov 13, 2023
@AlexWaygood
Copy link
Member

This is likely a duplicate of #16451. It should be fixed on latest master (merged few minutes ago). Could you please double-check and re-open if needed?

Both snippets pass for me locally with the latest master (but not before #16461)

@thomascellerier
Copy link
Author

Thanks!

I tested as well with master and it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-paramspec PEP 612, ParamSpec, Concatenate
Projects
None yet
Development

No branches or pull requests

3 participants