Don't report deleted attributes in __dir__ (GH#10148)

When an attribute is deleted from a Mock, a sentinel is added rather
than just deleting the attribute. This commit checks for such sentinels
when returning the child mocks in the __dir__ method as users won't
expect deleted attributes to appear when performing dir(mock).
This commit is contained in:
Mario Corchero 2019-04-30 19:56:36 +01:00 committed by Chris Withers
parent d537ab0ff9
commit 0df635c7f8
3 changed files with 15 additions and 2 deletions

View File

@ -684,12 +684,14 @@ class NonCallableMock(Base):
extras = self._mock_methods or [] extras = self._mock_methods or []
from_type = dir(type(self)) from_type = dir(type(self))
from_dict = list(self.__dict__) from_dict = list(self.__dict__)
from_child_mocks = [
m_name for m_name, m_value in self._mock_children.items()
if m_value is not _deleted]
from_type = [e for e in from_type if not e.startswith('_')] from_type = [e for e in from_type if not e.startswith('_')]
from_dict = [e for e in from_dict if not e.startswith('_') or from_dict = [e for e in from_dict if not e.startswith('_') or
_is_magic(e)] _is_magic(e)]
return sorted(set(extras + from_type + from_dict + return sorted(set(extras + from_type + from_dict + from_child_mocks))
list(self._mock_children)))
def __setattr__(self, name, value): def __setattr__(self, name, value):

View File

@ -885,6 +885,15 @@ class MockTest(unittest.TestCase):
patcher.stop() patcher.stop()
def test_dir_does_not_include_deleted_attributes(self):
mock = Mock()
mock.child.return_value = 1
self.assertIn('child', dir(mock))
del mock.child
self.assertNotIn('child', dir(mock))
def test_configure_mock(self): def test_configure_mock(self):
mock = Mock(foo='bar') mock = Mock(foo='bar')
self.assertEqual(mock.foo, 'bar') self.assertEqual(mock.foo, 'bar')

View File

@ -0,0 +1,2 @@
Don't return deleted attributes when calling dir on a
:class:`unittest.mock.Mock`.