https://github.com/python/cpython/commit/38ce10483c1c1ff5595dd3b3f532f96b35d33e45 commit: 38ce10483c1c1ff5595dd3b3f532f96b35d33e45 branch: main author: Dylan Semler <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-08-12T12:58:29Z summary:
gh-80762: Fix dir() on Mock with tuple specs (GH-12753) A tuple spec has been supported since the initial import and is used in tests, but it was never documented. Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: Claude Opus 5 (1M context) <[email protected]> files: A Misc/NEWS.d/next/Library/2026-08-12-14-30-00.gh-issue-80762.Kp3vQa.rst M Doc/library/unittest.mock.rst M Lib/test/test_unittest/testmock/testmock.py M Lib/unittest/mock.py diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index cce8f2833ac5a02..b9e6f65cb917df0 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -231,9 +231,10 @@ the *new_callable* argument to :func:`patch`. Create a new :class:`Mock` object. :class:`Mock` takes several optional arguments that specify the behaviour of the Mock object: - * *spec*: This can be either a list of strings or an existing object (a - class or instance) that acts as the specification for the mock object. If - you pass in an object then a list of strings is formed by calling dir on + * *spec*: This can be either a list or tuple of strings, + or an existing object (a class or instance) + that acts as the specification for the mock object. + If you pass in an object then a list of strings is formed by calling dir on the object (excluding unsupported magic attributes and methods). Accessing any attribute not in this list will raise an :exc:`AttributeError`. @@ -241,6 +242,9 @@ the *new_callable* argument to :func:`patch`. :attr:`~object.__class__` returns the class of the spec object. This allows mocks to pass :func:`isinstance` tests. + .. versionchanged:: next + :func:`dir` now works for a mock created with a tuple *spec*. + * *spec_set*: A stricter variant of *spec*. If used, attempting to *set* or get an attribute on the mock that isn't on the object passed as *spec_set* will raise an :exc:`AttributeError`. @@ -448,9 +452,9 @@ the *new_callable* argument to :func:`patch`. .. method:: mock_add_spec(spec, spec_set=False) - Add a spec to a mock. *spec* can either be an object or a - list of strings. Only attributes on the *spec* can be fetched as - attributes from the mock. + Add a spec to a mock. + *spec* can either be an object or a list or tuple of strings. + Only attributes on the *spec* can be fetched as attributes from the mock. If *spec_set* is true then only attributes on the spec can be set. diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py index 764585ec5d54688..ffc89dc5ce1562d 100644 --- a/Lib/test/test_unittest/testmock/testmock.py +++ b/Lib/test/test_unittest/testmock/testmock.py @@ -1073,6 +1073,10 @@ def test_dir(self): mock.__iter__ = lambda s: iter([]) self.assertIn('__iter__', dir(mock)) + # spec from a tuple + mock_tuple_spec = Mock(spec=('something',)) + self.assertIn('something', dir(mock_tuple_spec)) + def test_dir_from_spec(self): mock = Mock(spec=unittest.TestCase) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 49011faaa51eaed..d0ca94668e05bc2 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -798,7 +798,7 @@ def __dir__(self): 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 _is_magic(e)] - return sorted(set(extras + from_type + from_dict + from_child_mocks)) + return sorted({*extras, *from_type, *from_dict, *from_child_mocks}) def __setattr__(self, name, value): diff --git a/Misc/NEWS.d/next/Library/2026-08-12-14-30-00.gh-issue-80762.Kp3vQa.rst b/Misc/NEWS.d/next/Library/2026-08-12-14-30-00.gh-issue-80762.Kp3vQa.rst new file mode 100644 index 000000000000000..080fee4855a5e27 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-12-14-30-00.gh-issue-80762.Kp3vQa.rst @@ -0,0 +1,3 @@ +Fix :func:`dir` on :class:`unittest.mock.Mock` objects +created with a tuple *spec*: it raised :exc:`TypeError`. +Such *spec* is now also documented. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
