diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -60,14 +60,10 @@ ) -class _slotted(object): - __slots__ = ['a'] - - -DescriptorTypes = ( - type(_slotted.a), - property, -) +def _is_data_descriptor(obj): + # Data descriptors are Properties, slots, getsets and C data members. + return ((hasattr(obj, '__set__') or hasattr(obj, '__del__')) and + hasattr(obj, '__get__')) def _get_signature_object(func, as_instance, eat_self): @@ -2147,7 +2143,7 @@ _kwargs.update(kwargs) Klass = MagicMock - if type(spec) in DescriptorTypes: + if _is_data_descriptor(spec): # descriptors don't have a spec # because we don't know what type they return _kwargs = {} diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py --- a/Lib/unittest/test/testmock/testhelpers.py +++ b/Lib/unittest/test/testmock/testhelpers.py @@ -833,6 +833,32 @@ mock_slot.abc.assert_called_once_with(4, 5, 6) + def test_autospec_data_descriptor(self): + class Descriptor(object): + def __init__(self, value): + self.value = value + + def __get__(self, obj, cls=None): + if obj is None: + return self + return self.value + + def __set__(self, obj, value): + pass + + class Foo(object): + foo = Descriptor(42) + + foo = create_autospec(Foo) + mock_descr = foo.foo + + # no spec on data descriptors + self.assertTrue(isinstance(mock_descr, MagicMock)) + mock_descr(1, 2, 3) + mock_descr.abc(4, 5, 6) + mock_descr.assert_called_once_with(1, 2, 3) + + class TestCallList(unittest.TestCase): def test_args_list_contains_call_list(self):