Fix mock patch.dict stub and add mock stub#2173
Conversation
stdlib/3/unittest/mock.pyi
Outdated
| @@ -1,4 +1,5 @@ | |||
| # Stubs for unittest.mock | |||
| # Please sync with third_party/2and3/mock.pyi when changing. | |||
There was a problem hiding this comment.
You can put this in typeshed/tests/check_consistent.py (you'll have to make sure the files are byte-for-byte identical).
d7c5ff3 to
a0ab2e4
Compare
The dict stub was referring to an instance, not the type, leading to __call__ being considered when using as a decorator, rather than __init__. mock is a backport of the stdlib module and should be defined the same.
|
@JelleZijlstra is anything else needed from me for this to merge? |
|
Thanks for fixing this. |
|
@rbtcollins @JelleZijlstra This just broke a bunch of our type checks: from mock import MagicMock, call, mock_open, patchResults in: |
| import sys | ||
| from typing import Any, Optional, Type | ||
|
|
||
| if sys.version_info >= (3, 3): |
There was a problem hiding this comment.
This appears to be the problem - for Python 2 this is left as an empty module.
There was a problem hiding this comment.
Oops you're right. We should make it so that everything gets unconditionally exported. (We don't care about 3.2 anyway.)
Can you make a PR making that change?
|
@rbtcollins @JelleZijlstra @rowillia |
|
Hm, that is indeed unfortunate. But doesn't Mock still inherit from Any in this PR? |
It does. And in a toy example it seems to be acceptable; I get no errors here: class M(Any): pass
class A: pass
def f(a: A): pass
f(M())I'll have to look over our code more carefully to see what scenario triggered those errors. |
|
Oh, it's the other way around. Example: class M(Any): pass # type: ignore
class A: pass
def foo(a: M): pass
foo(A()) # error: Argument 1 to "foo" has incompatible type "A"; expected "M"This pattern happens a lot in our code (though typically it's a variable initialized with a Mock and later assigned something non-Mock). |
|
So you have functions that are annotated as taking If it's common though, I'd be OK with making Mock just be an alias for Any. |
|
I did find functions annotated as taking Mocks... I am not complaining about those, I changed them to Any. More common was instance variables initialized from a Mock and later assigned from a non-Mock (clearly an instance the class that the Mock was mocking). The initialization causes an implicit declaration. Sort of like class Account:
...
def get_account(username):
# type: (str) -> Account
...
class C:
def __init__(self):
# type: () -> None
self.account = Mock() # implies type: Mock
def switch_account(self, username):
# type: (str) -> None
self.account = get_account(username) # error here |
|
Could the solution be to just give explicit annotation, like self.account: Account = Mock()Also, the current behavior of classes with an |
|
Oh thanks, that makes more sense! I think even in this case though, mypy found a real type problem. The code works correctly if you do |
Upstream bug: python/typeshed#2173
The dict stub was referring to an instance, not the type, leading to __call__ being considered when using as a decorator, rather than __init__. mock is a backport of the stdlib module and should be defined the same.
The dict stub was referring to an instance, not the type, leading to
call being considered when using as a decorator, rather than
init.
mock is a backport of the stdlib module and should be defined the same.