msg314893 - (view) |
Author: (Dutcho) |
Date: 2018-04-03 20:38 |
While `enum.IntFlag.__and__` accepts an int arg `other` and converts it to `IntFlag` before masking, `enum.IntFlag.__contains__` handles an int arg `other` no different from a different type arg `other` (i.e. returns `True` in Python 3.6 due to issue 33217, but would raise `TypeError` after that's fixed): >>> import enum >>> ABC = enum.Flag('ABC', 'a, b, c') >>> ac = ABC.a | ABC.c >>> ABC.b in ac # works False >>> 2 in ac # should be the same; no exception due to issue 33217 True >>> ac & 3 # works, equivalent to ac & ABC(3) <ABC.a: 1> This is caused by a lack of specialized `IntFlag.__contains__`, so `Flag.__contains__` does the work. Can be fixed by adding a specialization, which (like in `IntFlag.__and__`) tests for `isinstance(other, (IntFlag, int))`. >>> def __contains__(self, other): ... if not isinstance(other, (self.__class__, int)): ... return TypeError ... return other & self == other # conversion of int to IntFlag implicitly handled by IntFlag.__and__ >>> IntFlag.__contains__ = __contains__ |
|
|
msg314897 - (view) |
Author: Ethan Furman (ethan.furman) *  |
Date: 2018-04-03 21:10 |
will not be "fixed" with a TypeError, but incorrect Falses are also bad. Rather than add __contains__ to IntFlag (and every other Flag mixin), I think the best answer is to adjust Flag.__contains__ a little bit more to check if `other` is of the same type as the mixin class, and if so see if it's one of the values. Thank you for being thorough and finding this problem as well. |
|
|
msg314912 - (view) |
Author: Nitish (nitishch) * |
Date: 2018-04-04 02:37 |
@Ethan Furman how can Flag do that? IntFlag can deal with int values too. Would it be possible to deal with int values in this case in Flag.__contains__? |
|
|
msg314951 - (view) |
Author: (Dutcho) |
Date: 2018-04-04 21:03 |
@Nitish The easiest way would probably be to change __contains__ in Flag to: def __contains__(self, other): try: return other & self == other # leave selection of _value_ attribute (if other is Flag) or conversion (if other is int mixin of IntFlag) to __and__ except TypeError: return False Although this would be somewhat convoluted (the generic delegation to __and__ isn't clear at first sight and therefore less maintainable) and may lead to confusing error messages |
|
|
msg314959 - (view) |
Author: Ethan Furman (ethan.furman) *  |
Date: 2018-04-04 23:14 |
Nitish, Flag can check if the current Flag class has a mixin, and if so if the object being checked for is of that same type. Dutcho, my apologies. Looks like I did not fully understand how __contains__ is supposed to work and a TypeError is completely appropriate. Looking into deprecation cycles now to get the change scheduled. |
|
|
msg314993 - (view) |
Author: Ethan Furman (ethan.furman) *  |
Date: 2018-04-05 16:32 |
is tracking member-containment checks; modifying this one to track class-containment checks. Given class Color(Enum): RED = 1 class Fruit(Enum): APPLE = 1 then --> Fruit.APPLE in Color False --> Fruit.APPLE in Fruit True --> 1 in Fruit TypeError The last is currently returning False instead of raising a TypeError. |
|
|
msg315233 - (view) |
Author: Ethan Furman (ethan.furman) *  |
Date: 2018-04-12 21:34 |
This and are similar enough I'm going to track it in . |
|
|