From 08decc96e7d53847c0097b6c155735291462f63a Mon Sep 17 00:00:00 2001 From: Vaclav Brozek Date: Thu, 10 Dec 2020 20:43:49 +0100 Subject: [PATCH 1/6] bpo-41877: Check for misspelled speccing arguments patch, patch.object and create_autospec silently ignore misspelled arguments such as autospect, auto_spec and set_spec. This can lead to tests failing to check what they are supposed to check. This change adds a check causing a RuntimeError if the above functions get any of the above misspellings as arguments. It also adds a new argument, "unsafe", which can be set to True to disable this check. --- Lib/unittest/mock.py | 47 ++++++++++++++++------ Lib/unittest/test/testmock/testmock.py | 52 +++++++++++++++++++++++++ Lib/unittest/test/testmock/testpatch.py | 4 +- 3 files changed, 89 insertions(+), 14 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index d43ea9e23c899c..78ab75cb0e8b61 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -654,8 +654,8 @@ def __getattr__(self, name): elif isinstance(result, _SpecState): result = create_autospec( - result.spec, result.spec_set, result.instance, - result.parent, result.name + result.spec, spec_set=result.spec_set, instance=result.instance, + _parent=result.parent, _name=result.name ) self._mock_children[name] = result @@ -1242,6 +1242,17 @@ def _importer(target): return thing +# _check_spec_arg_typos takes kwargs from commands like patch and checks that +# they don't contain common misspellings of arguments related to autospeccing. +def _check_spec_arg_typos(kwargs_to_check): + typos = ["autospect", "auto_spec", "set_spec"] + for typo in typos: + if typo in kwargs_to_check: + raise RuntimeError( + f"{typo} might be a typo; use unsafe=True if this is intended" + ) + + class _patch(object): attribute_name = None @@ -1249,7 +1260,7 @@ class _patch(object): def __init__( self, getter, attribute, new, spec, create, - spec_set, autospec, new_callable, kwargs + spec_set, autospec, new_callable, unsafe, kwargs ): if new_callable is not None: if new is not DEFAULT: @@ -1260,6 +1271,8 @@ def __init__( raise ValueError( "Cannot use 'autospec' and 'new_callable' together" ) + if not unsafe: + _check_spec_arg_typos(kwargs) self.getter = getter self.attribute = attribute @@ -1278,7 +1291,7 @@ def copy(self): patcher = _patch( self.getter, self.attribute, self.new, self.spec, self.create, self.spec_set, - self.autospec, self.new_callable, self.kwargs + self.autospec, self.new_callable, False, self.kwargs ) patcher.attribute_name = self.attribute_name patcher.additional_patchers = [ @@ -1569,7 +1582,7 @@ def _get_target(target): def _patch_object( target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, - new_callable=None, **kwargs + new_callable=None, unsafe=False, **kwargs ): """ patch the named member (`attribute`) on an object (`target`) with a mock @@ -1591,7 +1604,7 @@ def _patch_object( getter = lambda: target return _patch( getter, attribute, new, spec, create, - spec_set, autospec, new_callable, kwargs + spec_set, autospec, new_callable, unsafe, kwargs ) @@ -1631,13 +1644,13 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None, attribute, new = items[0] patcher = _patch( getter, attribute, new, spec, create, spec_set, - autospec, new_callable, {} + autospec, new_callable, False, {} ) patcher.attribute_name = attribute for attribute, new in items[1:]: this_patcher = _patch( getter, attribute, new, spec, create, spec_set, - autospec, new_callable, {} + autospec, new_callable, False, {} ) this_patcher.attribute_name = attribute patcher.additional_patchers.append(this_patcher) @@ -1646,7 +1659,7 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None, def patch( target, new=DEFAULT, spec=None, create=False, - spec_set=None, autospec=None, new_callable=None, **kwargs + spec_set=None, autospec=None, new_callable=None, unsafe=False, **kwargs ): """ `patch` acts as a function decorator, class decorator or a context @@ -1708,6 +1721,10 @@ def patch( use "as" then the patched object will be bound to the name after the "as"; very useful if `patch` is creating a mock object for you. + Patch will raise a `RuntimeError` if passed some common misspellings of + the arguments autospec and spec_set. Pass the argument `unsafe` with the + value True to disable that check. + `patch` takes arbitrary keyword arguments. These will be passed to `AsyncMock` if the patched object is asynchronous, to `MagicMock` otherwise or to `new_callable` if specified. @@ -1718,7 +1735,7 @@ def patch( getter, attribute = _get_target(target) return _patch( getter, attribute, new, spec, create, - spec_set, autospec, new_callable, kwargs + spec_set, autospec, new_callable, unsafe, kwargs ) @@ -2567,8 +2584,8 @@ def call_list(self): call = _Call(from_kall=False) -def create_autospec(spec, spec_set=False, instance=False, _parent=None, - _name=None, **kwargs): +def create_autospec(spec, spec_set=False, instance=False, unsafe=False, + _parent=None, _name=None, **kwargs): """Create a mock object using another object as a spec. Attributes on the mock will use the corresponding attribute on the `spec` object as their spec. @@ -2584,6 +2601,10 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None, spec for an instance object by passing `instance=True`. The returned mock will only be callable if instances of the mock are callable. + `create_autospec` will raise a `RuntimeError` if passed some common + misspellings of the arguments autospec and spec_set. Pass the argument + `unsafe` with the value True to disable that check. + `create_autospec` also takes arbitrary keyword arguments that are passed to the constructor of the created mock.""" if _is_list(spec): @@ -2601,6 +2622,8 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None, _kwargs = {} if _kwargs and instance: _kwargs['_spec_as_instance'] = True + if not unsafe: + _check_spec_arg_typos(kwargs) _kwargs.update(kwargs) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index 016905c3b90e5c..d763bf46317e25 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -38,6 +38,12 @@ def cmeth(cls, a, b, c, d=None): pass def smeth(a, b, c, d=None): pass +class Typos(object): + autospect = None + auto_spec = None + set_spec = None + + def something(a): pass @@ -2175,6 +2181,52 @@ def __init__(self): self.assertEqual(obj.obj_with_bool_func.__bool__.call_count, 0) + def test_misspelled_arguments(self): + class Foo(object): + one = 'one' + # patch, patch.object and create_autospec need to check for misspelled + # arguments explicitly and throw a RuntimError if found. + with self.assertRaises(RuntimeError): + with patch(f'{__name__}.Something.meth', autospect=True): pass + with self.assertRaises(RuntimeError): + with patch.object(Foo, 'one', autospect=True): pass + with self.assertRaises(RuntimeError): + with patch(f'{__name__}.Something.meth', auto_spec=True): pass + with self.assertRaises(RuntimeError): + with patch.object(Foo, 'one', auto_spec=True): pass + with self.assertRaises(RuntimeError): + with patch(f'{__name__}.Something.meth', set_spec=True): pass + with self.assertRaises(RuntimeError): + with patch.object(Foo, 'one', set_spec=True): pass + with self.assertRaises(RuntimeError): + m = create_autospec(Foo, set_spec=True) + # patch.multiple, on the other hand, should flag misspelled arguments + # through an AttributeError, when trying to find the keys from kwargs + # as attributes on the target. + with self.assertRaises(AttributeError): + with patch.multiple( + f'{__name__}.Something', meth=DEFAULT, autospect=True): pass + with self.assertRaises(AttributeError): + with patch.multiple( + f'{__name__}.Something', meth=DEFAULT, auto_spec=True): pass + with self.assertRaises(AttributeError): + with patch.multiple( + f'{__name__}.Something', meth=DEFAULT, set_spec=True): pass + + with patch(f'{__name__}.Something.meth', unsafe=True, autospect=True): + pass + with patch.object(Foo, 'one', unsafe=True, autospect=True): pass + with patch(f'{__name__}.Something.meth', unsafe=True, auto_spec=True): + pass + with patch.object(Foo, 'one', unsafe=True, auto_spec=True): pass + with patch(f'{__name__}.Something.meth', unsafe=True, set_spec=True): + pass + with patch.object(Foo, 'one', unsafe=True, set_spec=True): pass + m = create_autospec(Foo, set_spec=True, unsafe=True) + with patch.multiple( + f'{__name__}.Typos', autospect=True, set_spec=True, auto_spec=True): + pass + if __name__ == '__main__': unittest.main() diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py index d8c1515f8346c3..fd3584b882c452 100644 --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -1678,7 +1678,7 @@ def with_custom_patch(target): getter, attribute = _get_target(target) return custom_patch( getter, attribute, DEFAULT, None, False, None, - None, None, {} + None, None, False, {} ) @with_custom_patch('squizz.squozz') @@ -1810,7 +1810,7 @@ def stop(self): stopped.append(attribute) return super(mypatch, self).stop() return mypatch(lambda: thing, attribute, None, None, - False, None, None, None, {}) + False, None, None, None, False, {}) [get_patch(val).start() for val in ("one", "two", "three")] patch.stopall() From a19f848c1567a58a09b34a7165f0ff8e1f1e59f7 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 10 Dec 2020 19:49:52 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2020-12-10-19-49-52.bpo-41877.wiVlPc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2020-12-10-19-49-52.bpo-41877.wiVlPc.rst diff --git a/Misc/NEWS.d/next/Library/2020-12-10-19-49-52.bpo-41877.wiVlPc.rst b/Misc/NEWS.d/next/Library/2020-12-10-19-49-52.bpo-41877.wiVlPc.rst new file mode 100644 index 00000000000000..d42200ecd03de0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-10-19-49-52.bpo-41877.wiVlPc.rst @@ -0,0 +1 @@ +A check is added against misspellings of autospect, auto_spec and set_spec being passed as arguments to patch, patch.object and create_autospec. \ No newline at end of file From b2a07e4cdf4f72debafd16eb9fd55c8589aeeb53 Mon Sep 17 00:00:00 2001 From: Vaclav Brozek Date: Fri, 11 Dec 2020 08:24:24 +0100 Subject: [PATCH 3/6] Make `unsafe` a kw-only arg Also revert changes forced by `unsafe` being positional, and add "!r" to format specifiers in added error messages. --- Lib/unittest/mock.py | 30 ++++++++++++------------- Lib/unittest/test/testmock/testpatch.py | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 78ab75cb0e8b61..8777c65a0daa38 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -633,8 +633,8 @@ def __getattr__(self, name): if not self._mock_unsafe: if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')): raise AttributeError( - f"{name} is not a valid assertion. Use a spec " - f"for the mock if {name} is meant to be an attribute.") + f"{name!r} is not a valid assertion. Use a spec " + f"for the mock if {name!r} is meant to be an attribute.") result = self._mock_children.get(name) if result is _deleted: @@ -654,8 +654,8 @@ def __getattr__(self, name): elif isinstance(result, _SpecState): result = create_autospec( - result.spec, spec_set=result.spec_set, instance=result.instance, - _parent=result.parent, _name=result.name + result.spec, result.spec_set, result.instance, + result.parent, result.name ) self._mock_children[name] = result @@ -1249,7 +1249,7 @@ def _check_spec_arg_typos(kwargs_to_check): for typo in typos: if typo in kwargs_to_check: raise RuntimeError( - f"{typo} might be a typo; use unsafe=True if this is intended" + f"{typo!r} might be a typo; use unsafe=True if this is intended" ) @@ -1260,7 +1260,7 @@ class _patch(object): def __init__( self, getter, attribute, new, spec, create, - spec_set, autospec, new_callable, unsafe, kwargs + spec_set, autospec, new_callable, kwargs, *, unsafe=False ): if new_callable is not None: if new is not DEFAULT: @@ -1291,7 +1291,7 @@ def copy(self): patcher = _patch( self.getter, self.attribute, self.new, self.spec, self.create, self.spec_set, - self.autospec, self.new_callable, False, self.kwargs + self.autospec, self.new_callable, self.kwargs ) patcher.attribute_name = self.attribute_name patcher.additional_patchers = [ @@ -1582,7 +1582,7 @@ def _get_target(target): def _patch_object( target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, - new_callable=None, unsafe=False, **kwargs + new_callable=None, *, unsafe=False, **kwargs ): """ patch the named member (`attribute`) on an object (`target`) with a mock @@ -1604,7 +1604,7 @@ def _patch_object( getter = lambda: target return _patch( getter, attribute, new, spec, create, - spec_set, autospec, new_callable, unsafe, kwargs + spec_set, autospec, new_callable, kwargs, unsafe=unsafe ) @@ -1644,13 +1644,13 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None, attribute, new = items[0] patcher = _patch( getter, attribute, new, spec, create, spec_set, - autospec, new_callable, False, {} + autospec, new_callable, {} ) patcher.attribute_name = attribute for attribute, new in items[1:]: this_patcher = _patch( getter, attribute, new, spec, create, spec_set, - autospec, new_callable, False, {} + autospec, new_callable, {} ) this_patcher.attribute_name = attribute patcher.additional_patchers.append(this_patcher) @@ -1659,7 +1659,7 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None, def patch( target, new=DEFAULT, spec=None, create=False, - spec_set=None, autospec=None, new_callable=None, unsafe=False, **kwargs + spec_set=None, autospec=None, new_callable=None, *, unsafe=False, **kwargs ): """ `patch` acts as a function decorator, class decorator or a context @@ -1735,7 +1735,7 @@ def patch( getter, attribute = _get_target(target) return _patch( getter, attribute, new, spec, create, - spec_set, autospec, new_callable, unsafe, kwargs + spec_set, autospec, new_callable, kwargs, unsafe=unsafe ) @@ -2584,8 +2584,8 @@ def call_list(self): call = _Call(from_kall=False) -def create_autospec(spec, spec_set=False, instance=False, unsafe=False, - _parent=None, _name=None, **kwargs): +def create_autospec(spec, spec_set=False, instance=False, _parent=None, + _name=None, *, unsafe=False, **kwargs): """Create a mock object using another object as a spec. Attributes on the mock will use the corresponding attribute on the `spec` object as their spec. diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py index fd3584b882c452..d8c1515f8346c3 100644 --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -1678,7 +1678,7 @@ def with_custom_patch(target): getter, attribute = _get_target(target) return custom_patch( getter, attribute, DEFAULT, None, False, None, - None, None, False, {} + None, None, {} ) @with_custom_patch('squizz.squozz') @@ -1810,7 +1810,7 @@ def stop(self): stopped.append(attribute) return super(mypatch, self).stop() return mypatch(lambda: thing, attribute, None, None, - False, None, None, None, False, {}) + False, None, None, None, {}) [get_patch(val).start() for val in ("one", "two", "three")] patch.stopall() From b7fc748d5cb3ac6d9e7fc9f72d01993581c07c20 Mon Sep 17 00:00:00 2001 From: Vaclav Brozek Date: Fri, 11 Dec 2020 08:24:24 +0100 Subject: [PATCH 4/6] Make `unsafe` a kw-only arg Also revert changes forced by `unsafe` being positional, and add "!r" to format specifiers in added error messages. --- Lib/unittest/mock.py | 30 ++++++++++++------------- Lib/unittest/test/testmock/testpatch.py | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 78ab75cb0e8b61..8777c65a0daa38 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -633,8 +633,8 @@ def __getattr__(self, name): if not self._mock_unsafe: if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')): raise AttributeError( - f"{name} is not a valid assertion. Use a spec " - f"for the mock if {name} is meant to be an attribute.") + f"{name!r} is not a valid assertion. Use a spec " + f"for the mock if {name!r} is meant to be an attribute.") result = self._mock_children.get(name) if result is _deleted: @@ -654,8 +654,8 @@ def __getattr__(self, name): elif isinstance(result, _SpecState): result = create_autospec( - result.spec, spec_set=result.spec_set, instance=result.instance, - _parent=result.parent, _name=result.name + result.spec, result.spec_set, result.instance, + result.parent, result.name ) self._mock_children[name] = result @@ -1249,7 +1249,7 @@ def _check_spec_arg_typos(kwargs_to_check): for typo in typos: if typo in kwargs_to_check: raise RuntimeError( - f"{typo} might be a typo; use unsafe=True if this is intended" + f"{typo!r} might be a typo; use unsafe=True if this is intended" ) @@ -1260,7 +1260,7 @@ class _patch(object): def __init__( self, getter, attribute, new, spec, create, - spec_set, autospec, new_callable, unsafe, kwargs + spec_set, autospec, new_callable, kwargs, *, unsafe=False ): if new_callable is not None: if new is not DEFAULT: @@ -1291,7 +1291,7 @@ def copy(self): patcher = _patch( self.getter, self.attribute, self.new, self.spec, self.create, self.spec_set, - self.autospec, self.new_callable, False, self.kwargs + self.autospec, self.new_callable, self.kwargs ) patcher.attribute_name = self.attribute_name patcher.additional_patchers = [ @@ -1582,7 +1582,7 @@ def _get_target(target): def _patch_object( target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, - new_callable=None, unsafe=False, **kwargs + new_callable=None, *, unsafe=False, **kwargs ): """ patch the named member (`attribute`) on an object (`target`) with a mock @@ -1604,7 +1604,7 @@ def _patch_object( getter = lambda: target return _patch( getter, attribute, new, spec, create, - spec_set, autospec, new_callable, unsafe, kwargs + spec_set, autospec, new_callable, kwargs, unsafe=unsafe ) @@ -1644,13 +1644,13 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None, attribute, new = items[0] patcher = _patch( getter, attribute, new, spec, create, spec_set, - autospec, new_callable, False, {} + autospec, new_callable, {} ) patcher.attribute_name = attribute for attribute, new in items[1:]: this_patcher = _patch( getter, attribute, new, spec, create, spec_set, - autospec, new_callable, False, {} + autospec, new_callable, {} ) this_patcher.attribute_name = attribute patcher.additional_patchers.append(this_patcher) @@ -1659,7 +1659,7 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None, def patch( target, new=DEFAULT, spec=None, create=False, - spec_set=None, autospec=None, new_callable=None, unsafe=False, **kwargs + spec_set=None, autospec=None, new_callable=None, *, unsafe=False, **kwargs ): """ `patch` acts as a function decorator, class decorator or a context @@ -1735,7 +1735,7 @@ def patch( getter, attribute = _get_target(target) return _patch( getter, attribute, new, spec, create, - spec_set, autospec, new_callable, unsafe, kwargs + spec_set, autospec, new_callable, kwargs, unsafe=unsafe ) @@ -2584,8 +2584,8 @@ def call_list(self): call = _Call(from_kall=False) -def create_autospec(spec, spec_set=False, instance=False, unsafe=False, - _parent=None, _name=None, **kwargs): +def create_autospec(spec, spec_set=False, instance=False, _parent=None, + _name=None, *, unsafe=False, **kwargs): """Create a mock object using another object as a spec. Attributes on the mock will use the corresponding attribute on the `spec` object as their spec. diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py index fd3584b882c452..d8c1515f8346c3 100644 --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -1678,7 +1678,7 @@ def with_custom_patch(target): getter, attribute = _get_target(target) return custom_patch( getter, attribute, DEFAULT, None, False, None, - None, None, False, {} + None, None, {} ) @with_custom_patch('squizz.squozz') @@ -1810,7 +1810,7 @@ def stop(self): stopped.append(attribute) return super(mypatch, self).stop() return mypatch(lambda: thing, attribute, None, None, - False, None, None, None, False, {}) + False, None, None, None, {}) [get_patch(val).start() for val in ("one", "two", "three")] patch.stopall() From fb88a30308b9b5ce186688addc9cf4d9dcceef97 Mon Sep 17 00:00:00 2001 From: Vaclav Brozek Date: Fri, 11 Dec 2020 08:47:14 +0100 Subject: [PATCH 5/6] Fix indenting. --- Lib/unittest/test/testmock/testmock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index d763bf46317e25..5d364654855ea3 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -2225,7 +2225,7 @@ class Foo(object): m = create_autospec(Foo, set_spec=True, unsafe=True) with patch.multiple( f'{__name__}.Typos', autospect=True, set_spec=True, auto_spec=True): - pass + pass if __name__ == '__main__': From 0c3107a4bf1963cbf9576812788752514191e62b Mon Sep 17 00:00:00 2001 From: Vaclav Brozek Date: Fri, 11 Dec 2020 11:01:17 +0100 Subject: [PATCH 6/6] List -> tuple; drop object inheritance. --- Lib/unittest/mock.py | 2 +- Lib/unittest/test/testmock/testmock.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 8777c65a0daa38..720f682efbb54c 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1245,7 +1245,7 @@ def _importer(target): # _check_spec_arg_typos takes kwargs from commands like patch and checks that # they don't contain common misspellings of arguments related to autospeccing. def _check_spec_arg_typos(kwargs_to_check): - typos = ["autospect", "auto_spec", "set_spec"] + typos = ("autospect", "auto_spec", "set_spec") for typo in typos: if typo in kwargs_to_check: raise RuntimeError( diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index 5d364654855ea3..e38f41e1d21528 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -38,7 +38,7 @@ def cmeth(cls, a, b, c, d=None): pass def smeth(a, b, c, d=None): pass -class Typos(object): +class Typos(): autospect = None auto_spec = None set_spec = None @@ -2182,7 +2182,7 @@ def __init__(self): self.assertEqual(obj.obj_with_bool_func.__bool__.call_count, 0) def test_misspelled_arguments(self): - class Foo(object): + class Foo(): one = 'one' # patch, patch.object and create_autospec need to check for misspelled # arguments explicitly and throw a RuntimError if found.