Skip to content

bpo-32092: Mock patch fix autospec#4476

Open
claudiubelu wants to merge 1 commit into
python:mainfrom
claudiubelu:mock-patch-fix-autospec
Open

bpo-32092: Mock patch fix autospec#4476
claudiubelu wants to merge 1 commit into
python:mainfrom
claudiubelu:mock-patch-fix-autospec

Conversation

@claudiubelu

@claudiubelu claudiubelu commented Nov 20, 2017

Copy link
Copy Markdown

bpo-32092: Fixes mock.patch autospec self / cls argument consumption issue

https://bugs.python.org/issue32092

#76273

Currently, when patching methods with autospec, their self arguments are not consumed, causing call asserts to fail (they
expect an instance reference as the first argument).

Example:

from unittest import mock

class Something(object):
    def foo(self, a):
        pass

patcher = mock.patch.object(Something, 'foo', autospec=True)
patcher.start()

s = Something()

s.foo("foo")

s.foo.assert_called_once_with("foo")

The assertion above will fail, expecting an instance as a first argument. This issue only occurs in this scenario, and not in any of the following scenarios:

  • autospec=False
  • if the autospecced method is a classmethod or a staticmethod
  • if an instance is patched instead of a class
  • if mock.create_autospec(Something) is used instead
  • if mock.Mock(autospec=Something) is used instead (if the PR adding it gets accepted)

This issue affects all patch variants.

self is now consumed by the generated wrapper and excluded from call recording and signature checking, in both the sync and async paths.

wraps and side_effect still get self bound for the call if needed, since they need to proxy through to a potentially unbound callable (e.g.: wraps=getattr(cls, name).

Adds test coverage across instance methods, classmethods, staticmethods, sync and async, for both wraps and side_effect, including a recursive-wraps regression test.

@claudiubelu
claudiubelu force-pushed the mock-patch-fix-autospec branch 2 times, most recently from d59fe18 to 797f190 Compare November 20, 2017 16:12
@AraHaan

AraHaan commented Nov 20, 2017

Copy link
Copy Markdown
Contributor

@BCLAU mind editing the PR title to add bpo-32092: on the beginning to fix the CI-bot?

Also is bpo-32092 the replacement for bpo-30587?

@claudiubelu claudiubelu changed the title Mock patch fix autospec bpo-32092: Mock patch fix autospec Nov 20, 2017
@claudiubelu

claudiubelu commented Nov 20, 2017

Copy link
Copy Markdown
Author

Hi @AraHaan , sure, will do.

And I agree. Yeah, I would have sent the fixes separately, but this depends on the other one, which I've sent separately: #1982

Once that one merges, I can simply rebase this one. Or, I could simply separate them, but they'll have a merge conflict.

@AraHaan

AraHaan commented Nov 20, 2017

Copy link
Copy Markdown
Contributor

Or, just merge the 2 and close out the older one?

@claudiubelu

Copy link
Copy Markdown
Author

Hm, tbh, I'd like to keep it simple, since they're both addressing different issues.

Anyways, I guess I'll just separate this patch from the other. We'll deal with the merge conflict when it happens.

@claudiubelu

Copy link
Copy Markdown
Author

Actually, nevermind, the unit tests are not passing without the 1st patch. :)

@AraHaan

AraHaan commented Nov 20, 2017

Copy link
Copy Markdown
Contributor

alright then.

@csabella

Copy link
Copy Markdown
Contributor

@claudiubelu, please resolve the merge conflicts. Thank you!

@cjw296

cjw296 commented Jan 24, 2020

Copy link
Copy Markdown
Contributor

@claudiubelu - it looks like #1982 is with @voidspace and this PR depends on it? Would it be okay to close that one until #1982 is resolved?

@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label Aug 13, 2022
@github-actions github-actions Bot removed the stale Stale PR or inactive for long period of time. label Feb 24, 2026
stephenfin added a commit to stephenfin/cpython that referenced this pull request Mar 27, 2026
Currently, when patching instance / class methods with autospec, their
self / cls arguments are not consumed, causing call asserts to fail
(they expect an instance / class reference as the first argument).
Example:

  from unittest import mock

  class Something(object):
      def foo(self, a, b, c, d):
          pass

  with mock.patch.object(Something, 'foo', autospec=True):
      s = Something()
      s.foo()

Fix this by skipping the first argument when presented with a method.

Based on python#4476

Signed-off-by: Stephen Finucane <stephen@that.guru>
Co-authored-by: Claudiu Belu <cbelu@cloudbasesolutions.com>
stephenfin added a commit to stephenfin/cpython that referenced this pull request Mar 27, 2026
Currently, when patching instance / class methods with autospec, their
self / cls arguments are not consumed, causing call asserts to fail
(they expect an instance / class reference as the first argument).
Example:

  from unittest import mock

  class Something(object):
      def foo(self, a, b, c, d):
          pass

  with mock.patch.object(Something, 'foo', autospec=True):
      s = Something()
      s.foo()

Fix this by skipping the first argument when presented with a method.

Based on python#4476

Signed-off-by: Stephen Finucane <stephen@that.guru>
Co-authored-by: Claudiu Belu <cbelu@cloudbasesolutions.com>
@github-actions

github-actions Bot commented May 9, 2026

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label May 9, 2026
@claudiubelu
claudiubelu force-pushed the mock-patch-fix-autospec branch from 60bbe51 to 18deb31 Compare July 25, 2026 13:18
@claudiubelu
claudiubelu requested a review from cjw296 as a code owner July 25, 2026 13:18
Currently, when patching methods with autospec, their self
arguments are not consumed, causing call asserts to fail (they
expect an instance reference as the first argument).

Example:

```
from unittest import mock

class Something(object):
    def foo(self, a):
        pass

patcher = mock.patch.object(Something, 'foo', autospec=True)
patcher.start()

s = Something()

s.foo("foo")

s.foo.assert_called_once_with("foo")
```

The assertion above will fail, expecting an instance as a first
argument. This issue **only** occurs in this scenario, and **not**
in any of the following scenarios:
- `autospec=False`
- if the autospecced method is a `classmethod` or a `staticmethod`
- if an instance is patched instead of a class
- if `mock.create_autospec(Something)` is used instead
- if `mock.Mock(autospec=Something)` is used instead

This issue affects all patch variants.

self is now consumed by the generated wrapper and excluded from call
recording and signature checking, in both the sync and async paths.

wraps and side_effect still get `self` bound for the call if needed,
since they need to proxy through to a potentially unbound callable (e.g.:
`wraps=getattr(cls, name)`.

Adds test coverage across instance methods, classmethods,
staticmethods, sync and async, for both wraps and side_effect,
including a recursive-wraps regression test.

Signed-off-by: Claudiu Belu <cbelu@cloudbasesolutions.com>
@github-actions github-actions Bot removed the stale Stale PR or inactive for long period of time. label Jul 25, 2026
@claudiubelu
claudiubelu force-pushed the mock-patch-fix-autospec branch from 18deb31 to 3f8c8ff Compare July 26, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants