`unittest.mock.patch` and `unittest.mock.patch.object` are wrongly typed when new_callable is provided
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 48/100
Direzione di ricerca
Esamina gli overload di unittest.mock.patch e patch.object mostrati nell'issue, quindi trova i relativi stub di typeshed e i test associati. Controlla i tipi inferiti per il patching predefinito, new, new_callable e i casi con new_callable non chiamabile; il lavoro è completo quando entrambe le API accettano solo factory chiamabili e inferiscono correttamente il tipo creato.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Steps to reproduce
from unittest.mock import patch
class NewPrinter:
pass
with patch("pprint.PrettyPrinter", new_callable=lambda: NewPrinter) as patched_printer:
print(patched_printer) # <class '__main__.NewPrinter'>
reveal_type(patched_printer) # "Union[unittest.mock.MagicMock, unittest.mock.AsyncMock]"
Same deal with unittest.mock.patch.object
from unittest.mock import patch
import pprint
class NewPrinter:
...
with patch.object(pprint, "PrettyPrinter", new_callable=lambda: NewPrinter) as patched_printer:
print(patched_printer) # <class '__main__.NewPrinter'>
reveal_type(patched_printer) # "Union[unittest.mock.MagicMock, unittest.mock.AsyncMock]"
Suggested fix
We discuss unittest.mock.patch in the following, but the same principles apply to unittest.mock.patch.object too
Current signatures:
@overload
def __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]: ...
@overload
def __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_callableshouldn't beAny | Nonein the first place, it should only acceptCallable| None, as the it will raise if the provided value is not a callablewith patch("pprint.PrettyPrinter", new_callable=1) as patched_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:
@overload
def __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]: ...
@overload
def __call__(
self,
target: str,
*,
spec: Any | None = ...,
create: bool = ...,
spec_set: Any | None = ...,
autospec: Any | None = ...,
new_callable: Callable[..., _T],
**kwargs: Any,
) -> _patch[_T]
@overload
def __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
from unittest.mock import patch
class NewPrinter:
pass
with patch("pprint.PrettyPrinter") as patched_printer:
print(patched_printer) # <MagicMock name='PrettyPrinter' id='125908774402896'>
reveal_type(patched_printer) # MagicMock | AsyncMock
with patch("pprint.PrettyPrinter", new=NewPrinter) as patched_printer:
print(patched_printer) # <class '__main__.NewPrinter'>
reveal_type(patched_printer) # type[NewPrinter]
with patch("pprint.PrettyPrinter", new_callable=lambda: NewPrinter) as patched_printer:
print(patched_printer) # <class '__main__.NewPrinter'>
reveal_type(patched_printer) # type[NewPrinter]
# No overload variant matches for non-callable type
with patch("pprint.PrettyPrinter", new_callable="non-callable") as patched_printer:
...
Haven't tried unittest.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 :)
- Lingua principale
- Python
- Stelle
- 5.1k
- Fork
- 2.1k
- Merge medio
- 2g 1h
- PR unite (30g)
- 115
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di python/typeshed
-
`networkx.set_edge_attributes` should support scalar value + nameForse già presa @Fire162 l’ha presa 10 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
I maintainer di solito rispondono entro 1 giorno
-
false alarm on decode callForse già presa @jw9829 l’ha presa 38 giorni fa. Apertahelp wanted stubs: false positive
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
python/typeshed#16441 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Don't run pyright basic checks on projects with strict pyright settings in CIForse già presa @Mohith1612 l’ha presa 74 giorni fa. Apertaproject: infrastructure
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
python/typeshed#16005 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
stubs: improvement
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
python/typeshed#15548 · 5 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
stubs: improvement
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
python/typeshed#15529 · 5 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di python/typeshed
Issue simili
-
bump patch
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
autowarefoundation/autoware_carla_scenario#1321 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 1-3 ore Idoneità per principianti 78/100
QuantConnect/Documentation#2838 ·
I maintainer di solito rispondono entro 1 giorno
-
get_all_subclasses must deduplicate by class identityForse già presa @Gambit-Checkmate l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 15 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
awslabs/route53-dynamic-dns-with-lambda#67 · 1 commento ·