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]

Reply via email to