8000 [3.7] bpo-37479: on Enum subclasses with mixins, __format__ uses over… · ethanfurman/cpython@03c803b · GitHub
[go: up one dir, main page]

Skip to content

Commit 03c803b

Browse files
thatneatethanfurman
authored andcommitted
[3.7] bpo-37479: on Enum subclasses with mixins, __format__ uses overridden __str__ (pythonGH-14545)
* bpo-37479: on Enum subclasses with mixins, __format__ uses overridden __str__. (cherry picked from commit 2f19e82) Co-authored-by: thatneat <thatneat@users.noreply.github.com>
1 parent 4e02981 commit 03c803b

File tree

5 files changed

+64
-6
lines changed
  • Doc/library
  • Lib
  • Misc
    • NEWS.d/next/Library
      • 2019-07-02-12-43-57.bpo-37479.O53a5S.rst

5 files changed

+64
-6
lines changed

Doc/library/enum.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -743,9 +743,11 @@ Some rules:
743743
:meth:`__str__` and :meth:`__repr__` respectively; other codes (such as
744744
`%i` or `%h` for IntEnum) treat the enum member as its mixed-in type.
745745
5. :ref:`Formatted string literals <f-strings>`, :meth:`str.format`,
746-
and :func:`format` will use the mixed-in
747-
type's :meth:`__format__`. If the :class:`Enum` class's :func:`str` or
748-
:func:`repr` is desired, use the `!s` or `!r` format codes.
746+
and :func:`format` will use the mixed-in type's :meth:`__format__`
747+
unless :meth:`__str__` or :meth:`__format__` is overridden in the subclass,
748+
in which case the overridden methods or :class:`Enum` methods will be used.
749+
Use the !s and !r format codes to force usage of the :class:`Enum` class's
750+
:meth:`__str__` and :meth:`__repr__` methods.
749751

750752

751753
Interesting examples

Lib/enum.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,9 @@ def __format__(self, format_spec):
602602
# we can get strange results with the Enum name showing up instead of
603603
# the value
604604

605-
# pure Enum branch
606-
if self._member_type_ is object:
605+
# pure Enum branch, or branch with __str__ explicitly overridden
606+
str_overridden = type(self).__str__ != Enum.__str__
607+
if self._member_type_ is object or str_overridden:
607608
cls = str
608609
val = str(self)
609610
# mix-in branch

Lib/test/test_enum.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,12 +453,63 @@ def test_format_enum(self):
453453
self.assertEqual('{:<20}'.format(Season.SPRING),
454454
'{:<20}'.format(str(Season.SPRING)))
455455

456-
def test_format_enum_custom(self):
456+
def test_str_override_enum(self):
457+
class EnumWithStrOverrides(Enum):
458+
one = auto()
459+
two = auto()
460+
461+
def __str__(self):
462+
return 'Str!'
463+
self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
464+
self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
465+
466+
def test_format_override_enum(self):
467+
class EnumWithFormatOverride(Enum):
468+
one = 1.0
469+
two = 2.0
470+
def __format__(self, spec):
471+
return 'Format!!'
472+
self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
473+
self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
474+
475+
def test_str_and_format_override_enum(self):
476+
class EnumWithStrFormatOverrides(Enum):
477+
one = auto()
478+
two = auto()
479+
def __str__(self):
480+
return 'Str!'
481+
def __format__(self, spec):
482+
return 'Format!'
483+
self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
484+
self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
485+
486+
def test_str_override_mixin(self):
487+
class MixinEnumWithStrOverride(float, Enum):
488+
one = 1.0
489+
two = 2.0
490+
def __str__(self):
491+
return 'Overridden!'
492+
self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
493+
self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
494+
495+
def test_str_and_format_override_mixin(self):
496+
class MixinWithStrFormatOverrides(float, Enum):
497+
one = 1.0
498+
two = 2.0
499+
def __str__(self):
500+
return 'Str!'
501+
def __format__(self, spec):
502+
return 'Format!'
503+
self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
504+
self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
505+
506+
def test_format_override_mixin(self):
457507
class TestFloat(float, Enum):
458508
one = 1.0
459509
two = 2.0
460510
def __format__(self, spec):
461511
return 'TestFloat success!'
512+
self.assertEqual(str(TestFloat.one), 'TestFloat.one')
462513
self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
463514

464515
def assertFormatIsValue(self, spec, member):

Misc/ACKS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ Tom Culliton
356356
Raúl Cumplido
357357
Antonio Cuni
358358
Brian Curtin
359+
Jason Curtis
360+
Paul Dagnelie
359361
Lisandro Dalcin
360362
Darren Dale
361363
Andrew Dalke
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
When `Enum.__str__` is overridden in a derived class, the override will be
2+
used by `Enum.__format__` regardless of whether mixin classes are present.

0 commit comments

Comments
 (0)
0