Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork1.9k
Open
Description
Steps to reproduce
fromunittest.mockimportpatchclassNewPrinter:passwithpatch("pprint.PrettyPrinter",new_callable=lambda:NewPrinter)aspatched_printer:print(patched_printer)# <class '__main__.NewPrinter'>reveal_type(patched_printer)# "Union[unittest.mock.MagicMock, unittest.mock.AsyncMock]"
Same deal withunittest.mock.patch.object
fromunittest.mockimportpatchimportpprintclassNewPrinter: ...withpatch.object(pprint,"PrettyPrinter",new_callable=lambda:NewPrinter)aspatched_printer:print(patched_printer)# <class '__main__.NewPrinter'>reveal_type(patched_printer)# "Union[unittest.mock.MagicMock, unittest.mock.AsyncMock]"
Suggested fix
We discussunittest.mock.patch
in the following, but the same principles apply tounittest.mock.patch.object
too
Current signatures:
@overloaddef__call__(self,target:str,new:_T,spec:Any|None= ...,create:bool= ...,spec_set:Any|None= ...,autospec:Any|None= ...,new_callable:Any|None= ...,**kwargs:Any, )->_patch[_T]: ...@overloaddef__call__(self,target:str,*,spec:Any|None= ...,create:bool= ...,spec_set:Any|None= ...,autospec:Any|None= ...,new_callable:Any|None= ...,**kwargs:Any, )->_patch_default_new: ...
There are 2 problems here:
new_callable
shouldn't beAny | None
in the first place, it should only acceptCallable| None
, as the it will raise if the provided value is not a callablewithpatch("pprint.PrettyPrinter",new_callable=1)aspatched_printer:# TypeError: 'int' object is not callable
- Need to differentiate the case where new_callable is provided and left as default None
- When
new_callable: Callable[..., T]
, returns_patch[_T]
- When
new_callable: None = ...
, returns_patch_default_new
- When
Seems like this would do the job:
@overloaddef__call__(self,target:str,new:_T,spec:Any|None= ...,create:bool= ...,spec_set:Any|None= ...,autospec:Any|None= ...,new_callable:Callable[...,Any]|None= ...,**kwargs:Any, )->_patch[_T]: ...@overloaddef__call__(self,target:str,*,spec:Any|None= ...,create:bool= ...,spec_set:Any|None= ...,autospec:Any|None= ...,new_callable:Callable[...,_T],**kwargs:Any, )->_patch[_T] @overloaddef__call__(self,target:str,*,spec:Any|None= ...,create:bool= ...,spec_set:Any|None= ...,autospec:Any|None= ...,new_callable:None= ...,**kwargs:Any, )->_patch_default_new: ...
Testing results
fromunittest.mockimportpatchclassNewPrinter:passwithpatch("pprint.PrettyPrinter")aspatched_printer:print(patched_printer)# <MagicMock name='PrettyPrinter' id='125908774402896'>reveal_type(patched_printer)# MagicMock | AsyncMockwithpatch("pprint.PrettyPrinter",new=NewPrinter)aspatched_printer:print(patched_printer)# <class '__main__.NewPrinter'>reveal_type(patched_printer)# type[NewPrinter]withpatch("pprint.PrettyPrinter",new_callable=lambda:NewPrinter)aspatched_printer:print(patched_printer)# <class '__main__.NewPrinter'>reveal_type(patched_printer)# type[NewPrinter]# No overload variant matches for non-callable typewithpatch("pprint.PrettyPrinter",new_callable="non-callable")aspatched_printer: ...
Haven't triedunittest.mock.patch.object
yet, but probably same thing
Would be great to see what the maintainers think.
I'll dig deeper and try to open a PR, maybe this weekend, will be my first PR in typeshed :)
Metadata
Metadata
Assignees
Labels
No labels