mirror of https://github.com/python/cpython
bpo-37479: on Enum subclasses with mixins, __format__ uses overridden __str__ (GH-14545)
* bpo-37479: on Enum subclasses with mixins, __format__ uses overridden __str__
This commit is contained in:
parent
b4e68960b9
commit
2f19e82fbe
|
@ -739,9 +739,11 @@ Some rules:
|
||||||
:meth:`__str__` and :meth:`__repr__` respectively; other codes (such as
|
:meth:`__str__` and :meth:`__repr__` respectively; other codes (such as
|
||||||
`%i` or `%h` for IntEnum) treat the enum member as its mixed-in type.
|
`%i` or `%h` for IntEnum) treat the enum member as its mixed-in type.
|
||||||
5. :ref:`Formatted string literals <f-strings>`, :meth:`str.format`,
|
5. :ref:`Formatted string literals <f-strings>`, :meth:`str.format`,
|
||||||
and :func:`format` will use the mixed-in
|
and :func:`format` will use the mixed-in type's :meth:`__format__`
|
||||||
type's :meth:`__format__`. If the :class:`Enum` class's :func:`str` or
|
unless :meth:`__str__` or :meth:`__format__` is overridden in the subclass,
|
||||||
:func:`repr` is desired, use the `!s` or `!r` format codes.
|
in which case the overridden methods or :class:`Enum` methods will be used.
|
||||||
|
Use the !s and !r format codes to force usage of the :class:`Enum` class's
|
||||||
|
:meth:`__str__` and :meth:`__repr__` methods.
|
||||||
|
|
||||||
When to use :meth:`__new__` vs. :meth:`__init__`
|
When to use :meth:`__new__` vs. :meth:`__init__`
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
|
@ -622,8 +622,9 @@ class Enum(metaclass=EnumMeta):
|
||||||
# we can get strange results with the Enum name showing up instead of
|
# we can get strange results with the Enum name showing up instead of
|
||||||
# the value
|
# the value
|
||||||
|
|
||||||
# pure Enum branch
|
# pure Enum branch, or branch with __str__ explicitly overridden
|
||||||
if self._member_type_ is object:
|
str_overridden = type(self).__str__ != Enum.__str__
|
||||||
|
if self._member_type_ is object or str_overridden:
|
||||||
cls = str
|
cls = str
|
||||||
val = str(self)
|
val = str(self)
|
||||||
# mix-in branch
|
# mix-in branch
|
||||||
|
|
|
@ -445,12 +445,63 @@ class TestEnum(unittest.TestCase):
|
||||||
self.assertEqual('{:<20}'.format(Season.SPRING),
|
self.assertEqual('{:<20}'.format(Season.SPRING),
|
||||||
'{:<20}'.format(str(Season.SPRING)))
|
'{:<20}'.format(str(Season.SPRING)))
|
||||||
|
|
||||||
def test_format_enum_custom(self):
|
def test_str_override_enum(self):
|
||||||
|
class EnumWithStrOverrides(Enum):
|
||||||
|
one = auto()
|
||||||
|
two = auto()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Str!'
|
||||||
|
self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
|
||||||
|
self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
|
||||||
|
|
||||||
|
def test_format_override_enum(self):
|
||||||
|
class EnumWithFormatOverride(Enum):
|
||||||
|
one = 1.0
|
||||||
|
two = 2.0
|
||||||
|
def __format__(self, spec):
|
||||||
|
return 'Format!!'
|
||||||
|
self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
|
||||||
|
self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
|
||||||
|
|
||||||
|
def test_str_and_format_override_enum(self):
|
||||||
|
class EnumWithStrFormatOverrides(Enum):
|
||||||
|
one = auto()
|
||||||
|
two = auto()
|
||||||
|
def __str__(self):
|
||||||
|
return 'Str!'
|
||||||
|
def __format__(self, spec):
|
||||||
|
return 'Format!'
|
||||||
|
self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
|
||||||
|
self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
|
||||||
|
|
||||||
|
def test_str_override_mixin(self):
|
||||||
|
class MixinEnumWithStrOverride(float, Enum):
|
||||||
|
one = 1.0
|
||||||
|
two = 2.0
|
||||||
|
def __str__(self):
|
||||||
|
return 'Overridden!'
|
||||||
|
self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
|
||||||
|
self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
|
||||||
|
|
||||||
|
def test_str_and_format_override_mixin(self):
|
||||||
|
class MixinWithStrFormatOverrides(float, Enum):
|
||||||
|
one = 1.0
|
||||||
|
two = 2.0
|
||||||
|
def __str__(self):
|
||||||
|
return 'Str!'
|
||||||
|
def __format__(self, spec):
|
||||||
|
return 'Format!'
|
||||||
|
self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
|
||||||
|
self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
|
||||||
|
|
||||||
|
def test_format_override_mixin(self):
|
||||||
class TestFloat(float, Enum):
|
class TestFloat(float, Enum):
|
||||||
one = 1.0
|
one = 1.0
|
||||||
two = 2.0
|
two = 2.0
|
||||||
def __format__(self, spec):
|
def __format__(self, spec):
|
||||||
return 'TestFloat success!'
|
return 'TestFloat success!'
|
||||||
|
self.assertEqual(str(TestFloat.one), 'TestFloat.one')
|
||||||
self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
|
self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
|
||||||
|
|
||||||
def assertFormatIsValue(self, spec, member):
|
def assertFormatIsValue(self, spec, member):
|
||||||
|
|
|
@ -356,6 +356,7 @@ Tom Culliton
|
||||||
Raúl Cumplido
|
Raúl Cumplido
|
||||||
Antonio Cuni
|
Antonio Cuni
|
||||||
Brian Curtin
|
Brian Curtin
|
||||||
|
Jason Curtis
|
||||||
Paul Dagnelie
|
Paul Dagnelie
|
||||||
Lisandro Dalcin
|
Lisandro Dalcin
|
||||||
Darren Dale
|
Darren Dale
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
When `Enum.__str__` is overridden in a derived class, the override will be
|
||||||
|
used by `Enum.__format__` regardless of whether mixin classes are present.
|
Loading…
Reference in New Issue