-
-
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
Generator fixup #1137
Generator fixup #1137
Conversation
This commit fixes up the handling of Generators in several ways: - it removes YieldStmt and YieldFromStmt, because they unnecessarily duplicate ExpressionStmt of YieldExpr/YieldFromExpr - it ensures functions are properly marked as is_generator when appropriate - it fixes a parsing bug where empty yield expressions would cause a parse error - it checks Generator functions for the appropriate type signature at the function level, rather than at the yield statement level - it adds support for return statements in Generator functions
self.fail(messages.INVALID_RETURN_TYPE_FOR_GENERATOR, typ) | ||
|
||
# Python 2 generators aren't allowed to return values | ||
if self.pyversion[0] == 2 and typ.ret_type.type.fullname() == 'typing.Generator': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure how to write a unit test for this, but it should probably have one.
About the Travis failures... It fails for Python 3.4 and 3.5 only, and is related to asyncio. Here is a repro that fails when run with your PR:
And since Future isn't a base class of Generator, it fails your code, with this error:
The tests containing this pattern are in mypy/test/data/pythoneval-asyncio.test, and are skipped in 3.2 and 3.3, where asyncio doesn't exist (the test framework only runs pythoneval-asyncio.test in 3.4 and higher -- see mypy/test/testpythoneval.py:31). So what to do? I can make this error go away by adding a check for 'asyncio.futures.Future' to is_generator_return_type(). That seems pretty unprincipled though -- and what if some other async library were to introduce a different Future type? It is also a lie. The function foo() above does not return a Future! It really does return a generator. It doesn't have any of Future's methods, like cancel(), done() or add_done_callback(). Everywhere a test defines a coroutine with return type That's still unfortunately verbose though. Also, the stubs for asyncio need to be changed -- they currently define several coroutines that claim to return Futures, which are all lies: either those APIs aren't coroutines, or they don't return Futures -- asyncio is sometimes a bit vague about whether something is a coroutine or a Future, and callers aren't supposed to care much -- they are expected to call asyncio.ensure_future() if they need a Future (e.g. to add a callback) and they're not expected to depend on specific behavior of generators/coroutines -- only yield from them. Apparently so far all this was put off till the future (!) by the code you are fixing that deals with yield-from -- that code was quietly accepting the lies. Note that there's a further wrinkle -- Awaitable. This only exists in 3.5 and later (both in collections.abc and in typing). However, I think that we can put off Awaitable (maybe file an issue about it). There are no tests involving it yet, so it won't distract us further here. |
Thanks for the detailed explanation! I definitely agree that we shouldn't be satisfied with lies here. For the verbosity, it would be nice if we could define a type alias I also agree about punting on Awaitable support for now -- that seems like the sort of thing we should implement after we have the rest of the language working and fast. I filed an issue (#1139) for it. |
It would be great if somebody would think through the whole asynchronous topic and how mypy should behave ideally in light of Python 3.5 and other recent developments. Most of the existing code related to |
So my recommendation to unblock this PR is to just change the asyncio tests and stubs to use |
# Function returning a value of type None may have a Void return. | ||
if isinstance(self.function_stack[-1], FuncExpr) or isinstance(typ, NoneTyp): | ||
return None | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please get rid of this blank line (it looks weird in context).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
This commit fixes up the handling of Generators in several ways:
duplicate ExpressionStmt of YieldExpr/YieldFromExpr
appropriate
error
the function level, rather than at the yield statement level
fixes #20, fixes #836, fixes #695, fixes #633, fixes #498