[3.7] bpo-33217: deprecate non-Enum lookups in Enums (GH-6392)
deprecate non-Enum lookups in Enums Lookups such as `1 in Color` and `2 in SomeFlag()` will raise TypeError in 3.8+.
This commit is contained in:
parent
cbbf746186
commit
3715176557
|
@ -976,7 +976,7 @@ Enum Classes
|
||||||
The :class:`EnumMeta` metaclass is responsible for providing the
|
The :class:`EnumMeta` metaclass is responsible for providing the
|
||||||
:meth:`__contains__`, :meth:`__dir__`, :meth:`__iter__` and other methods that
|
:meth:`__contains__`, :meth:`__dir__`, :meth:`__iter__` and other methods that
|
||||||
allow one to do things with an :class:`Enum` class that fail on a typical
|
allow one to do things with an :class:`Enum` class that fail on a typical
|
||||||
class, such as `list(Color)` or `some_var in Color`. :class:`EnumMeta` is
|
class, such as `list(Color)` or `some_enum_var in Color`. :class:`EnumMeta` is
|
||||||
responsible for ensuring that various other methods on the final :class:`Enum`
|
responsible for ensuring that various other methods on the final :class:`Enum`
|
||||||
class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`,
|
class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`,
|
||||||
:meth:`__str__` and :meth:`__repr__`).
|
:meth:`__str__` and :meth:`__repr__`).
|
||||||
|
|
|
@ -1041,6 +1041,12 @@ Deprecated
|
||||||
:meth:`ssl.SSLContext.wrap_socket` instead.
|
:meth:`ssl.SSLContext.wrap_socket` instead.
|
||||||
(Contributed by Christian Heimes in :issue:`28124`.)
|
(Contributed by Christian Heimes in :issue:`28124`.)
|
||||||
|
|
||||||
|
- In Python 3.8, attempting to check for non-Enum objects in :class:`Enum`
|
||||||
|
classes will raise a :exc:`TypeError` (e.g. ``1 in Color``); similarly,
|
||||||
|
attempting to check for non-Flag objects in a :class:`Flag` member will
|
||||||
|
raise :exc:`TypeError` (e.g. ``1 in Perm.RW``); currently, both operations
|
||||||
|
return :const:`False` instead.
|
||||||
|
|
||||||
|
|
||||||
Windows Only
|
Windows Only
|
||||||
------------
|
------------
|
||||||
|
|
13
Lib/enum.py
13
Lib/enum.py
|
@ -309,6 +309,12 @@ class EnumMeta(type):
|
||||||
return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
|
return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
|
||||||
|
|
||||||
def __contains__(cls, member):
|
def __contains__(cls, member):
|
||||||
|
if not isinstance(member, Enum):
|
||||||
|
import warnings
|
||||||
|
warnings.warn(
|
||||||
|
"using non-Enums in containment checks will raise "
|
||||||
|
"TypeError in Python 3.8",
|
||||||
|
DeprecationWarning, 2)
|
||||||
return isinstance(member, cls) and member._name_ in cls._member_map_
|
return isinstance(member, cls) and member._name_ in cls._member_map_
|
||||||
|
|
||||||
def __delattr__(cls, attr):
|
def __delattr__(cls, attr):
|
||||||
|
@ -713,7 +719,12 @@ class Flag(Enum):
|
||||||
|
|
||||||
def __contains__(self, other):
|
def __contains__(self, other):
|
||||||
if not isinstance(other, self.__class__):
|
if not isinstance(other, self.__class__):
|
||||||
return NotImplemented
|
import warnings
|
||||||
|
warnings.warn(
|
||||||
|
"using non-Flags in containment checks will raise "
|
||||||
|
"TypeError in Python 3.8",
|
||||||
|
DeprecationWarning, 2)
|
||||||
|
return False
|
||||||
return other._value_ & self._value_ == other._value_
|
return other._value_ & self._value_ == other._value_
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
|
@ -325,7 +325,10 @@ class TestEnum(unittest.TestCase):
|
||||||
def test_contains(self):
|
def test_contains(self):
|
||||||
Season = self.Season
|
Season = self.Season
|
||||||
self.assertIn(Season.AUTUMN, Season)
|
self.assertIn(Season.AUTUMN, Season)
|
||||||
self.assertNotIn(3, Season)
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertNotIn(3, Season)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertNotIn('AUTUMN', Season)
|
||||||
|
|
||||||
val = Season(3)
|
val = Season(3)
|
||||||
self.assertIn(val, Season)
|
self.assertIn(val, Season)
|
||||||
|
@ -334,6 +337,11 @@ class TestEnum(unittest.TestCase):
|
||||||
one = 1; two = 2
|
one = 1; two = 2
|
||||||
self.assertNotIn(OtherEnum.two, Season)
|
self.assertNotIn(OtherEnum.two, Season)
|
||||||
|
|
||||||
|
def test_member_contains(self):
|
||||||
|
self.assertRaises(TypeError, lambda: 'test' in self.Season.AUTUMN)
|
||||||
|
self.assertRaises(TypeError, lambda: 3 in self.Season.AUTUMN)
|
||||||
|
self.assertRaises(TypeError, lambda: 'AUTUMN' in self.Season.AUTUMN)
|
||||||
|
|
||||||
def test_comparisons(self):
|
def test_comparisons(self):
|
||||||
Season = self.Season
|
Season = self.Season
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
|
@ -1745,6 +1753,13 @@ class TestFlag(unittest.TestCase):
|
||||||
class Perm(Flag):
|
class Perm(Flag):
|
||||||
R, W, X = 4, 2, 1
|
R, W, X = 4, 2, 1
|
||||||
|
|
||||||
|
class Color(Flag):
|
||||||
|
BLACK = 0
|
||||||
|
RED = 1
|
||||||
|
GREEN = 2
|
||||||
|
BLUE = 4
|
||||||
|
PURPLE = RED|BLUE
|
||||||
|
|
||||||
class Open(Flag):
|
class Open(Flag):
|
||||||
RO = 0
|
RO = 0
|
||||||
WO = 1
|
WO = 1
|
||||||
|
@ -1954,7 +1969,21 @@ class TestFlag(unittest.TestCase):
|
||||||
test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
|
test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
|
||||||
test_pickle_dump_load(self.assertIs, FlagStooges)
|
test_pickle_dump_load(self.assertIs, FlagStooges)
|
||||||
|
|
||||||
def test_containment(self):
|
def test_contains(self):
|
||||||
|
Open = self.Open
|
||||||
|
Color = self.Color
|
||||||
|
self.assertFalse(Color.BLACK in Open)
|
||||||
|
self.assertFalse(Open.RO in Color)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse('BLACK' in Color)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse('RO' in Open)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse(1 in Color)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse(1 in Open)
|
||||||
|
|
||||||
|
def test_member_contains(self):
|
||||||
Perm = self.Perm
|
Perm = self.Perm
|
||||||
R, W, X = Perm
|
R, W, X = Perm
|
||||||
RW = R | W
|
RW = R | W
|
||||||
|
@ -2065,6 +2094,13 @@ class TestIntFlag(unittest.TestCase):
|
||||||
W = 1 << 1
|
W = 1 << 1
|
||||||
R = 1 << 2
|
R = 1 << 2
|
||||||
|
|
||||||
|
class Color(IntFlag):
|
||||||
|
BLACK = 0
|
||||||
|
RED = 1
|
||||||
|
GREEN = 2
|
||||||
|
BLUE = 4
|
||||||
|
PURPLE = RED|BLUE
|
||||||
|
|
||||||
class Open(IntFlag):
|
class Open(IntFlag):
|
||||||
RO = 0
|
RO = 0
|
||||||
WO = 1
|
WO = 1
|
||||||
|
@ -2340,7 +2376,23 @@ class TestIntFlag(unittest.TestCase):
|
||||||
self.assertEqual(len(lst), len(Thing))
|
self.assertEqual(len(lst), len(Thing))
|
||||||
self.assertEqual(len(Thing), 0, Thing)
|
self.assertEqual(len(Thing), 0, Thing)
|
||||||
|
|
||||||
def test_containment(self):
|
def test_contains(self):
|
||||||
|
Color = self.Color
|
||||||
|
Open = self.Open
|
||||||
|
self.assertTrue(Color.GREEN in Color)
|
||||||
|
self.assertTrue(Open.RW in Open)
|
||||||
|
self.assertFalse(Color.GREEN in Open)
|
||||||
|
self.assertFalse(Open.RW in Color)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse('GREEN' in Color)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse('RW' in Open)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse(2 in Color)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse(2 in Open)
|
||||||
|
|
||||||
|
def test_member_contains(self):
|
||||||
Perm = self.Perm
|
Perm = self.Perm
|
||||||
R, W, X = Perm
|
R, W, X = Perm
|
||||||
RW = R | W
|
RW = R | W
|
||||||
|
@ -2359,6 +2411,8 @@ class TestIntFlag(unittest.TestCase):
|
||||||
self.assertFalse(R in WX)
|
self.assertFalse(R in WX)
|
||||||
self.assertFalse(W in RX)
|
self.assertFalse(W in RX)
|
||||||
self.assertFalse(X in RW)
|
self.assertFalse(X in RW)
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
self.assertFalse('swallow' in RW)
|
||||||
|
|
||||||
def test_bool(self):
|
def test_bool(self):
|
||||||
Perm = self.Perm
|
Perm = self.Perm
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Deprecate looking up non-Enum objects in Enum classes and Enum members (will
|
||||||
|
raise :exc:`TypeError` in 3.8+).
|
Loading…
Reference in New Issue