`unittest.mock.patch` and `unittest.mock.patch.object` are wrongly typed when new_callable is provided
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 48/100
Línea de trabajo
Revisa las sobrecargas de unittest.mock.patch y patch.object que se muestran en el issue y, después, busca sus stubs de typeshed y las pruebas asociadas. Comprueba los tipos inferidos para el patching predeterminado, new, new_callable y los casos de new_callable no invocable; el trabajo estará terminado cuando ambas APIs acepten únicamente factories invocables e infieran correctamente el tipo creado.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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 :)
- Lenguaje dominante
- Python
- Estrellas
- 5.1k
- Forks
- 2.1k
- Merge medio
- 2 d 5 h
- PR fusionados (30 d)
- 122
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de python/typeshed
-
`networkx.set_edge_attributes` should support scalar value + namePosiblemente ocupada @Fire162 la tomó hace 11 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
Los mantenedores suelen responder en 1 día
-
false alarm on decode callPosiblemente ocupada @jw9829 la tomó hace 38 días. Abiertohelp wanted stubs: false positive
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
python/typeshed#16441 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Don't run pyright basic checks on projects with strict pyright settings in CIPosiblemente ocupada @Mohith1612 la tomó hace 75 días. Abiertoproject: infrastructure
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
python/typeshed#16005 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
stubs: improvement
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
python/typeshed#15548 · 5 comentarios ·
Los mantenedores suelen responder en 1 día
-
stubs: improvement
Dificultad 2/5 1-3 horas Aptitud para principiantes 64/100
python/typeshed#15529 · 5 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de python/typeshed
Issues similares
-
needs-area-label
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 2 días
-
enhancement good first issue
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Official-Space-AI/OpenPhysGraspGen#114 ·
Los mantenedores suelen responder en 2 días
-
changelog investigate
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
ramnes/notion-sdk-py#441 ·
-
qa_bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
NVIDIA-NeMo/Gym#5644 ·
Los mantenedores suelen responder en 2 días
-
BUG: catalog database credentials printed to logs at startupPosiblemente ocupada @cjboyle la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
Los mantenedores suelen responder en 1 día