8000 Python 3.11 changes behavior how enums are formatted as string · Issue #447 · mobilityhouse/ocpp · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Python 3.11 changes behavior how enums are formatted as string #447
Closed
@OrangeTux

Description

@OrangeTux

@proelke made me aware about a changes to Python 3.11 that introduce subtle changes to all enums that subclass from both str and enum.Enum. Practically all enums defined in this library are subclassed from these 2 classes.

Consider the following code:

import enum

class ResetType(str, enum.Enum):
    hard = "hard"
    soft = "soft"

# Passes in both Python 3.11 and earlier.
assert ResetType.hard == "hard"

# Passes in Python 3.10 and below, but fails in Python 3.11.
assert f'{ResetType.hard}' == "hard"
$  python3.11 /enum_test.py
Traceback (most recent call last):
  File "/tmp/enum_test.py", line 15, in <module>
    assert f'{ResetType.hard}' == "hard"
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

The underlying cause is that Python 3.11 changes the behavior of enum.Enum.__format__() slightly. f-strings (and a few other string formatting methods) rely on dunder method __format___().

So far, I considered two solutions.

Solution 1: StrEnum

Python 3.11 introduces enum.StrEnum. One could implement a solution as described at https://tomwojcik.com/posts/2023-01-02/python-311-str-enum-breaking-change

try:
    # breaking change introduced in python 3.11
    from enum import StrEnum
except ImportError:  # pragma: no cover
    from enum import Enum  # pragma: no cover

    class StrEnum(str, Enum):  # pragma: no cover
        pass  # pragma: no cover

class ResetType(StrEnum):
    hard = "hard"
    soft = "soft"

# Passes in both Python 3.11 and earlier.
assert ResetType.hard == "hard"

# Passes now in Python 3.10 and below and Python 3.11!
assert f'{ResetType.hard}' == "hard"

Manually implement __format__()

The other solution is to implement __format__() manually.

import enum

class _Enum(str, enum.Enum):
    def __format__(self, spec) -> str:
        return str.__format__(str(self.name), spec)

class ResetType(_Enum):
    hard = "hard"
    soft = "soft"

# Passes in both Python 3.11 and earlier.
assert ResetType.hard == "hard"

# Passes now in Python 3.10 and below and Python 3.11!
assert f"{ResetType.hard}" == "hard"

See also

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0