New submission from Drekin:

I tried to implement an Enum variant OptionalEnum such that OptionalEnum(value) 
leaves value alone and returnes it (if there is no corresponding enum member) 
rather than raising ValueError. My use case is following: I'm trying to parse 
some keyboard layout related data. There is a table which maps virtual keys to 
unicode codepoints, however there are some special values which don't represent 
a codepoint but the fact that the key is a deadkey and more information is 
provided in the next table entry. Or that the key produces a ligature. So I 
wanted to define enums for those special values.

This brought me to the following naive approach:
class OptionalEnum(Enum):
    def __new__(cls, value):
        try:
            return super(cls, cls).__new__(cls, value)
        except ValueError:
            return value

This ends with a weird exception. As I ran through enum code I found out that 
there are actually two flavors of EnumSubclass.__new__. The first one is for 
precreating the enum members (during creation of EnumSubclass). This is the 
intended usage. The second flavor is what happens when EnumSubclass(value) is 
called later. This flavor is represented by Enum.__new__ which returns existing 
member corresponding to the value or raises ValueError. However this 
Enum.__new__ is rather special. It doesn't take place in the process of the 
first flavor, it is explicitly by-passed. On the other hand it is forced 
behavior of the second flavor since it is explicitly assigned to 
EnumSubclass.__new__. So there seems to be no way to customize the second 
flavor (as I tried in my use case).

So could the customization of the second flavor of __new__ be added? (One maybe 
naive solution would be to let user explicitly define __new_member__ rather 
than __new__ to customize the first flavor and leave __new__ for the second 
flavor.) Or could at least be done something with the exceptions produced when 
one tries to? (The exception in my case was 'TypeError: object() takes no 
parameters' and was result of having custom __new__ and hence use_args==True 
but having member_type==object and __new__ not creating member with _value_ 
attribute so object(*args) was called.)

In any case additional documentation on customizing __new__ could help. There 
are points like that one should avoid the pattern of falling back to 
super().__new__ since that is Enum.__new__ which is for something else. Also 
the custom __new__ should return an object with _value_ attribute or object() 
with some argument may be called which leads to uninformative exception.

----------
assignee: docs@python
components: Documentation, Library (Lib)
messages: 197979
nosy: Drekin, docs@python
priority: normal
severity: normal
status: open
title: Problems with overriding Enum.__new__
type: behavior
versions: Python 3.4

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue19040>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to