Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite7ac070

Browse files
committed
Support for pickling sentinel objects as singletons
The `repr` parameters position was replaced by `module_name` to conform to PEP 661.Added copy and pickle tests.Updated documentation for Sentinel.`_marker` was defined before `caller` which causes minor issues,resolved by setting its module name manually.
1 parent19cc3bc commite7ac070

File tree

3 files changed

+45
-11
lines changed

3 files changed

+45
-11
lines changed

‎doc/index.rst‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,11 +1056,14 @@ Capsule objects
10561056
Sentinel objects
10571057
~~~~~~~~~~~~~~~~
10581058

1059-
..class::Sentinel(name, repr=None)
1059+
..class::Sentinel(name,module_name=None, *,repr=None)
10601060

10611061
A type used to define sentinel values. The *name* argument should be the
10621062
name of the variable to which the return value shall be assigned.
10631063

1064+
*module_name* is the module where the sentinel is defined.
1065+
Defaults to the current modules ``__name__``.
1066+
10641067
If *repr* is provided, it will be used for the:meth:`~object.__repr__`
10651068
of the sentinel object. If not provided, ``"<name>"`` will be used.
10661069

@@ -1076,6 +1079,13 @@ Sentinel objects
10761079
...
10771080
>>> func(MISSING)
10781081

1082+
Sentinels defined inside a class scope should use a:term:`qualified name`.
1083+
1084+
Example::
1085+
1086+
>>> class MyClass:
1087+
... MISSING = Sentinel('MyClass.MISSING')
1088+
10791089
..versionadded::4.14.0
10801090

10811091
See:pep:`661`

‎src/test_typing_extensions.py‎

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9541,6 +9541,8 @@ def test_invalid_special_forms(self):
95419541

95429542

95439543
classTestSentinels(BaseTestCase):
9544+
SENTINEL=Sentinel("TestSentinels.SENTINEL")
9545+
95449546
deftest_sentinel_no_repr(self):
95459547
sentinel_no_repr=Sentinel('sentinel_no_repr')
95469548

@@ -9570,13 +9572,26 @@ def test_sentinel_not_callable(self):
95709572
):
95719573
sentinel()
95729574

9573-
deftest_sentinel_not_picklable(self):
9574-
sentinel=Sentinel('sentinel')
9575-
withself.assertRaisesRegex(
9576-
TypeError,
9577-
"Cannot pickle 'Sentinel' object"
9578-
):
9579-
pickle.dumps(sentinel)
9575+
deftest_sentinel_copy_identity(self):
9576+
self.assertIs(self.SENTINEL,copy.copy(self.SENTINEL))
9577+
self.assertIs(self.SENTINEL,copy.deepcopy(self.SENTINEL))
9578+
9579+
anonymous_sentinel=Sentinel("anonymous_sentinel")
9580+
self.assertIs(anonymous_sentinel,copy.copy(anonymous_sentinel))
9581+
self.assertIs(anonymous_sentinel,copy.deepcopy(anonymous_sentinel))
9582+
9583+
deftest_sentinel_picklable_qualified(self):
9584+
forprotoinrange(pickle.HIGHEST_PROTOCOL+1):
9585+
self.assertIs(self.SENTINEL,pickle.loads(pickle.dumps(self.SENTINEL,protocol=proto)))
9586+
9587+
deftest_sentinel_picklable_anonymous(self):
9588+
anonymous_sentinel=Sentinel("anonymous_sentinel")# Anonymous sentinel can not be pickled
9589+
forprotoinrange(pickle.HIGHEST_PROTOCOL+1):
9590+
withself.assertRaisesRegex(
9591+
pickle.PicklingError,
9592+
r"attribute lookup anonymous_sentinel on \w+ failed|not found as \w+.anonymous_sentinel"
9593+
):
9594+
self.assertIs(anonymous_sentinel,pickle.loads(pickle.dumps(anonymous_sentinel,protocol=proto)))
95809595

95819596
defload_tests(loader,tests,pattern):
95829597
importdoctest

‎src/typing_extensions.py‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,18 +164,26 @@ class Sentinel:
164164
165165
*name* should be the name of the variable to which the return value shall be assigned.
166166
167+
*module_name* is the module where the sentinel is defined.
168+
Defaults to the current modules ``__name__``.
169+
167170
*repr*, if supplied, will be used for the repr of the sentinel object.
168171
If not provided, "<name>" will be used.
169172
"""
170173

171174
def__init__(
172175
self,
173176
name:str,
177+
module_name:typing.Optional[str]=None,
178+
*,
174179
repr:typing.Optional[str]=None,
175180
):
176181
self._name=name
177182
self._repr=reprifreprisnotNoneelsef'<{name}>'
178183

184+
# For pickling as a singleton:
185+
self.__module__=module_nameifmodule_nameisnotNoneelse_caller()
186+
179187
def__repr__(self):
180188
returnself._repr
181189

@@ -193,11 +201,12 @@ def __or__(self, other):
193201
def__ror__(self,other):
194202
returntyping.Union[other,self]
195203

196-
def__getstate__(self):
197-
raiseTypeError(f"Cannot pickle{type(self).__name__!r} object")
204+
def__reduce__(self)->str:
205+
"""Reduce this sentinel to a singleton."""
206+
returnself._name# Module is taken from the __module__ attribute
198207

199208

200-
_marker=Sentinel("sentinel")
209+
_marker=Sentinel("sentinel",module_name=__name__)
201210

202211
# The functions below are modified copies of typing internal helpers.
203212
# They are needed by _ProtocolMeta and they provide support for PEP 646.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp