[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-16 Thread Ethan Furman

Ethan Furman added the comment:

http://hg.python.org/cpython/rev/4135f3929b35
http://hg.python.org/cpython/rev/cdd412347827

--
resolution:  -> fixed
stage: patch review -> resolved
status: open -> closed

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-08 Thread Kiss György

Kiss György added the comment:

Thanks for the tip! That looks much better.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-06 Thread Ethan Furman

Ethan Furman added the comment:

You could do the same kind of check in __new__, but consider this:

class StrValues(MultiValueEnum):
one = ('One'
  'one',
   '1')
two = ('two',
  'Two',
   '2')

In this scenario the 'Oneone' mistake would still not be automatically caught.  
There are the two ways I deal with this type of problem:

  - unit tests
  - formatting

The formatting looks like this:

class StrValues(MultiValueEnum):
one = (
'One'
'one',
'1',
)
two = (
'two',
'Two',
'2',
)

This style of format does several things for us:

  - easier to read the code:
 - each value is on it's own line
 - each value is lined up
 - there is white space between the values of one attribute and
   the values of the next attribute

  - easier to read diffs, as we don't see extraneous stuff like

-  '2'
+  '2',

  - easier to spot mistakes, since we get used to seeing that trailing
comma and it's absence will stand out.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-06 Thread Kiss György

Kiss György added the comment:

I found one thing which you can't do subclassing Enum what you can with 
metaclasses:
enforcing type checking at class creation time. Values are passed to __new__ as 
positional arguments, so it's impossible to tell the difference between these 
two:

class SingleValue(MultiVAlueEnum):
one = 1, 'one'
two = 2


class Tuple(MultiVAlueEnum):
one = 1, 'one'
two = 2,

because in both cases (2,) would be passed. It's not a big deal, but "Explicit 
is better than implicit." and also I would like to avoid typos, which I often 
make like this:

class StrValues(MultiValueEnum):
one = ('One'
  'one')
two = ('two',
  'Two')

In this case, the first member would be accepted as 'Oneone' instead of ('One', 
'one') and I see no way to check that without metaclasses. Do you?

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-05 Thread Kiss György

Kiss György added the comment:

Oh, wow. I never really understood what _find_new_ did, now I do.

> I'm not sure what you are trying to accomplish there.
Exactly that, I'm just not as good. Oh well at least I found a bug! :) Thanks 
for the enlightenment!

If the patch goes in, I also would like one more minor change. On line 457, the 
missing value is represented as simple str(). In case of user defined types, it 
would make debugging easier if repr() would be used instead. I attached the 
patch.

--
Added file: http://bugs.python.org/file36554/enum.patch2

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-05 Thread Ethan Furman

Ethan Furman added the comment:

Right.  We can still use the alias machinery to accomplish this task for us, 
and avoid the metaclass hacking:

-- python2 sample code 
# -*- coding: utf-8 -*-
from enum import Enum

class MultiValueEnum(Enum):
def __new__(cls, *values):
obj = object.__new__(cls)
obj._value_ = values[0]
obj._all_values = values
for alias in values[1:]:
cls._value2member_map_[alias] = obj
return obj
def __repr__(self):
return "<%s.%s: %s>" % (
 self.__class__.__name__,
 self._name_,
 ', '.join(["'%s'" % v for v in self._all_values])
 )

class Suits(MultiValueEnum):
CLUBS ='♣', 'c', 'C', 'clubs', 'club'
DIAMONDS = '♦', 'd', 'D', 'diamonds', 'diamond'
HEARTS =   '♥', 'h', 'H', 'hearts', 'heart'
SPADES =   '♠', 's', 'S', 'spades', 'spade'

print(Suits.HEARTS)
print(repr(Suits.HEARTS))
print(Suits('d'))
print(Suits('club'))
print(Suits('S'))
print(Suits('hearts'))



And the output:

Suits.HEARTS

Suits.DIAMONDS
Suits.CLUBS
Suits.SPADES
Suits.HEARTS



I'm still going to fix the bug, though.  :)

Oh, the above does not fix the IncorrectAliasBehavior class, but honestly I'm 
not sure what you are trying to accomplish there.

--
stage:  -> patch review
type: enhancement -> behavior

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-05 Thread Kiss György

Kiss György added the comment:

> Is this a way to easily handle multiple aliases?

You mean this MultiValueEnum implementation? (If not I don't understand the 
question, could you elaborate?)

No, this is the opposite of aliases, because an alias is when the same value 
have multiple names, but this is when the values are used to lookup the same 
name.

I use it when very similar values have the same meaning like:

class Suit(MultiValueEnum):
CLUBS ='♣', 'c', 'C', 'clubs', 'club'
DIAMONDS = '♦', 'd', 'D', 'diamonds', 'diamond'
HEARTS =   '♥', 'h', 'H', 'hearts', 'heart'
SPADES =   '♠', 's', 'S', 'spades', 'spade'


Also it can be used for ECP testing (Equivalence class testing) like this:

from http.client import responses
class ResponseEnum(MultiValueEnum):
GOOD = [status for status in responses if 200 <= status <= 299]
BAD = [status for status in responses if not (200 <= status <= 299)]

I did not think about this use case, but I think it's very interesting and 
useful.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-05 Thread Ethan Furman

Ethan Furman added the comment:

My apologies for the confusion, and thanks for tracking it down.

I'll get the patch in, but I'm curious how you actually use these Enums?  Is 
this a way to easily handle multiple aliases?

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-04 Thread Kiss György

Kiss György added the comment:

Yes, sorry I forgot about that. Here is a minimal example:


from enum import EnumMeta, Enum
from types import DynamicClassAttribute


class _MultiMeta(EnumMeta):
def __init__(enum_class, cls, bases, classdict):
# make sure we only have tuple values, not single values
for member in enum_class.__members__.values():
if not isinstance(member._value_, tuple):
raise ValueError('{!r}, should be tuple'.format(member._value_))

def __call__(cls, suit):
for member in cls:
if suit in member._value_:
return member
return super().__call__(suit)


class MultiValueEnum(Enum, metaclass=_MultiMeta):
@DynamicClassAttribute
def value(self):
"""The value of the Enum member."""
return self._value_[0]

class IncorrectAliasBehavior(MultiValueEnum):
first = 1, 2, 3
second = 4, 5, 6
alias_to_first = 1, 2, 3


When you call IncorrectAliasBehavior.alias_to_first, the documentation says it 
should return IncorrectAliasBehavior.first, but in this case it returns 
IncorrectAliasBehavior.alias_to_first, because canonical_member.value is 
referenced on line 162, and so it returns the redefined value, not the 
internally used one.
This was very confusing for me.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-04 Thread Ethan Furman

Ethan Furman added the comment:

Can you give an example of the code you were having problems with?

--
assignee:  -> ethan.furman
nosy: +ethan.furman

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-04 Thread Ethan Furman

Changes by Ethan Furman :


--
nosy: +barry, eli.bendersky

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue22339] Incorrect behavior when subclassing enum.Enum

2014-09-04 Thread Kiss György

New submission from Kiss György:

There is a small inconvenience in the ``enum`` module.
When I subclass ``enum.Enum`` and redefine the ``value`` dynamic attribute, the 
aliasing behavior doesn't work correctly, because ``member.value`` is used in 
some places instead of ``member._value_``.
I attached a patch where I fixed all these places. This causes no harm to the 
internal working, but makes subclassing behave correctly.

--
components: Library (Lib)
files: enum.patch
keywords: patch
messages: 226392
nosy: Walkman
priority: normal
severity: normal
status: open
title: Incorrect behavior when subclassing enum.Enum
type: enhancement
versions: Python 3.4
Added file: http://bugs.python.org/file36543/enum.patch

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com