`unittest.mock.patch` and `unittest.mock.patch.object` are wrongly typed when new_callable is provided
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 48/100
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.
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 :)
- Ngôn ngữ chính
- Python
- Star
- 5.1k
- Fork
- 2.1k
- Merge trung bình
- 2 ngày 1 giờ
- Pull request đã merge (30 ngày)
- 115
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc 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.
Issue khác của python/typeshed
-
`networkx.set_edge_attributes` should support scalar value + nameCó thể đã có người làm @Fire162 đã nhận 10 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
Maintainer thường phản hồi trong vòng 1 ngày
-
false alarm on decode callCó thể đã có người làm @jw9829 đã nhận 37 ngày trước. Đang mởhelp wanted stubs: false positive
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
python/typeshed#16441 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Don't run pyright basic checks on projects with strict pyright settings in CICó thể đã có người làm @Mohith1612 đã nhận 74 ngày trước. Đang mởproject: infrastructure
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
python/typeshed#16005 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
stubs: improvement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
python/typeshed#15548 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
stubs: improvement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
python/typeshed#15529 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của python/typeshed
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
unionai-oss/pandera#2640 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
JdeRobot/RoboticsInfrastructure#843 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
automated endpoint-dead needs-curation
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
almanac-data/climate-almanac#122 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area:harness enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
evarness-ai/iris-harness#420 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
suitenumerique/find#206 ·
Maintainer thường phản hồi trong vòng 2 ngày