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

Remove arguments passed by decorators from function type hint #1758

Closed
qumusabel opened this issue Apr 12, 2021 · 6 comments
Closed

Remove arguments passed by decorators from function type hint #1758

qumusabel opened this issue Apr 12, 2021 · 6 comments

Comments

@qumusabel
Copy link

Describe the bug
I can't seem to find a way to remove the arguments that should be passed by the decorator from the function type hint.

To Reproduce
This code should reproduce the issue:

from functools import wraps
import rich

def get_console(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        console = rich.get_console()
        return func(console, *args, **kwargs)
    return wrapper

@get_console # pass the global console object to any function that needs it
def error(console: Console, msg: str):
    console.print(r"[red][bold]Error![/bold] {}[/]".format(msg))

Now when I type error the hint is error(console: Console, msg: str) -> None, and error("Something went wrong") is highlighted with Argument missing for parameter "msg" (and type mismatch).

Expected behavior
The argument which is passed to the function by the decorator should be hidden from the type hint. In the example, I want error(msg: str) -> None to be the type hint.

VS Code extension or command-line
I am using coc-pyright for coc.nvim.

P.S. I'm sorry if this is a duplicate or unrelated to pyright.

@erictraut
Copy link
Collaborator

Until recently, there was no way to provide type annotations to handle this pattern. The good news is that PEP 612, which was recently accepted, was created specifically for this use case.

Here's how you would use it:

from typing import Callable, TypeVar
from typing_extensions import Concatenate, ParamSpec

_P = ParamSpec("_P")
_T = TypeVar("_T")

def get_console(func: Callable[Concatenate[Console, _P], _T]) -> Callable[_P, _T]:
    @wraps(func)
    def wrapper(*args: _P.args, **kwargs: _P.kwargs):
        console = rich.get_console()
        return func(console, *args, **kwargs)
    return wrapper

Pyright has full support for PEP 612, so you can use this today. You'll need to import Concatenate and ParamSpec from typing_extensions unless you're using alpha versions of Python 3.10 (in which case you can import these symbols directly from typing).

@qumusabel
Copy link
Author

qumusabel commented Apr 12, 2021

Works like a charm in the editor, thank you very much. However, it doesn't seem to work when the code is actually executed. It throws an ImportError from typing_extensions (but in the editor it shows Concatenate and ParamSpec in autocomplete). And the PyPI packages for both typing and typing_extensions haven't been updated for half a year now. Makes me wonder why... and how can I upgrade without pulling the git repo...

@erictraut
Copy link
Collaborator

I think that typing_extensions has been updated to include PEP 612 support, but it sounds like the latest code hasn't been published.

To work around this in the meantime, you might need to resort to hacks like this:

from __future__ import annotations
from typing import Callable, TypeVar, TYPE_CHECKING

if TYPE_CHECKING:
    from typing_extensions import Concatenate, ParamSpec

    _P = ParamSpec("_P")
    _T = TypeVar("_T")

@qumusabel
Copy link
Author

Thank you very much!

@erictraut
Copy link
Collaborator

I confirmed that the support has been added to typing_extensions. Here's the code in the typing_extensions repo.

@gvanrossum, do you know when a new version of typing_extensions will be published to pypi? What is the process for getting this done?

@gvanrossum
Copy link

@gvanrossum, do you know when a new version of typing_extensions will be published to pypi? What is the process for getting this done?

I'd file an issue requesting one. I've just transferred the responsibility for this job to some new maintainers and they seem eager to get stuff done.

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

No branches or pull requests

3 participants