Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 482fe04

Browse files
committed
issue23673
add private method to enum to support replacing global constants with Enum members: - search for candidate constants via supplied filter - create new enum class and members - insert enum class and replace constants with members via supplied module name - replace __reduce_ex__ with function that returns member name, so previous Python versions can unpickle modify IntEnum classes to use new method
1 parent d833779 commit 482fe04

4 files changed

Lines changed: 48 additions & 9 deletions

File tree

Lib/enum.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,11 +511,37 @@ def value(self):
511511
"""The value of the Enum member."""
512512
return self._value_
513513

514+
@classmethod
515+
def _convert(cls, name, module, filter, source=None):
516+
"""
517+
Create a new Enum subclass that replaces a collection of global constants
518+
"""
519+
# convert all constants from source (or module) that pass filter() to
520+
# a new Enum called name, and export the enum and its members back to
521+
# module;
522+
# also, replace the __reduce_ex__ method so unpickling works in
523+
# previous Python versions
524+
module_globals = vars(sys.modules[module])
525+
if source:
526+
source = vars(source)
527+
else:
528+
source = module_globals
529+
members = {name: value for name, value in source.items()
530+
if filter(name)}
531+
cls = cls(name, members, module=module)
532+
cls.__reduce_ex__ = _reduce_ex_by_name
533+
module_globals.update(cls.__members__)
534+
module_globals[name] = cls
535+
return cls
536+
514537

515538
class IntEnum(int, Enum):
516539
"""Enum where members are also (and must be) ints"""
517540

518541

542+
def _reduce_ex_by_name(self, proto):
543+
return self.name
544+
519545
def unique(enumeration):
520546
"""Class decorator for enumerations ensuring unique member values."""
521547
duplicates = []

Lib/socket.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@
6969
# Note that _socket only knows about the integer values. The public interface
7070
# in this module understands the enums and translates them back from integers
7171
# where needed (e.g. .family property of a socket object).
72-
AddressFamily = IntEnum('AddressFamily',
73-
{name: value for name, value in globals().items()
74-
if name.isupper() and name.startswith('AF_')})
75-
globals().update(AddressFamily.__members__)
76-
77-
SocketKind = IntEnum('SocketKind',
78-
{name: value for name, value in globals().items()
79-
if name.isupper() and name.startswith('SOCK_')})
80-
globals().update(SocketKind.__members__)
72+
IntEnum._convert(
73+
'AddressFamily',
74+
__name__,
75+
lambda C: C.isupper() and C.startswith('AF_'))
76+
77+
IntEnum._convert(
78+
'SocketKind',
79+
__name__,
80+
lambda C: C.isupper() and C.startswith('SOCK_'))
8181

8282
def _intenum_converter(value, enum_klass):
8383
"""Convert a numeric family value to an IntEnum member.

Lib/test/test_enum.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,14 @@ class NestedEnum(Enum):
581581
test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs,
582582
protocol=(4, HIGHEST_PROTOCOL))
583583

584+
def test_pickle_by_name(self):
585+
class ReplaceGlobalInt(IntEnum):
586+
ONE = 1
587+
TWO = 2
588+
ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
589+
for proto in range(HIGHEST_PROTOCOL):
590+
self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
591+
584592
def test_exploding_pickle(self):
585593
BadPickle = Enum(
586594
'BadPickle', 'dill sweet bread-n-butter', module=__name__)

Lib/test/test_socket.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,11 @@ def test_pickle(self):
13751375
with sock:
13761376
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
13771377
self.assertRaises(TypeError, pickle.dumps, sock, protocol)
1378+
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
1379+
family = pickle.loads(pickle.dumps(socket.AF_INET, protocol))
1380+
self.assertEqual(family, socket.AF_INET)
1381+
type = pickle.loads(pickle.dumps(socket.SOCK_STREAM, protocol))
1382+
self.assertEqual(type, socket.SOCK_STREAM)
13781383

13791384
def test_listen_backlog(self):
13801385
for backlog in 0, -1:

0 commit comments

Comments
 (0)