`unittest.mock.patch` and `unittest.mock.patch.object` are wrongly typed when new_callable is provided
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 5.1k
- Fork
- 2.1k
- Merge trung bình
- 1 ngày 19 giờ
- Pull request đã merge (30 ngày)
- 82
Mô tả
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 :)
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Xem xét các overload của unittest.mock.patch và patch.object được nêu trong issue, sau đó tìm các stub typeshed và các bài kiểm thử liên quan của chúng. Kiểm tra các kiểu được suy luận cho việc patch mặc định, new, new_callable và các trường hợp new_callable không thể gọi; hoàn tất khi cả hai API chỉ chấp nhận các factory có thể gọi và suy luận đúng kiểu được tạo ra.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python
- Lĩnh vực
- testing
- Loại issue
- Lỗi
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 48/100