-
-
Notifications
You must be signed in to change notification settings - Fork 3k
@overload breaks @coroutine #6802
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
Comments
Upon further investigation, this seems to happen because the signature of @overload
@abstractmethod
@coroutine
def create_server(self, protocol_factory: _ProtocolFactory, host: Optional[Union[str, Sequence[str]]] = ..., port: int = ..., *,
family: int = ..., flags: int = ...,
sock: None = ..., backlog: int = ..., ssl: _SSLContext = ...,
reuse_address: Optional[bool] = ...,
reuse_port: Optional[bool] = ...) -> Generator[Any, None, AbstractServer]: ...
@overload
@abstractmethod
@coroutine
def create_server(self, protocol_factory: _ProtocolFactory, host: None = ..., port: None = ..., *,
family: int = ..., flags: int = ...,
sock: socket, backlog: int = ..., ssl: _SSLContext = ...,
reuse_address: Optional[bool] = ...,
reuse_port: Optional[bool] = ...) -> Generator[Any, None, AbstractServer]: ... If I remove the second definition, the problem goes away. This suggests a bad interaction between the implementation of |
I dived into the mypy source code and drowned :-/ I showed that the two Adding: if name == 'create_server':
print(typ) at line 868 gives:
I suspect that the issue occurs after these two definitions are grouped by |
Actually this isn't a regression in mypy. I had in mind a passing run of mypy v0.660. If I go back to this version of mypy, the change that triggers the regression is a patch I submitted to typeshed: python/typeshed@503cbb9. I must have written that patch based on the docs and not tried it on my code... I'm willing to investigate this issue further, however I could really use some pointers about how |
I'm not too familiar with the code either, but I know an overloaded function creates a different internal node in mypy, Also curious if the presence of |
Removing Thanks for the pointer to tl;dr I figured out what happens.
The type of the The conversion to The return types of the two coroutines underlying the overload are converted to One possible solution is to apply something similar to this: Line 852 in 3c04293
to overloads that wrap coroutines in Propagating the gory details For future reference and posterity, here are my debugging notes. I managed to determine where the code paths diverge depending on whether there's an overload or not. It's in If you add this debug code: diff --git a/mypy/checkmember.py b/mypy/checkmember.py
index e17d5f04..124f79fe 100644
--- a/mypy/checkmember.py
+++ b/mypy/checkmember.py
@@ -169,6 +169,10 @@ def analyze_instance_member_access(name: str,
# Look up the member. First look up the method dictionary.
method = info.get_method(name)
+
+ if name == 'create_server':
+ print(method)
+
if method:
if method.is_property:
assert isinstance(method, OverloadedFuncDef) and run If you comment out one of the two Execution then goes through: Line 179 in 3c04293
At this point, we have an I followed the trail through:
I ended up on this comment but I'm not sure it's the actual problem: Line 624 in 3c04293
Digging through git blame, I discovered that this TODO has been there for over two years, so the trail is cold. At this point, I realized that the types were "wrong" (i.e. not converted to AwaitableGenerator), which I had seen the "right" ones earlier. So they had to change later. With this debug code, the ordering issue becomes clear. diff --git a/mypy/checker.py b/mypy/checker.py
index e25368a1..208a1931 100644
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -860,6 +860,11 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
tr = self.get_coroutine_return_type(t)
else:
tr = self.get_generator_return_type(t, c)
+ if defn.name() == "create_server":
+ print()
+ print()
+ print()
+ print("CONVERTING RETURN TYPE OF create_server()")
ret_type = self.named_generic_type('typing.AwaitableGenerator',
[ty, tc, tr, t])
typ = typ.copy_modified(ret_type=ret_type)
diff --git a/mypy/nodes.py b/mypy/nodes.py
index 25c38eb6..9780e9b6 100644
--- a/mypy/nodes.py
+++ b/mypy/nodes.py
@@ -494,7 +494,24 @@ class OverloadedFuncDef(FuncBase, SymbolNode, Statement):
return self.impl.name()
def accept(self, visitor: StatementVisitor[T]) -> T:
- return visitor.visit_overloaded_func_def(self)
+ if self.name() == 'create_server':
+ print()
+ print()
+ print()
+ print(visitor)
+ print()
+ print("BEFORE")
+ print(self.type)
+ for item in self.items:
+ print(str(item))
+ res = visitor.visit_overloaded_func_def(self)
+ if self.name() == 'create_server':
+ print()
+ print("AFTER")
+ print(self.type)
+ for item in self.items:
+ print(str(item))
+ return res
def serialize(self) -> JsonDict:
return {'.class': 'OverloadedFuncDef', |
Work around python/mypy#6802.
Is there anything I can do to help move this forwards, besides the PR with tests that I submitted two weeks ago? |
The core team is unfortunately really busy last weeks, hopefully someone will look at your PR before the next release (planned soon), since technically this is a regression. cc @gvanrossum who is going to be the release manger. |
I just reviewed the PR, but somebody else on the PR should also take a look before it can be merged. |
This bug no longer exists in mypy 0.730.
Anyway, since it isn't reproducible anymore, I'll close it. Thanks, whoever made improvements that had the side effect of fixing this for me :-) |
This seemingly simple example fails
mypy --strict
. Unless I'm missing something obvious, it should pass.(The example looks artificial because it's reduced from a more complicated, real-world piece of code.)
This failure is new in mypy 0.701. It used to work a few months ago. (I didn't bisect the regression).
I'm using Python 3.7.3 from homebrew on an up-to-date macOS.
When mypy processes the code, if I understand the
@asyncio.coroutine
example in the docs correctly, the type ofmy_awaitable
should be converted intoAwaitable[AbstractServer]
. For some reason this doesn't happen and it stays asGenerator[Any, None, AbstractServer]
.The type definition in typeshed matches the docs I just linked to, which is why I'm posting this on the mypy repository rather than typeshed.
This looks similar to #2907. The discussion there says that the order of functions matter. I have only one function so this can't be the whole explanation.
The text was updated successfully, but these errors were encountered: