Skip to content

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

Merged
srittau merged 5 commits into
python:mainfrom
leonarduschen:fix-unittest-mock-patch-and-object
Jul 16, 2025
Merged

Fix unittest.mock.patch and unittest.mock.patch.object when new_callable is not None#14358
srittau merged 5 commits into
python:mainfrom
leonarduschen:fix-unittest-mock-patch-and-object

Conversation

@leonarduschen
Copy link
Copy Markdown
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
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

sure!

@github-actions
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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