mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	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
					
				
					 5 changed files with 63 additions and 6 deletions
				
			
		| 
						 | 
					@ -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 @@ def __format__(self, format_spec):
 | 
				
			||||||
        # 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 @@ def test_format_enum(self):
 | 
				
			||||||
        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…
	
	Add table
		Add a link
		
	
		Reference in a new issue