@@ -182,12 +182,12 @@ def _instance_callable(obj):
182182 return False
183183
184184
185- def _set_signature (mock , original , instance = False ):
185+ def _set_signature (mock , original , instance = False , skipfirst = False ):
186186 # creates a function with signature (*args, **kwargs) that delegates to a
187187 # mock. It still does signature checking by calling a lambda with the same
188188 # signature as the original.
189189
190- skipfirst = isinstance (original , type )
190+ skipfirst = skipfirst or isinstance (original , type )
191191 result = _get_signature_object (original , instance , skipfirst )
192192 if result is None :
193193 return mock
@@ -200,28 +200,41 @@ def checksig(*args, **kwargs):
200200 if not name .isidentifier ():
201201 name = 'funcopy'
202202 context = {'_checksig_' : checksig , 'mock' : mock }
203- src = """def %s(*args, **kwargs):
203+ if skipfirst :
204+ src = """def %s(_mock_self, /, *args, **kwargs):
205+ _checksig_(*args, **kwargs)
206+ return mock(*args, **kwargs)""" % name
207+ else :
208+ src = """def %s(*args, **kwargs):
204209 _checksig_(*args, **kwargs)
205210 return mock(*args, **kwargs)""" % name
206211 exec (src , context )
207212 funcopy = context [name ]
208213 _setup_func (funcopy , mock , sig )
209214 return funcopy
210215
211- def _set_async_signature (mock , original , instance = False , is_async_mock = False ):
216+ def _set_async_signature (mock , original , instance = False , is_async_mock = False , skipfirst = False ):
212217 # creates an async function with signature (*args, **kwargs) that delegates to a
213218 # mock. It still does signature checking by calling a lambda with the same
214219 # signature as the original.
215220
216- skipfirst = isinstance (original , type )
217- func , sig = _get_signature_object (original , instance , skipfirst )
221+ skipfirst = skipfirst or isinstance (original , type )
222+ result = _get_signature_object (original , instance , skipfirst )
223+ if result is None :
224+ return mock
225+ func , sig = result
218226 def checksig (* args , ** kwargs ):
219227 sig .bind (* args , ** kwargs )
220228 _copy_func_details (func , checksig )
221229
222230 name = original .__name__
223231 context = {'_checksig_' : checksig , 'mock' : mock }
224- src = """async def %s(*args, **kwargs):
232+ if skipfirst :
233+ src = """async def %s(_mock_self, /, *args, **kwargs):
234+ _checksig_(*args, **kwargs)
235+ return await mock(*args, **kwargs)""" % name
236+ else :
237+ src = """async def %s(*args, **kwargs):
225238 _checksig_(*args, **kwargs)
226239 return await mock(*args, **kwargs)""" % name
227240 exec (src , context )
@@ -1508,6 +1521,7 @@ def __enter__(self):
15081521 raise TypeError ("Can't provide explicit spec_set *and* spec or autospec" )
15091522
15101523 original , local = self .get_original ()
1524+ _is_classmethod = _is_staticmethod = False
15111525
15121526 if new is DEFAULT and autospec is None :
15131527 inherit = False
@@ -1593,7 +1607,10 @@ def __enter__(self):
15931607 raise TypeError ("Can't use 'autospec' with create=True" )
15941608 spec_set = bool (spec_set )
15951609 if autospec is True :
1596- autospec = original
1610+ if isinstance (self .target , type ):
1611+ autospec = getattr (self .target , self .attribute , original )
1612+ else :
1613+ autospec = original
15971614
15981615 if _is_instance_mock (self .target ):
15991616 raise InvalidSpecError (
@@ -1607,14 +1624,34 @@ def __enter__(self):
16071624 f'{ target_name !r} as it has already been mocked out. '
16081625 f'[target={ self .target !r} , attr={ autospec !r} ]' )
16091626
1627+ # For regular methods on classes, self is passed by the descriptor
1628+ # protocol but should not be recorded in mock call args.
1629+ _eat_self = _must_skip (
1630+ self .target , self .attribute , isinstance (self .target , type )
1631+ )
1632+
1633+ _is_classmethod = isinstance (original , classmethod )
1634+ _is_staticmethod = isinstance (original , staticmethod )
1635+ if _is_classmethod :
1636+ autospec = original .__func__
1637+ _eat_self = True
1638+
16101639 new = create_autospec (autospec , spec_set = spec_set ,
1611- _name = self .attribute , ** kwargs )
1640+ _name = self .attribute , _eat_self = _eat_self ,
1641+ ** kwargs )
16121642 elif kwargs :
16131643 # can't set keyword args when we aren't creating the mock
16141644 # XXXX If new is a Mock we could call new.configure_mock(**kwargs)
16151645 raise TypeError ("Can't pass kwargs to a mock we aren't creating" )
16161646
16171647 new_attr = new
1648+ if isinstance (new_attr , FunctionTypes ):
1649+ if _is_classmethod :
1650+ _check_signature (original .__func__ , new .mock , skipfirst = True )
1651+ new_attr = classmethod (new )
1652+ new = new .mock
1653+ elif _is_staticmethod :
1654+ new_attr = staticmethod (new )
16181655
16191656 self .temp_original = original
16201657 self .is_local = local
@@ -2746,7 +2783,7 @@ def call_list(self):
27462783
27472784
27482785def create_autospec (spec , spec_set = False , instance = False , _parent = None ,
2749- _name = None , * , unsafe = False , ** kwargs ):
2786+ _name = None , * , unsafe = False , _eat_self = False , ** kwargs ):
27502787 """Create a mock object using another object as a spec. Attributes on the
27512788 mock will use the corresponding attribute on the `spec` object as their
27522789 spec.
@@ -2823,17 +2860,17 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
28232860 Klass = NonCallableMagicMock
28242861
28252862 mock = Klass (parent = _parent , _new_parent = _parent , _new_name = _new_name ,
2826- name = _name , ** _kwargs )
2863+ name = _name , _eat_self = _eat_self or None , ** _kwargs )
28272864 if is_dataclass_spec :
28282865 mock ._mock_extend_spec_methods (dataclass_spec_list )
28292866
28302867 if isinstance (spec , FunctionTypes ):
28312868 # should only happen at the top level because we don't
28322869 # recurse for functions
28332870 if is_async_func :
2834- mock = _set_async_signature (mock , spec )
2871+ mock = _set_async_signature (mock , spec , skipfirst = _eat_self )
28352872 else :
2836- mock = _set_signature (mock , spec )
2873+ mock = _set_signature (mock , spec , skipfirst = _eat_self )
28372874 else :
28382875 _check_signature (spec , mock , is_type , instance )
28392876
0 commit comments