Skip to content

Unable to use @overload with Concatenate decorator #12716

Closed

Description

@Dreamsorcerer

Bug Report

I can't seem to figure out any way to get @overloads to work with a method being transformed by a decorator.

To Reproduce

I've attempted to reduce it to a small example:

def acquire(func: Callable[Concatenate[Any, str, _P], Awaitable[_T]]) -> Callable[Concatenate[Any, _P], Awaitable[_T]]:
    ...

@overload
async def get(self, key: bytes, default: None = ...) -> Union[bytes, _T, None]:
    ...
@overload
async def get(self, key: bytes, default: _U) -> Union[bytes, _T, _U]:
    ...
@acquire
async def get(
    self, conn: str, key: bytes, default: Optional[_U] = None
) -> Union[bytes, _T, _U, None]:
    ...

get(b"foo")

I have experimented with adding/removing conn from the overloads and adding/moving the @acquire at various locations.

Expected Behavior

The final call to work correctly with no errors in mypy.

Actual Behavior

Depending on exactly how I write it, I end up with either complaints about the definition (e.g. Overloaded function implementation does not accept all possible arguments of signature 1) or complaints about the final call (e.g. No overload variant of "get" matches argument type "bytes").

Your Environment

  • Mypy version used: 0.950
  • Python version used: 3.8

Activity

  1. Dreamsorcerer commented on Nov 8, 2022

    @Dreamsorcerer
    ContributorAuthor
  2. ilevkivskyi commented on Aug 18, 2023

    @ilevkivskyi
    Member

    Note after #15898 is merged, you should be able to either:

    • Decorate each overload with @acquire as defined now (overloads should have undecorated signature obviously)
    • Or fix @acquire to preserve the name of first argument to be "self".
  3. Dreamsorcerer commented on Oct 17, 2023

    @Dreamsorcerer
    ContributorAuthor
    • Decorate each overload with @acquire as defined now (overloads should have undecorated signature obviously)

    • Or fix @acquire to preserve the name of first argument to be "self".

    First option works. But, I don't understand how to do the second option.

    Looks like your tests do the former, so I guess I'll stick with that.

  4. ilevkivskyi commented on Oct 17, 2023

    @ilevkivskyi
    Member

    I meant something using callback protocols (that allow specifying argument names unlike simple Callable[] and are generally more expressive, but somewhat verbose), like this:

    class WithConn(Protocol[_P, _R]):
        def __call__(s, self: Any, conn: str, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
    
    class NoConn(Protocol[_P, _R]):
        def __call__(s, self: Any, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
    
    def acquire(func: WithConn[_P, _T]) -> NoConn[_P, _T]:
        ...

    But I just tried and it looks like it doesn't really work because of some unrelated bug with return type checks for generic overloads.

  5. Dreamsorcerer commented on Nov 13, 2023

    @Dreamsorcerer
    ContributorAuthor

    Not sure if there's something I'm doing wrong, but seem to have encountered a regression that's breaking this again in 1.7: #16481

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions