mirror of
https://github.com/python/cpython.git
synced 2025-08-02 08:02:56 +00:00
Issue #26750: unittest.mock.create_autospec() now works properly
for subclasses of property() and other data descriptors.
This commit is contained in:
parent
abfe28b012
commit
9854789efe
3 changed files with 51 additions and 22 deletions
|
@ -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,
|
||||||
_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):
|
||||||
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 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 MyProperty(property):
|
||||||
|
pass
|
||||||
|
|
||||||
class Foo(object):
|
class Foo(object):
|
||||||
|
__slots__ = ['slot']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def foo(self):
|
def prop(self):
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
foo = create_autospec(Foo)
|
@MyProperty
|
||||||
mock_property = foo.foo
|
def subprop(self):
|
||||||
|
return 4
|
||||||
|
|
||||||
# no spec on properties
|
desc = Descriptor(42)
|
||||||
self.assertIsInstance(mock_property, MagicMock)
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
def test_autospec_slots(self):
|
|
||||||
class Foo(object):
|
|
||||||
__slots__ = ['a']
|
|
||||||
|
|
||||||
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
|
||||||
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.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue