summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doc/library/unittest.mock.rst4
-rw-r--r--Doc/whatsnew/3.7.rst7
-rw-r--r--Lib/unittest/mock.py6
-rw-r--r--Lib/unittest/test/testmock/testsentinel.py13
-rw-r--r--Misc/NEWS3
5 files changed, 33 insertions, 0 deletions
diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst
index 3cc22fdde7..ca5c2bc787 100644
--- a/Doc/library/unittest.mock.rst
+++ b/Doc/library/unittest.mock.rst
@@ -1831,6 +1831,10 @@ sentinel
the same attribute will always return the same object. The objects
returned have a sensible repr so that test failure messages are readable.
+ .. versionchanged:: 3.7
+ The ``sentinel`` attributes now preserve their identity when they are
+ :mod:`copied <copy>` or :mod:`pickled <pickle>`.
+
Sometimes when testing you need to test that a specific object is passed as an
argument to another method, or returned. It can be common to create named
sentinel objects to test this. :data:`sentinel` provides a convenient way of
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index 0d19f25942..a2e6422793 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -93,6 +93,13 @@ New Modules
Improved Modules
================
+unittest.mock
+-------------
+
+The :const:`~unittest.mock.sentinel` attributes now preserve their identity
+when they are :mod:`copied <copy>` or :mod:`pickled <pickle>`.
+(Contributed by Serhiy Storchaka in :issue:`20804`.)
+
Optimizations
=============
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index dbb05d780e..2ec14e555a 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -238,6 +238,9 @@ class _SentinelObject(object):
def __repr__(self):
return 'sentinel.%s' % self.name
+ def __reduce__(self):
+ return 'sentinel.%s' % self.name
+
class _Sentinel(object):
"""Access attributes to return a named object, usable as a sentinel."""
@@ -250,6 +253,9 @@ class _Sentinel(object):
raise AttributeError
return self._sentinels.setdefault(name, _SentinelObject(name))
+ def __reduce__(self):
+ return 'sentinel'
+
sentinel = _Sentinel()
diff --git a/Lib/unittest/test/testmock/testsentinel.py b/Lib/unittest/test/testmock/testsentinel.py
index 3fb5acbc25..de53509803 100644
--- a/Lib/unittest/test/testmock/testsentinel.py
+++ b/Lib/unittest/test/testmock/testsentinel.py
@@ -1,4 +1,6 @@
import unittest
+import copy
+import pickle
from unittest.mock import sentinel, DEFAULT
@@ -23,6 +25,17 @@ class SentinelTest(unittest.TestCase):
# If this doesn't raise an AttributeError then help(mock) is broken
self.assertRaises(AttributeError, lambda: sentinel.__bases__)
+ def testPickle(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL+1):
+ with self.subTest(protocol=proto):
+ pickled = pickle.dumps(sentinel.whatever, proto)
+ unpickled = pickle.loads(pickled)
+ self.assertIs(unpickled, sentinel.whatever)
+
+ def testCopy(self):
+ self.assertIs(copy.copy(sentinel.whatever), sentinel.whatever)
+ self.assertIs(copy.deepcopy(sentinel.whatever), sentinel.whatever)
+
if __name__ == '__main__':
unittest.main()
diff --git a/Misc/NEWS b/Misc/NEWS
index bf7e5989d8..db9243fa3c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -212,6 +212,9 @@ Core and Builtins
Library
-------
+- Issue #20804: The unittest.mock.sentinel attributes now preserve their
+ identity when they are copied or pickled.
+
- Issue #29142: In urllib.request, suffixes in no_proxy environment variable with
leading dots could match related hostnames again (e.g. .b.c matches a.b.c).
Patch by Milan Oberkirch.