Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StrEnum.__getitem__ raises TypeError #128659

Open
injust opened this issue Jan 9, 2025 · 1 comment
Open

StrEnum.__getitem__ raises TypeError #128659

injust opened this issue Jan 9, 2025 · 1 comment
Assignees
Labels
type-bug An unexpected behavior, bug, or error

Comments

@injust
Copy link

injust commented Jan 9, 2025

Bug report

Bug description:

from enum import Enum, StrEnum, auto

class Foo(Enum):
    one = auto()
    two = auto()
    
class Bar(StrEnum):
    one = auto()
    two = auto()
    
names = ["one", "two"]

print([Foo[name] for name in names])
print(list(map(Foo.__getitem__, names)))

print([Bar[name] for name in names])
print(list(map(Bar.__getitem__, names)))  # TypeError: expected 1 argument, got 0

CPython versions tested on:

3.12, 3.13

Operating systems tested on:

macOS

@injust injust added the type-bug An unexpected behavior, bug, or error label Jan 9, 2025
@ethanfurman ethanfurman self-assigned this Jan 9, 2025
@tom-pytel
Copy link

tom-pytel commented Jan 9, 2025

str class slots are overriding EnumType mapping for __getitem__ and others in StrEnum for certain uses.

>>> Foo.__getitem__
<bound method EnumType.__getitem__ of <enum 'Foo'>>

>>> Bar.__getitem__
<slot wrapper '__getitem__' of 'str' objects>

They work implicitly but not explicitly:

>>> Bar['one']
<Bar.one: 'one'>

>>> Bar.__getitem__('one')
Traceback (most recent call last):
  File "<python-input-19>", line 1, in <module>
    Bar.__getitem__('one')
    ~~~~~~~~~~~~~~~^^^^^^^
TypeError: expected 1 argument, got 0

>>> Bar.__getitem__(Bar, 'one')
Traceback (most recent call last):
  File "<python-input-20>", line 1, in <module>
    Bar.__getitem__(Bar, 'one')
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^
TypeError: descriptor '__getitem__' requires a 'str' object but received a 'EnumType'

Because Bar['one'] calls EnumType.__getitem__() and Bar.__getitem__('one') calls str.__getitem__(). This also applies to other magics like __contains__ or __len__:

>>> Bar.__contains__
<slot wrapper '__contains__' of 'str' objects>

>>> Bar.__len__
<slot wrapper '__len__' of 'str' objects>

>>> len(Bar)
2

>>> Bar.__len__()
Traceback (most recent call last):
  File "<python-input-22>", line 1, in <module>
    Bar.__len__()
    ~~~~~~~~~~~^^
TypeError: descriptor '__len__' of 'str' object needs an argument

>>> Bar.__len__(Bar)
Traceback (most recent call last):
  File "<python-input-23>", line 1, in <module>
    Bar.__len__(Bar)
    ~~~~~~~~~~~^^^^^
TypeError: descriptor '__len__' requires a 'str' object but received a 'EnumType'

>>> Bar.__len__('abc')
3

Quick hack fix, add the following to StrEnum to re-override methods overridden by str (if this is the desired behavior):

    # re-override methods overridden by str, see gh-128659
    __contains__ = classmethod(EnumType.__contains__)
    __getitem__ = classmethod(EnumType.__getitem__)
    __iter__ = classmethod(EnumType.__iter__)
    __len__ = classmethod(EnumType.__len__)

Before:

>>> Foo.__getitem__
<bound method EnumType.__getitem__ of <enum 'Foo'>>
>>> Bar.__getitem__
<slot wrapper '__getitem__' of 'str' objects>

After:

>>> Foo.__getitem__
<bound method EnumType.__getitem__ of <enum 'Foo'>>
>>> Bar.__getitem__
<bound method EnumType.__getitem__ of <enum 'Bar'>>
>>> Bar.__getitem__('one')
<Bar.one: 'one'>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants