Commit 524d375f authored by Gregory P. Smith's avatar Gregory P. Smith

Issue #26750: unittest.mock.create_autospec() now works properly

for subclasses of property() and other data descriptors.
parent d331c8ec
...@@ -64,12 +64,20 @@ class _slotted(object): ...@@ -64,12 +64,20 @@ class _slotted(object):
__slots__ = ['a'] __slots__ = ['a']
# Do not use this tuple. It was never documented as a public API.
# It will be removed. It has no obvious signs of users on github.
DescriptorTypes = ( DescriptorTypes = (
type(_slotted.a), type(_slotted.a),
property, 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): def _get_signature_object(func, as_instance, eat_self):
""" """
Given an arbitrary, possibly callable object, try to create a suitable Given an arbitrary, possibly callable object, try to create a suitable
...@@ -2130,7 +2138,7 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None, ...@@ -2130,7 +2138,7 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
_kwargs.update(kwargs) _kwargs.update(kwargs)
Klass = MagicMock Klass = MagicMock
if type(spec) in DescriptorTypes: if _is_data_descriptor(spec):
# descriptors don't have a spec # descriptors don't have a spec
# because we don't know what type they return # because we don't know what type they return
_kwargs = {} _kwargs = {}
......
...@@ -802,35 +802,53 @@ class SpecSignatureTest(unittest.TestCase): ...@@ -802,35 +802,53 @@ class SpecSignatureTest(unittest.TestCase):
a.f.assert_called_with(self=10) a.f.assert_called_with(self=10)
def test_autospec_property(self): def test_autospec_data_descriptor(self):
class Foo(object): class Descriptor(object):
@property def __init__(self, value):
def foo(self): self.value = value
return 3
foo = create_autospec(Foo) def __get__(self, obj, cls=None):
mock_property = foo.foo if obj is None:
return self
return self.value
# no spec on properties def __set__(self, obj, value):
self.assertIsInstance(mock_property, MagicMock) pass
mock_property(1, 2, 3)
mock_property.abc(4, 5, 6)
mock_property.assert_called_once_with(1, 2, 3)
mock_property.abc.assert_called_once_with(4, 5, 6)
class MyProperty(property):
pass
def test_autospec_slots(self):
class Foo(object): class Foo(object):
__slots__ = ['a'] __slots__ = ['slot']
@property
def prop(self):
return 3
@MyProperty
def subprop(self):
return 4
desc = Descriptor(42)
foo = create_autospec(Foo) foo = create_autospec(Foo)
mock_slot = foo.a
# no spec on slots def check_data_descriptor(mock_attr):
mock_slot(1, 2, 3) # Data descriptors don't have a spec.
mock_slot.abc(4, 5, 6) self.assertIsInstance(mock_attr, MagicMock)
mock_slot.assert_called_once_with(1, 2, 3) mock_attr(1, 2, 3)
mock_slot.abc.assert_called_once_with(4, 5, 6) mock_attr.abc(4, 5, 6)
mock_attr.assert_called_once_with(1, 2, 3)
mock_attr.abc.assert_called_once_with(4, 5, 6)
# property
check_data_descriptor(foo.prop)
# property subclass
check_data_descriptor(foo.subprop)
# class __slot__
check_data_descriptor(foo.slot)
# plain data descriptor
check_data_descriptor(foo.desc)
class TestCallList(unittest.TestCase): class TestCallList(unittest.TestCase):
......
...@@ -34,6 +34,9 @@ Core and Builtins ...@@ -34,6 +34,9 @@ Core and Builtins
Library Library
------- -------
- Issue #26750: unittest.mock.create_autospec() now works properly for
subclasses of property() and other data descriptors.
- Issue #27568: Prevent HTTPoxy attack (CVE-2016-1000110). Ignore the - Issue #27568: Prevent HTTPoxy attack (CVE-2016-1000110). Ignore the
HTTP_PROXY variable when REQUEST_METHOD environment is set, which indicates HTTP_PROXY variable when REQUEST_METHOD environment is set, which indicates
that the script is in CGI mode. that the script is in CGI mode.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment