Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
9a0cbcc4
Commit
9a0cbcc4
authored
Feb 18, 2014
by
Ethan Furman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Close issue20653: allow Enum subclasses to override __reduce_ex__
parent
59a55330
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
73 additions
and
14 deletions
+73
-14
Lib/enum.py
Lib/enum.py
+13
-13
Lib/test/test_enum.py
Lib/test/test_enum.py
+60
-1
No files found.
Lib/enum.py
View file @
9a0cbcc4
...
...
@@ -116,7 +116,9 @@ class EnumMeta(type):
enum_class
.
_value2member_map_
=
{}
# check for a supported pickle protocols, and if not present sabotage
# pickling, since it won't work anyway
# pickling, since it won't work anyway.
# if new class implements its own __reduce_ex__, do not sabotage
if
classdict
.
get
(
'__reduce_ex__'
)
is
None
:
if
member_type
is
not
object
:
methods
=
(
'__getnewargs_ex__'
,
'__getnewargs__'
,
'__reduce_ex__'
,
'__reduce__'
)
...
...
@@ -167,7 +169,7 @@ class EnumMeta(type):
# double check that repr and friends are not the mixin's or various
# things break (such as pickle)
for
name
in
(
'__repr__'
,
'__str__'
,
'__format__'
,
'__
getnewargs__'
,
'__
reduce_ex__'
):
for
name
in
(
'__repr__'
,
'__str__'
,
'__format__'
,
'__reduce_ex__'
):
class_method
=
getattr
(
enum_class
,
name
)
obj_method
=
getattr
(
member_type
,
name
,
None
)
enum_method
=
getattr
(
first_enum
,
name
,
None
)
...
...
@@ -192,8 +194,9 @@ class EnumMeta(type):
(i.e. Color = Enum('Color', names='red green blue')).
When used for the functional API: `module`, if set, will be stored in
the new class' __module__ attribute; `type`, if set, will be mixed in
as the first base class.
the new class' __module__ attribute; `qualname`, if set, will be stored
in the new class' __qualname__ attribute; `type`, if set, will be mixed
in as the first base class.
Note: if `module` is not set this routine will attempt to discover the
calling module by walking the frame stack; if this is unsuccessful
...
...
@@ -465,14 +468,11 @@ class Enum(metaclass=EnumMeta):
val
=
self
.
value
return
cls
.
__format__
(
val
,
format_spec
)
def
__getnewargs__
(
self
):
return
(
self
.
_value_
,
)
def
__hash__
(
self
):
return
hash
(
self
.
_name_
)
def
__reduce_ex__
(
self
,
proto
):
return
self
.
__class__
,
self
.
__getnewargs__
(
)
return
self
.
__class__
,
(
self
.
_value_
,
)
# DynamicClassAttribute is used to provide access to the `name` and
# `value` properties of enum members while keeping some measure of
...
...
Lib/test/test_enum.py
View file @
9a0cbcc4
...
...
@@ -956,6 +956,7 @@ class TestEnum(unittest.TestCase):
test_pickle_dump_load
(
self
.
assertEqual
,
NI5
,
5
)
self
.
assertEqual
(
NEI
.
y
.
value
,
2
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
.
y
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
)
def
test_subclasses_with_getnewargs_ex
(
self
):
class
NamedInt
(
int
):
...
...
@@ -1012,6 +1013,7 @@ class TestEnum(unittest.TestCase):
test_pickle_dump_load
(
self
.
assertEqual
,
NI5
,
5
,
protocol
=
(
4
,
4
))
self
.
assertEqual
(
NEI
.
y
.
value
,
2
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
.
y
,
protocol
=
(
4
,
4
))
test_pickle_dump_load
(
self
.
assertIs
,
NEI
)
def
test_subclasses_with_reduce
(
self
):
class
NamedInt
(
int
):
...
...
@@ -1068,6 +1070,7 @@ class TestEnum(unittest.TestCase):
test_pickle_dump_load
(
self
.
assertEqual
,
NI5
,
5
)
self
.
assertEqual
(
NEI
.
y
.
value
,
2
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
.
y
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
)
def
test_subclasses_with_reduce_ex
(
self
):
class
NamedInt
(
int
):
...
...
@@ -1124,8 +1127,9 @@ class TestEnum(unittest.TestCase):
test_pickle_dump_load
(
self
.
assertEqual
,
NI5
,
5
)
self
.
assertEqual
(
NEI
.
y
.
value
,
2
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
.
y
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
)
def
test_subclasses_without_
getnewargs
(
self
):
def
test_subclasses_without_
direct_pickle_support
(
self
):
class
NamedInt
(
int
):
__qualname__
=
'NamedInt'
def
__new__
(
cls
,
*
args
):
...
...
@@ -1178,6 +1182,61 @@ class TestEnum(unittest.TestCase):
test_pickle_exception
(
self
.
assertRaises
,
TypeError
,
NEI
.
x
)
test_pickle_exception
(
self
.
assertRaises
,
PicklingError
,
NEI
)
def
test_subclasses_without_direct_pickle_support_using_name
(
self
):
class
NamedInt
(
int
):
__qualname__
=
'NamedInt'
def
__new__
(
cls
,
*
args
):
_args
=
args
name
,
*
args
=
args
if
len
(
args
)
==
0
:
raise
TypeError
(
"name and value must be specified"
)
self
=
int
.
__new__
(
cls
,
*
args
)
self
.
_intname
=
name
self
.
_args
=
_args
return
self
@
property
def
__name__
(
self
):
return
self
.
_intname
def
__repr__
(
self
):
# repr() is updated to include the name and type info
return
"{}({!r}, {})"
.
format
(
type
(
self
).
__name__
,
self
.
__name__
,
int
.
__repr__
(
self
))
def
__str__
(
self
):
# str() is unchanged, even if it relies on the repr() fallback
base
=
int
base_str
=
base
.
__str__
if
base_str
.
__objclass__
is
object
:
return
base
.
__repr__
(
self
)
return
base_str
(
self
)
# for simplicity, we only define one operator that
# propagates expressions
def
__add__
(
self
,
other
):
temp
=
int
(
self
)
+
int
(
other
)
if
isinstance
(
self
,
NamedInt
)
and
isinstance
(
other
,
NamedInt
):
return
NamedInt
(
'({0} + {1})'
.
format
(
self
.
__name__
,
other
.
__name__
),
temp
)
else
:
return
temp
class
NEI
(
NamedInt
,
Enum
):
__qualname__
=
'NEI'
x
=
(
'the-x'
,
1
)
y
=
(
'the-y'
,
2
)
def
__reduce_ex__
(
self
,
proto
):
return
getattr
,
(
self
.
__class__
,
self
.
_name_
)
self
.
assertIs
(
NEI
.
__new__
,
Enum
.
__new__
)
self
.
assertEqual
(
repr
(
NEI
.
x
+
NEI
.
y
),
"NamedInt('(the-x + the-y)', 3)"
)
globals
()[
'NamedInt'
]
=
NamedInt
globals
()[
'NEI'
]
=
NEI
NI5
=
NamedInt
(
'test'
,
5
)
self
.
assertEqual
(
NI5
,
5
)
self
.
assertEqual
(
NEI
.
y
.
value
,
2
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
.
y
)
test_pickle_dump_load
(
self
.
assertIs
,
NEI
)
def
test_tuple_subclass
(
self
):
class
SomeTuple
(
tuple
,
Enum
):
__qualname__
=
'SomeTuple'
# needed for pickle protocol 4
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment