mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-99248: [Enum] fix negative number infinite loop (GH-99256)
[Enum] fix negative number infinite loop - _iter_bits_lsb() now raises a ValueError if a negative number is passed in - verify() now skips checking negative numbers for named flags
This commit is contained in:
parent
52f91c642b
commit
0b4ffb08cc
3 changed files with 23 additions and 2 deletions
|
@ -114,9 +114,12 @@ def _make_class_unpicklable(obj):
|
||||||
setattr(obj, '__module__', '<unknown>')
|
setattr(obj, '__module__', '<unknown>')
|
||||||
|
|
||||||
def _iter_bits_lsb(num):
|
def _iter_bits_lsb(num):
|
||||||
# num must be an integer
|
# num must be a positive integer
|
||||||
|
original = num
|
||||||
if isinstance(num, Enum):
|
if isinstance(num, Enum):
|
||||||
num = num.value
|
num = num.value
|
||||||
|
if num < 0:
|
||||||
|
raise ValueError('%r is not a positive integer' % original)
|
||||||
while num:
|
while num:
|
||||||
b = num & (~num + 1)
|
b = num & (~num + 1)
|
||||||
yield b
|
yield b
|
||||||
|
@ -1839,6 +1842,9 @@ class verify:
|
||||||
if name in member_names:
|
if name in member_names:
|
||||||
# not an alias
|
# not an alias
|
||||||
continue
|
continue
|
||||||
|
if alias.value < 0:
|
||||||
|
# negative numbers are not checked
|
||||||
|
continue
|
||||||
values = list(_iter_bits_lsb(alias.value))
|
values = list(_iter_bits_lsb(alias.value))
|
||||||
missed = [v for v in values if v not in member_values]
|
missed = [v for v in values if v not in member_values]
|
||||||
if missed:
|
if missed:
|
||||||
|
|
|
@ -14,7 +14,7 @@ from datetime import date
|
||||||
from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
|
from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
|
||||||
from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
|
from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
|
||||||
from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
|
from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
|
||||||
from enum import member, nonmember
|
from enum import member, nonmember, _iter_bits_lsb
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
|
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
|
||||||
from test import support
|
from test import support
|
||||||
|
@ -174,6 +174,10 @@ class TestHelpers(unittest.TestCase):
|
||||||
for name in self.sunder_names + self.dunder_names + self.random_names:
|
for name in self.sunder_names + self.dunder_names + self.random_names:
|
||||||
self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
|
self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
|
||||||
|
|
||||||
|
def test_iter_bits_lsb(self):
|
||||||
|
self.assertEqual(list(_iter_bits_lsb(7)), [1, 2, 4])
|
||||||
|
self.assertRaisesRegex(ValueError, '-8 is not a positive integer', list, _iter_bits_lsb(-8))
|
||||||
|
|
||||||
|
|
||||||
# for subclassing tests
|
# for subclassing tests
|
||||||
|
|
||||||
|
@ -3960,6 +3964,16 @@ class TestVerify(unittest.TestCase):
|
||||||
triple = 3
|
triple = 3
|
||||||
value = 4
|
value = 4
|
||||||
|
|
||||||
|
def test_negative_alias(self):
|
||||||
|
@verify(NAMED_FLAGS)
|
||||||
|
class Color(Flag):
|
||||||
|
RED = 1
|
||||||
|
GREEN = 2
|
||||||
|
BLUE = 4
|
||||||
|
WHITE = -1
|
||||||
|
# no error means success
|
||||||
|
|
||||||
|
|
||||||
class TestInternals(unittest.TestCase):
|
class TestInternals(unittest.TestCase):
|
||||||
|
|
||||||
sunder_names = '_bad_', '_good_', '_what_ho_'
|
sunder_names = '_bad_', '_good_', '_what_ho_'
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
fix negative numbers failing in verify()
|
Loading…
Add table
Add a link
Reference in a new issue