-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Function returning a generic function #1551
Comments
This is related to my comments at #1317, but maybe worth keeping open as a separate issue. |
As Jukka and I discussed at PyCon, this situation where a type variable appears only in the result type of a generic callable could be handled by "floating in" the type variable to the result type: instead of
give
I wonder how often this arises in practice? |
The only case where I remember having seen this is in a decorator that is used like this:
The decorator, when called, returns a generic function |
At Zulip, we're using such decorator-returning functions a lot. One of these decorator-returning functions, named |
I have another example from our codebase: @app.route('/')
@rate_limit(30, timedelta(seconds=60))
def index() -> Response:
# ... Both of the decorators returned by Sadly I don't have enough knowledge to help with this myself. |
This seems like something we'll really want to fix, but it's not immediately clear yet what the fix looks like. |
As a workaround, rewriting nested functions to a class seem to work: from functools import wraps
from typing import TypeVar, Callable, Any, cast
TFun = TypeVar('TFun', bound=Callable[..., Any])
class log_calls:
def __init__(self, prefix: str) -> None:
self.prefix = prefix
def __call__(self, f: TFun) -> TFun:
prefix = self.prefix
@wraps(f)
def wrapper(*args, **kwargs) -> Any:
print('{}: {!r} {!r}'.format(prefix, args, kwargs))
return f(*args, **kwargs)
return cast(TFun, wrapper)
@log_calls('Calling foo')
def foo(x: str) -> str:
return x
reveal_type(foo) |
Oooh, very clever! I can't say I personally understand how it works, and we On Sat, Oct 15, 2016 at 4:28 AM, Yegor Roganov [email protected]
--Guido van Rossum (python.org/~guido) |
Starting with python/mypy#2521 mypy is performing stricter function signature checks. This makes the stubs diverge from the actual implementation but makes the stubs internally consistent. Since this is an actual typing issue in the base implementation, we need to defer to the original authors to fix it. Sadly, in this case the breakage is rather fundamental and unlikely to get fixed by upstream. Consider: ``` class AWSAuthConnection(object): def make_request(self, method, path, headers=None, data='', host=None, auth_path=None, sender=None, override_num_retries=None, params=None, retry_handler=None): ... class AWSQueryConnection(AWSAuthConnection): def make_request(self, action, params=None, path='/', verb='GET'): ... ``` Hence, until we have a workaround for the error produced by Mypy, we're excluding those stubs from being tested against.
Reverts #804. Reason: until python/mypy#1551 is fixed this gives an error whenever @Skip() is used. Specifically see #804 (comment).
This looks fun and important. It'll be a good warm-up to all the rest of the features we need to get decorators working right. claim |
…1118) Another attempt for #804, to unblock python/mypy#2626. There's a work-around here for python/mypy#1551.
Instead of TypeQuery always returning a boolean and having the strategy be an enum, the strategy is now a Callable describing how to combine partial results, and the two default strategies are plain old funcitons. To preserve the short-circuiting behavior of the previous code, this PR uses an exception. This is a pure refactor that I am using in my experimentation regarding fixing python#1551. It should result in exactly no change to current behavior. It's separable from the other things I'm experimenting with, so I'm filing it as a separate pull request now. It enables me to rewrite the code that pulls type variables out of types as a TypeQuery. Consider waiting to merge this PR until I have some code that uses it ready for review. Or merge it now, if you think it's a pleasant cleanup instead of an ugly complication. I'm of two minds on that particular question.
Instead of TypeQuery always returning a boolean and having the strategy be an enum, the strategy is now a Callable describing how to combine partial results, and the two default strategies are plain old funcitons. To preserve the short-circuiting behavior of the previous code, this PR uses an exception. This is a pure refactor that I am using in my experimentation regarding fixing python#1551. It should result in exactly no change to current behavior. It's separable from the other things I'm experimenting with, so I'm filing it as a separate pull request now. It enables me to rewrite the code that pulls type variables out of types as a TypeQuery. Consider waiting to merge this PR until I have some code that uses it ready for review. Or merge it now, if you think it's a pleasant cleanup instead of an ugly complication. I'm of two minds on that particular question.
Instead of TypeQuery always returning a boolean and having the strategy be an enum, the strategy is now a Callable describing how to combine partial results, and the two default strategies are plain old funcitons. To preserve the short-circuiting behavior of the previous code, this PR uses an exception. This is a pure refactor that I am using in my experimentation regarding fixing python#1551. It should result in exactly no change to current behavior. It's separable from the other things I'm experimenting with, so I'm filing it as a separate pull request now. It enables me to rewrite the code that pulls type variables out of types as a TypeQuery. Consider waiting to merge this PR until I have some code that uses it ready for review. Or merge it now, if you think it's a pleasant cleanup instead of an ugly complication. I'm of two minds on that particular question.
Instead of TypeQuery always returning a boolean and having the strategy be an enum, the strategy is now a Callable describing how to combine partial results, and the two default strategies are plain old funcitons. To preserve the short-circuiting behavior of the previous code, this PR uses an exception. This is a pure refactor that I am using in my experimentation regarding fixing python#1551. It should result in exactly no change to current behavior. It's separable from the other things I'm experimenting with, so I'm filing it as a separate pull request now. It enables me to rewrite the code that pulls type variables out of types as a TypeQuery. Consider waiting to merge this PR until I have some code that uses it ready for review. Or merge it now, if you think it's a pleasant cleanup instead of an ugly complication. I'm of two minds on that particular question.
I just opened a pull request #3113 that fixes this. It's still WIP, but I should link this issue in. |
Instead of TypeQuery always returning a boolean and having the strategy be an enum, the strategy is now a Callable describing how to combine partial results, and the two default strategies are plain old funcitons. To preserve the short-circuiting behavior of the previous code, this PR uses an exception. This is a pure refactor that I am using in my experimentation regarding fixing #1551. It should result in exactly no change to current behavior. It's separable from the other things I'm experimenting with, so I'm filing it as a separate pull request now. It enables me to rewrite the code that pulls type variables out of types as a TypeQuery. Consider waiting to merge this PR until I have some code that uses it ready for review. Or merge it now, if you think it's a pleasant cleanup instead of an ugly complication. I'm of two minds on that particular question.
This is the email I meant to reply to saying yes I think it's fixed. Sorry, I was getting off a plane on 4h sleep. |
NP! We've had quite a busy week. I'll tell you the stories some time. |
Mypy doesn't support a function that tries to return a generic callable. I wonder if mypy could make this code work properly:
The text was updated successfully, but these errors were encountered: