Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
5bdab641
Unverified
Kaydet (Commit)
5bdab641
authored
Eyl 22, 2018
tarafından
Ethan Furman
Kaydeden (comit)
GitHub
Eyl 22, 2018
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
bpo-29577: Enum: mixin classes don't mix well with already mixed Enums (GH-9328)
* bpo-29577: allow multiple mixin classes
üst
fd97d1f1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
229 additions
and
34 deletions
+229
-34
enum.rst
Doc/library/enum.rst
+10
-3
enum.py
Lib/enum.py
+19
-31
test_enum.py
Lib/test/test_enum.py
+199
-0
2018-09-14-20-00-47.bpo-29577.RzwKFD.rst
...S.d/next/Library/2018-09-14-20-00-47.bpo-29577.RzwKFD.rst
+1
-0
No files found.
Doc/library/enum.rst
Dosyayı görüntüle @
5bdab641
...
@@ -387,10 +387,17 @@ whatever value(s) were given to the enum member will be passed into those
...
@@ -387,10 +387,17 @@ whatever value(s) were given to the enum member will be passed into those
methods. See `Planet`_ for an example.
methods. See `Planet`_ for an example.
Restricted
subclassing of enumerations
Restricted
Enum subclassing
---------------------------
-----------
---------------------------
Subclassing an enumeration is allowed only if the enumeration does not define
A new :class:`Enum` class must have one base Enum class, up to one concrete
data type, and as many :class:`object`-based mixin classes as needed. The
order of these base classes is::
def EnumName([mix-in, ...,] [data-type,] base-enum):
pass
Also, subclassing an enumeration is allowed only if the enumeration does not define
any members. So this is forbidden::
any members. So this is forbidden::
>>> class MoreColor(Color):
>>> class MoreColor(Color):
...
...
Lib/enum.py
Dosyayı görüntüle @
5bdab641
...
@@ -480,37 +480,25 @@ class EnumMeta(type):
...
@@ -480,37 +480,25 @@ class EnumMeta(type):
if
not
bases
:
if
not
bases
:
return
object
,
Enum
return
object
,
Enum
# double check that we are not subclassing a class with existing
def
_find_data_type
(
bases
):
# enumeration members; while we're at it, see if any other data
for
chain
in
bases
:
# type has been mixed in so we can use the correct __new__
for
base
in
chain
.
__mro__
:
member_type
=
first_enum
=
None
if
base
is
object
:
for
base
in
bases
:
continue
if
(
base
is
not
Enum
and
elif
'__new__'
in
base
.
__dict__
:
issubclass
(
base
,
Enum
)
and
if
issubclass
(
base
,
Enum
)
and
not
hasattr
(
base
,
'__new_member__'
):
base
.
_member_names_
):
continue
raise
TypeError
(
"Cannot extend enumerations"
)
return
base
# base is now the last base in bases
if
not
issubclass
(
base
,
Enum
):
# ensure final parent class is an Enum derivative, find any concrete
raise
TypeError
(
"new enumerations must be created as "
# data type, and check that Enum has no members
"`ClassName([mixin_type,] enum_type)`"
)
first_enum
=
bases
[
-
1
]
if
not
issubclass
(
first_enum
,
Enum
):
# get correct mix-in type (either mix-in type of Enum subclass, or
raise
TypeError
(
"new enumerations should be created as "
# first base if last base is Enum)
"`EnumName([mixin_type, ...] [data_type,] enum_type)`"
)
if
not
issubclass
(
bases
[
0
],
Enum
):
member_type
=
_find_data_type
(
bases
)
or
object
member_type
=
bases
[
0
]
# first data type
if
first_enum
.
_member_names_
:
first_enum
=
bases
[
-
1
]
# enum type
raise
TypeError
(
"Cannot extend enumerations"
)
else
:
for
base
in
bases
[
0
]
.
__mro__
:
# most common: (IntEnum, int, Enum, object)
# possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
# <class 'int'>, <Enum 'Enum'>,
# <class 'object'>)
if
issubclass
(
base
,
Enum
):
if
first_enum
is
None
:
first_enum
=
base
else
:
if
member_type
is
None
:
member_type
=
base
return
member_type
,
first_enum
return
member_type
,
first_enum
...
...
Lib/test/test_enum.py
Dosyayı görüntüle @
5bdab641
...
@@ -122,6 +122,22 @@ class TestHelpers(unittest.TestCase):
...
@@ -122,6 +122,22 @@ class TestHelpers(unittest.TestCase):
'__'
,
'___'
,
'____'
,
'_____'
,):
'__'
,
'___'
,
'____'
,
'_____'
,):
self
.
assertFalse
(
enum
.
_is_dunder
(
s
))
self
.
assertFalse
(
enum
.
_is_dunder
(
s
))
# for subclassing tests
class
classproperty
:
def
__init__
(
self
,
fget
=
None
,
fset
=
None
,
fdel
=
None
,
doc
=
None
):
self
.
fget
=
fget
self
.
fset
=
fset
self
.
fdel
=
fdel
if
doc
is
None
and
fget
is
not
None
:
doc
=
fget
.
__doc__
self
.
__doc__
=
doc
def
__get__
(
self
,
instance
,
ownerclass
):
return
self
.
fget
(
ownerclass
)
# tests
# tests
class
TestEnum
(
unittest
.
TestCase
):
class
TestEnum
(
unittest
.
TestCase
):
...
@@ -1730,6 +1746,102 @@ class TestEnum(unittest.TestCase):
...
@@ -1730,6 +1746,102 @@ class TestEnum(unittest.TestCase):
else
:
else
:
raise
Exception
(
'Exception not raised.'
)
raise
Exception
(
'Exception not raised.'
)
def
test_multiple_mixin
(
self
):
class
MaxMixin
:
@classproperty
def
MAX
(
cls
):
max
=
len
(
cls
)
cls
.
MAX
=
max
return
max
class
StrMixin
:
def
__str__
(
self
):
return
self
.
_name_
.
lower
()
class
SomeEnum
(
Enum
):
def
behavior
(
self
):
return
'booyah'
class
AnotherEnum
(
Enum
):
def
behavior
(
self
):
return
'nuhuh!'
def
social
(
self
):
return
"what's up?"
class
Color
(
MaxMixin
,
Enum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
Color
.
MAX
,
3
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'Color.BLUE'
)
class
Color
(
MaxMixin
,
StrMixin
,
Enum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
Color
.
MAX
,
3
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'blue'
)
class
Color
(
StrMixin
,
MaxMixin
,
Enum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
Color
.
MAX
,
3
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'blue'
)
class
CoolColor
(
StrMixin
,
SomeEnum
,
Enum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
CoolColor
.
RED
.
value
,
1
)
self
.
assertEqual
(
CoolColor
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
CoolColor
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
str
(
CoolColor
.
BLUE
),
'blue'
)
self
.
assertEqual
(
CoolColor
.
RED
.
behavior
(),
'booyah'
)
class
CoolerColor
(
StrMixin
,
AnotherEnum
,
Enum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
CoolerColor
.
RED
.
value
,
1
)
self
.
assertEqual
(
CoolerColor
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
CoolerColor
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
str
(
CoolerColor
.
BLUE
),
'blue'
)
self
.
assertEqual
(
CoolerColor
.
RED
.
behavior
(),
'nuhuh!'
)
self
.
assertEqual
(
CoolerColor
.
RED
.
social
(),
"what's up?"
)
class
CoolestColor
(
StrMixin
,
SomeEnum
,
AnotherEnum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
CoolestColor
.
RED
.
value
,
1
)
self
.
assertEqual
(
CoolestColor
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
CoolestColor
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
str
(
CoolestColor
.
BLUE
),
'blue'
)
self
.
assertEqual
(
CoolestColor
.
RED
.
behavior
(),
'booyah'
)
self
.
assertEqual
(
CoolestColor
.
RED
.
social
(),
"what's up?"
)
class
ConfusedColor
(
StrMixin
,
AnotherEnum
,
SomeEnum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
ConfusedColor
.
RED
.
value
,
1
)
self
.
assertEqual
(
ConfusedColor
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
ConfusedColor
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
str
(
ConfusedColor
.
BLUE
),
'blue'
)
self
.
assertEqual
(
ConfusedColor
.
RED
.
behavior
(),
'nuhuh!'
)
self
.
assertEqual
(
ConfusedColor
.
RED
.
social
(),
"what's up?"
)
class
ReformedColor
(
StrMixin
,
IntEnum
,
SomeEnum
,
AnotherEnum
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
ReformedColor
.
RED
.
value
,
1
)
self
.
assertEqual
(
ReformedColor
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
ReformedColor
.
BLUE
.
value
,
3
)
self
.
assertEqual
(
str
(
ReformedColor
.
BLUE
),
'blue'
)
self
.
assertEqual
(
ReformedColor
.
RED
.
behavior
(),
'booyah'
)
self
.
assertEqual
(
ConfusedColor
.
RED
.
social
(),
"what's up?"
)
self
.
assertTrue
(
issubclass
(
ReformedColor
,
int
))
class
TestOrder
(
unittest
.
TestCase
):
class
TestOrder
(
unittest
.
TestCase
):
...
@@ -2093,6 +2205,49 @@ class TestFlag(unittest.TestCase):
...
@@ -2093,6 +2205,49 @@ class TestFlag(unittest.TestCase):
d
=
6
d
=
6
self
.
assertEqual
(
repr
(
Bizarre
(
7
)),
'<Bizarre.d|c|b: 7>'
)
self
.
assertEqual
(
repr
(
Bizarre
(
7
)),
'<Bizarre.d|c|b: 7>'
)
def
test_multiple_mixin
(
self
):
class
AllMixin
:
@classproperty
def
ALL
(
cls
):
members
=
list
(
cls
)
all_value
=
None
if
members
:
all_value
=
members
[
0
]
for
member
in
members
[
1
:]:
all_value
|=
member
cls
.
ALL
=
all_value
return
all_value
class
StrMixin
:
def
__str__
(
self
):
return
self
.
_name_
.
lower
()
class
Color
(
AllMixin
,
Flag
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
4
)
self
.
assertEqual
(
Color
.
ALL
.
value
,
7
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'Color.BLUE'
)
class
Color
(
AllMixin
,
StrMixin
,
Flag
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
4
)
self
.
assertEqual
(
Color
.
ALL
.
value
,
7
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'blue'
)
class
Color
(
StrMixin
,
AllMixin
,
Flag
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
4
)
self
.
assertEqual
(
Color
.
ALL
.
value
,
7
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'blue'
)
@support.reap_threads
@support.reap_threads
def
test_unique_composite
(
self
):
def
test_unique_composite
(
self
):
# override __eq__ to be identity only
# override __eq__ to be identity only
...
@@ -2468,6 +2623,49 @@ class TestIntFlag(unittest.TestCase):
...
@@ -2468,6 +2623,49 @@ class TestIntFlag(unittest.TestCase):
for
f
in
Open
:
for
f
in
Open
:
self
.
assertEqual
(
bool
(
f
.
value
),
bool
(
f
))
self
.
assertEqual
(
bool
(
f
.
value
),
bool
(
f
))
def
test_multiple_mixin
(
self
):
class
AllMixin
:
@classproperty
def
ALL
(
cls
):
members
=
list
(
cls
)
all_value
=
None
if
members
:
all_value
=
members
[
0
]
for
member
in
members
[
1
:]:
all_value
|=
member
cls
.
ALL
=
all_value
return
all_value
class
StrMixin
:
def
__str__
(
self
):
return
self
.
_name_
.
lower
()
class
Color
(
AllMixin
,
IntFlag
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
4
)
self
.
assertEqual
(
Color
.
ALL
.
value
,
7
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'Color.BLUE'
)
class
Color
(
AllMixin
,
StrMixin
,
IntFlag
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
4
)
self
.
assertEqual
(
Color
.
ALL
.
value
,
7
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'blue'
)
class
Color
(
StrMixin
,
AllMixin
,
IntFlag
):
RED
=
auto
()
GREEN
=
auto
()
BLUE
=
auto
()
self
.
assertEqual
(
Color
.
RED
.
value
,
1
)
self
.
assertEqual
(
Color
.
GREEN
.
value
,
2
)
self
.
assertEqual
(
Color
.
BLUE
.
value
,
4
)
self
.
assertEqual
(
Color
.
ALL
.
value
,
7
)
self
.
assertEqual
(
str
(
Color
.
BLUE
),
'blue'
)
@support.reap_threads
@support.reap_threads
def
test_unique_composite
(
self
):
def
test_unique_composite
(
self
):
# override __eq__ to be identity only
# override __eq__ to be identity only
...
@@ -2553,6 +2751,7 @@ class TestUnique(unittest.TestCase):
...
@@ -2553,6 +2751,7 @@ class TestUnique(unittest.TestCase):
value
=
4
value
=
4
expected_help_output_with_docs
=
"""
\
expected_help_output_with_docs
=
"""
\
Help on class Color in module
%
s:
Help on class Color in module
%
s:
...
...
Misc/NEWS.d/next/Library/2018-09-14-20-00-47.bpo-29577.RzwKFD.rst
0 → 100644
Dosyayı görüntüle @
5bdab641
Support multiple mixin classes when creating Enums.
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