diff options
author | thatneat <thatneat@users.noreply.github.com> | 2019-07-04 18:28:37 (GMT) |
---|---|---|
committer | Ethan Furman <ethan@stoneleaf.us> | 2019-07-04 18:28:37 (GMT) |
commit | 2f19e82fbe98ce86bcd98a176328af2808b678e8 (patch) | |
tree | 0febe00f3456e58aa82575a2c16a62f3e2385c6a | |
parent | b4e68960b90627422325fdb75f463df1e4153c6e (diff) | |
download | cpython-2f19e82fbe98ce86bcd98a176328af2808b678e8.zip cpython-2f19e82fbe98ce86bcd98a176328af2808b678e8.tar.gz cpython-2f19e82fbe98ce86bcd98a176328af2808b678e8.tar.bz2 |
bpo-37479: on Enum subclasses with mixins, __format__ uses overridden __str__ (GH-14545)
* bpo-37479: on Enum subclasses with mixins, __format__ uses overridden __str__
-rw-r--r-- | Doc/library/enum.rst | 8 | ||||
-rw-r--r-- | Lib/enum.py | 5 | ||||
-rw-r--r-- | Lib/test/test_enum.py | 53 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2019-07-02-12-43-57.bpo-37479.O53a5S.rst | 2 |
5 files changed, 63 insertions, 6 deletions
diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 19277d7..d7d319a 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -739,9 +739,11 @@ Some rules: :meth:`__str__` and :meth:`__repr__` respectively; other codes (such as `%i` or `%h` for IntEnum) treat the enum member as its mixed-in type. 5. :ref:`Formatted string literals <f-strings>`, :meth:`str.format`, - and :func:`format` will use the mixed-in - type's :meth:`__format__`. If the :class:`Enum` class's :func:`str` or - :func:`repr` is desired, use the `!s` or `!r` format codes. + and :func:`format` will use the mixed-in type's :meth:`__format__` + unless :meth:`__str__` or :meth:`__format__` is overridden in the subclass, + 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__` ------------------------------------------------ diff --git a/Lib/enum.py b/Lib/enum.py index 403f747..69a7f49 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -622,8 +622,9 @@ class Enum(metaclass=EnumMeta): # we can get strange results with the Enum name showing up instead of # the value - # pure Enum branch - if self._member_type_ is object: + # pure Enum branch, or branch with __str__ explicitly overridden + str_overridden = type(self).__str__ != Enum.__str__ + if self._member_type_ is object or str_overridden: cls = str val = str(self) # mix-in branch diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 47081cf..fcfa7d9 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -445,12 +445,63 @@ class TestEnum(unittest.TestCase): self.assertEqual('{:<20}'.format(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): one = 1.0 two = 2.0 def __format__(self, spec): return 'TestFloat success!' + self.assertEqual(str(TestFloat.one), 'TestFloat.one') self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!') def assertFormatIsValue(self, spec, member): @@ -356,6 +356,7 @@ Tom Culliton Raúl Cumplido Antonio Cuni Brian Curtin +Jason Curtis Paul Dagnelie Lisandro Dalcin Darren Dale diff --git a/Misc/NEWS.d/next/Library/2019-07-02-12-43-57.bpo-37479.O53a5S.rst b/Misc/NEWS.d/next/Library/2019-07-02-12-43-57.bpo-37479.O53a5S.rst new file mode 100644 index 0000000..cf23155 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-07-02-12-43-57.bpo-37479.O53a5S.rst @@ -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.
\ No newline at end of file |