[issue33217] x in enum.Flag() is True when x is no Flag

2018-04-03 Thread Ethan Furman

Ethan Furman  added the comment:

Strings are actually the odd-man out -- dicts, sets, lists, tuples, etc., all 
return False instead of raising TypeError.

The reason str raises an error is because `in`, for str, is a substring check, 
not a membership check.

--

___
Python tracker 

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



[issue33217] x in enum.Flag() is True when x is no Flag

2018-04-03 Thread Dutcho

Dutcho  added the comment:

Ah, the mixin logic mentioned in 33219 solves most of my objections to 
returning False; agree that would make sense
Only remaining inconsistency would be with 1 in 'hello'

--

___
Python tracker 

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



[issue33217] x in enum.Flag() is True when x is no Flag

2018-04-03 Thread Dutcho

Dutcho  added the comment:

Fully agree that Flag.__contains__ must RETURN False or True; that's why I 
suggested it RAISES TypeError
The exception was to be consistent with e.g. Flag.__and__, which by returning 
NotImplemented transfers to type(other).__rand__, and assuming __rand__ cannot 
handle Flag and also returns NotImplemented, falls back to the interpreter 
raising TypeError. Also e.g. 1 in 'hello' raises TypeError.
For Flag, I wouldn't strongly oppose to False for other being a different type. 
However, classes derived from Flag could face issues, e.g. `class MyIntFlag 
(Flag, int): pass`.

--

___
Python tracker 

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



[issue33217] x in enum.Flag() is True when x is no Flag

2018-04-03 Thread Ethan Furman

Ethan Furman  added the comment:

Thanks for finding this!

However, TypeError, an exception, is not the correct type of answer -- the 
correct type of answer for a yes/no question is either True or False.

So the code should be changed from returning NotImplemented to returning False.

--
keywords: +easy

___
Python tracker 

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



[issue33217] x in enum.Flag() is True when x is no Flag

2018-04-03 Thread Ethan Furman

Change by Ethan Furman :


--
assignee:  -> ethan.furman
nosy: +barry, eli.bendersky, ethan.furman
versions: +Python 3.7, Python 3.8

___
Python tracker 

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



[issue33217] x in enum.Flag() is True when x is no Flag

2018-04-03 Thread Dutcho

New submission from Dutcho :

While `Flag() in Flag()` and `Flag() | Flag()` result in the expected outcomes, 
e.g. `str() in Flag()` unexpectedly returns `True`, whereas `Flag() | str()` as 
expected raises a TypeError.
>>> import enum
>>> ABC = enum.Flag('ABC', 'a, b, c')
>>> ac = ABC.a | ABC.c
>>> def test():
... for x in (*ABC, 'test'):
... print(x, end=' ')
... try:
... print(x in ac, end=' ')
... except TypeError as e:
... print(e, end=' ')
... try:
... print(x | ac)
... except TypeError as e:
... print(e)
>>> test()
ABC.a True ABC.c|a
ABC.b False ABC.c|b|a
ABC.c True ABC.c|a
test True unsupported operand type(s) for |: 'str' and 'ABC'

Likely cause is modelling of Flag.__contains__ after Flag.__and__ etc., which 
is incorrect as __contains__ doesn't have a reflected version like __and__ etc. 
have. The returned `NotImplemented` is therefore not handled by the 
interpreter, although it is converted to bool to satisfy __contains__ return 
type.

This can be fixed by redefinition of Flag.__contains__ to raise TypeError:
>>> def __contains__(self, other):
... if not isinstance(other, self.__class__):
... raise TypeError(f"unsupported operand type(s) for 'in': "
... f"{type(other).__qualname__!r} and 
{type(self).__qualname__!r}")
... return other & self == other
>>> enum.Flag.__contains__ = __contains__
>>> test()
ABC.a True ABC.c|a
ABC.b False ABC.c|b|a
ABC.c True ABC.c|a
test unsupported operand type(s) for 'in': 'str' and 'ABC' unsupported 
operand type(s) for |: 'str' and 'ABC'

--
components: Library (Lib)
messages: 314890
nosy: Dutcho
priority: normal
severity: normal
status: open
title: x in enum.Flag() is True when x is no Flag
type: behavior
versions: Python 3.6

___
Python tracker 

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