Issue #20804: The unittest.mock.sentinel attributes now preserve their

identity when they are copied or pickled.
This commit is contained in:
Serhiy Storchaka 2017-01-11 20:13:03 +02:00
parent d4f5001bac
commit d9c956fb23
5 changed files with 33 additions and 0 deletions

View File

@ -1831,6 +1831,10 @@ sentinel
the same attribute will always return the same object. The objects the same attribute will always return the same object. The objects
returned have a sensible repr so that test failure messages are readable. 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 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 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 sentinel objects to test this. :data:`sentinel` provides a convenient way of

View File

@ -93,6 +93,13 @@ New Modules
Improved 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 Optimizations
============= =============

View File

@ -238,6 +238,9 @@ class _SentinelObject(object):
def __repr__(self): def __repr__(self):
return 'sentinel.%s' % self.name return 'sentinel.%s' % self.name
def __reduce__(self):
return 'sentinel.%s' % self.name
class _Sentinel(object): class _Sentinel(object):
"""Access attributes to return a named object, usable as a sentinel.""" """Access attributes to return a named object, usable as a sentinel."""
@ -250,6 +253,9 @@ class _Sentinel(object):
raise AttributeError raise AttributeError
return self._sentinels.setdefault(name, _SentinelObject(name)) return self._sentinels.setdefault(name, _SentinelObject(name))
def __reduce__(self):
return 'sentinel'
sentinel = _Sentinel() sentinel = _Sentinel()

View File

@ -1,4 +1,6 @@
import unittest import unittest
import copy
import pickle
from unittest.mock import sentinel, DEFAULT 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 # If this doesn't raise an AttributeError then help(mock) is broken
self.assertRaises(AttributeError, lambda: sentinel.__bases__) 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__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -212,6 +212,9 @@ Core and Builtins
Library 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 - 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). leading dots could match related hostnames again (e.g. .b.c matches a.b.c).
Patch by Milan Oberkirch. Patch by Milan Oberkirch.