Skip to content

Fix unittest.mock.patch and unittest.mock.patch.object when new_callable is not None #14358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 16, 2025

Conversation

leonarduschen
Copy link
Contributor

@leonarduschen leonarduschen commented Jul 1, 2025

This PR fixes multiple issues with unittest.mock.patch and unittest.mock.patch.object

  • Both should only accept Callable | None for new_callable, currently Any | None
  • When used as context managers, both should return T for new_callable: Callable[..., T], currently they both return Mock | AsyncMock
  • When used as decorators to functions:
    • When neither new nor new_callable is given, the function signature should be updated (the mock is passed as last parameter), patch already has the correct behavior but patch.object does not
    • When new_callable is given, same as above, should update function signature. patch already has the correct behavior (by chance, explicit new_callable is not actually handled), but patch.object does not

Addresses #14339

@leonarduschen leonarduschen changed the title Fix patch and patch.object when new_callable is not None Fix unittest.mock.patch and unittest.mock.patch.object when new_callable is not None Jul 1, 2025

This comment has been minimized.

Copy link
Collaborator

@hauntsaninja hauntsaninja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be interested in adding a few test cases to https://github.com/python/typeshed/blob/main/stdlib/%40tests/test_cases/check_unittest.py ? (the unittest.mock stubs can get a little tricky)

@leonarduschen
Copy link
Contributor Author

sure!

Copy link
Contributor

github-actions bot commented Jul 2, 2025

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

@leonarduschen
Copy link
Contributor Author

I've updated the original PR description to explain what this PR is fixing

@@ -5,9 +5,9 @@
from datetime import datetime, timedelta
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test result with old implementation

check_unittest.py:190: error: Expression is of type "MagicMock | AsyncMock", not "int"  [assert-type]
check_unittest.py:213: error: Missing positional argument "mock" in call to "obj_f_default_new"  [call-arg]
check_unittest.py:214: error: Missing positional argument "mock" in call to "obj_f_default_new"  [call-arg]
check_unittest.py:214: error: Argument 1 to "obj_f_default_new" has incompatible type "str"; expected "int"  [arg-type]
check_unittest.py:217: error: Missing positional argument "new_callable_ret" in call to "obj_f_explicit_new_callable"  [call-arg]
check_unittest.py:218: error: Missing positional argument "new_callable_ret" in call to "obj_f_explicit_new_callable"  [call-arg]
check_unittest.py:218: error: Argument 1 to "obj_f_explicit_new_callable" has incompatible type "str"; expected "int"  [arg-type]
check_unittest.py:228: error: Expression is of type "MagicMock | AsyncMock", not "int"  [assert-type]

This agrees with the upated PR description:

This PR fixes multiple issues with unittest.mock.patch and unittest.mock.patch.object

  • Both should only accept Callable | None for new_callable, currently Any | None

  • When used as context managers, both should return T for new_callable: Callable[..., T], currently they both return Mock | AsyncMock

  • When used as decorators to functions:

    • When neither new nor new_callable is given, the function signature should be updated (the mock is passed as last parameter), patch already has the correct behavior but patch.object does not
    • When new_callable is given, same as above, should update function signature. patch already has the correct behavior (by chance, explicit new_callable is not actually handled), but patch.object does not

Copy link
Collaborator

@srittau srittau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@srittau srittau merged commit a1ae191 into python:main Jul 16, 2025
64 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants