Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 18 additions & 33 deletions Lib/enum.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import sys
import builtins as bltns
from functools import partial
from types import MappingProxyType, DynamicClassAttribute


Expand Down Expand Up @@ -38,7 +37,7 @@ def _is_descriptor(obj):
"""
Returns True if obj is a descriptor, False otherwise.
"""
return not isinstance(obj, partial) and (
return (
hasattr(obj, '__get__') or
hasattr(obj, '__set__') or
hasattr(obj, '__delete__')
Expand Down Expand Up @@ -151,18 +150,6 @@ def bin(num, max_bits=None):
digits = (sign[-1] * max_bits + digits)[-max_bits:]
return "%s %s" % (sign, digits)

def _dedent(text):
"""
Like textwrap.dedent. Rewritten because we cannot import textwrap.
"""
lines = text.split('\n')
for i, ch in enumerate(lines[0]):
if ch != ' ':
break
for j, l in enumerate(lines):
lines[j] = l[i:]
return '\n'.join(lines)

class _not_given:
def __repr__(self):
return('<not given>')
Expand Down Expand Up @@ -208,7 +195,7 @@ def __get__(self, instance, ownerclass=None):
# use previous enum.property
return self.fget(instance)
elif self._attr_type == 'attr':
# look up previous attibute
# look up previous attribute
return getattr(self._cls_type, self.name)
elif self._attr_type == 'desc':
# use previous descriptor
Expand Down Expand Up @@ -406,12 +393,6 @@ def __setitem__(self, key, value):
elif isinstance(value, nonmember):
# unwrap value here; it won't be processed by the below `else`
value = value.value
elif isinstance(value, partial):
import warnings
warnings.warn('functools.partial will be a method descriptor '
'in future Python versions; wrap it in '
'enum.member() if you want to preserve the '
'old behavior', FutureWarning, stacklevel=2)
elif _is_descriptor(value):
pass
elif self._cls_name is not None and _is_internal_class(self._cls_name, value):
Expand Down Expand Up @@ -1103,6 +1084,21 @@ def _add_member_(cls, name, member):
# now add to _member_map_ (even aliases)
cls._member_map_[name] = member

@property
def __signature__(cls):
from inspect import Parameter, Signature
if cls._member_names_:
return Signature([Parameter('values', Parameter.VAR_POSITIONAL)])
else:
return Signature([Parameter('new_class_name', Parameter.POSITIONAL_ONLY),
Parameter('names', Parameter.POSITIONAL_OR_KEYWORD),
Parameter('module', Parameter.KEYWORD_ONLY, default=None),
Parameter('qualname', Parameter.KEYWORD_ONLY, default=None),
Parameter('type', Parameter.KEYWORD_ONLY, default=None),
Parameter('start', Parameter.KEYWORD_ONLY, default=1),
Parameter('boundary', Parameter.KEYWORD_ONLY, default=None)])


EnumMeta = EnumType # keep EnumMeta name for backwards compatibility


Expand Down Expand Up @@ -1146,13 +1142,6 @@ class Enum(metaclass=EnumType):
attributes -- see the documentation for details.
"""

@classmethod
def __signature__(cls):
if cls._member_names_:
return '(*values)'
else:
return '(new_class_name, /, names, *, module=None, qualname=None, type=None, start=1, boundary=None)'

def __new__(cls, value):
# all enum instances are actually created during class construction
# without calling this method; this method is called by the metaclass'
Expand Down Expand Up @@ -1214,9 +1203,6 @@ def __new__(cls, value):
exc = None
ve_exc = None

def __init__(self, *args, **kwds):
pass

def _add_alias_(self, name):
self.__class__._add_member_(name, self)

Expand Down Expand Up @@ -2041,8 +2027,7 @@ def _test_simple_enum(checked_enum, simple_enum):
... RED = auto()
... GREEN = auto()
... BLUE = auto()
... # TODO: RUSTPYTHON
>>> _test_simple_enum(CheckedColor, Color) # doctest: +SKIP
>>> _test_simple_enum(CheckedColor, Color)

If differences are found, a :exc:`TypeError` is raised.
"""
Expand Down
74 changes: 26 additions & 48 deletions Lib/test/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import builtins as bltns
from collections import OrderedDict
from datetime import date
from functools import partial
from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
Expand All @@ -20,7 +19,8 @@
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
from test import support
from test.support import ALWAYS_EQ, REPO_ROOT
from test.support import threading_helper
from test.support import threading_helper, cpython_only
from test.support.import_helper import ensure_lazy_imports
from datetime import timedelta

python_version = sys.version_info[:2]
Expand Down Expand Up @@ -434,9 +434,9 @@ class Season(self.enum_type):
def spam(cls):
pass
#
self.assertTrue(hasattr(Season, 'spam'))
self.assertHasAttr(Season, 'spam')
del Season.spam
self.assertFalse(hasattr(Season, 'spam'))
self.assertNotHasAttr(Season, 'spam')
#
with self.assertRaises(AttributeError):
del Season.SPRING
Expand All @@ -445,8 +445,7 @@ def spam(cls):
with self.assertRaises(AttributeError):
del Season.SPRING.name

@unittest.expectedFailure # TODO: RUSTPYTHON
# RuntimeError: Error calling __set_name__ on '_proto_member' instance failed in 'BadSuper'
@unittest.expectedFailure # TODO: RUSTPYTHON; RuntimeError: Error calling __set_name__ on '_proto_member' instance failed in 'BadSuper'
def test_bad_new_super(self):
with self.assertRaisesRegex(
TypeError,
Expand Down Expand Up @@ -659,9 +658,6 @@ def __repr__(self):
self.assertEqual(str(Generic.item), 'item.test')

def test_overridden_str(self):
# TODO: RUSTPYTHON, format(NS.first) does not use __str__
if self.__class__ in (TestIntFlagFunction, TestIntFlagClass, TestIntEnumFunction, TestIntEnumClass, TestMinimalFloatFunction, TestMinimalFloatClass):
self.skipTest("format(NS.first) does not use __str__")
NS = self.NewStrEnum
self.assertEqual(str(NS.first), NS.first.name.upper())
self.assertEqual(format(NS.first), NS.first.name.upper())
Expand Down Expand Up @@ -1544,22 +1540,6 @@ class Inner(Enum):
[Outer.a, Outer.b, Outer.Inner],
)

# TODO: RUSTPYTHON
# AssertionError: FutureWarning not triggered
@unittest.expectedFailure
def test_partial(self):
def func(a, b=5):
return a, b
with self.assertWarnsRegex(FutureWarning, r'partial.*enum\.member') as cm:
class E(Enum):
a = 1
b = partial(func)
self.assertEqual(cm.filename, __file__)
self.assertIsInstance(E.b, partial)
self.assertEqual(E.b(2), (2, 5))
with self.assertWarnsRegex(FutureWarning, 'partial'):
self.assertEqual(E.a.b(2), (2, 5))

def test_enum_with_value_name(self):
class Huh(Enum):
name = 1
Expand Down Expand Up @@ -1769,7 +1749,7 @@ class ThreePart(Enum):
self.assertIs(ThreePart((3, 3.0, 'three')), ThreePart.THREE)
self.assertIs(ThreePart(3, 3.0, 'three'), ThreePart.THREE)

@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: <test.test_enum.IntStooges object at 0x55c70c38a240> is not <IntStooges.MOE: 3>
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: <test.test_enum.IntStooges object at 0x55c70c38a240> is not <IntStooges.MOE: 3>
@reraise_if_not_enum(IntStooges)
def test_intenum_from_bytes(self):
self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
Expand Down Expand Up @@ -1923,8 +1903,7 @@ def test_wrong_inheritance_order(self):
class Wrong(Enum, str):
NotHere = 'error before this point'

@unittest.expectedFailure # TODO: RUSTPYTHON
# RuntimeError: Error calling __set_name__ on '_proto_member' instance INVALID in 'RgbColor'
@unittest.expectedFailure # TODO: RUSTPYTHON; RuntimeError: Error calling __set_name__ on '_proto_member' instance INVALID in 'RgbColor'
def test_raise_custom_error_on_creation(self):
class InvalidRgbColorError(ValueError):
def __init__(self, r, g, b):
Expand Down Expand Up @@ -2612,8 +2591,7 @@ class Test(Base2):
self.assertEqual(Test.flash.flash, 'flashy dynamic')
self.assertEqual(Test.flash.value, 1)

@unittest.expectedFailure # TODO: RUSTPYTHON
# RuntimeError: Error calling __set_name__ on '_proto_member' instance grene in 'Color'
@unittest.expectedFailure # TODO: RUSTPYTHON; RuntimeError: Error calling __set_name__ on '_proto_member' instance grene in 'Color'
def test_no_duplicates(self):
class UniqueEnum(Enum):
def __init__(self, *args):
Expand Down Expand Up @@ -2678,12 +2656,12 @@ def __new__(cls, value, period):
OneDay = day_1
OneWeek = week_1
OneMonth = month_1
self.assertFalse(hasattr(Period, '_ignore_'))
self.assertFalse(hasattr(Period, 'Period'))
self.assertFalse(hasattr(Period, 'i'))
self.assertTrue(isinstance(Period.day_1, timedelta))
self.assertTrue(Period.month_1 is Period.day_30)
self.assertTrue(Period.week_4 is Period.day_28)
self.assertNotHasAttr(Period, '_ignore_')
self.assertNotHasAttr(Period, 'Period')
self.assertNotHasAttr(Period, 'i')
self.assertIsInstance(Period.day_1, timedelta)
self.assertIs(Period.month_1, Period.day_30)
self.assertIs(Period.week_4, Period.day_28)

def test_nonhash_value(self):
class AutoNumberInAList(Enum):
Expand Down Expand Up @@ -2903,7 +2881,7 @@ class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
self.assertEqual(str(ReformedColor.BLUE), 'blue')
self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
self.assertEqual(ConfusedColor.RED.social(), "what's up?")
self.assertTrue(issubclass(ReformedColor, int))
self.assertIsSubclass(ReformedColor, int)

def test_multiple_inherited_mixin(self):
@unique
Expand Down Expand Up @@ -2999,8 +2977,7 @@ def test_empty_globals(self):
local_ls = {}
exec(code, global_ns, local_ls)

@unittest.expectedFailure # TODO: RUSTPYTHON
# RuntimeError: Error calling __set_name__ on '_proto_member' instance one in 'FirstFailedStrEnum'
@unittest.expectedFailure # TODO: RUSTPYTHON; RuntimeError: Error calling __set_name__ on '_proto_member' instance one in 'FirstFailedStrEnum'
def test_strenum(self):
class GoodStrEnum(StrEnum):
one = '1'
Expand Down Expand Up @@ -3063,7 +3040,7 @@ class ThirdFailedStrEnum(StrEnum):
one = '1'
two = b'2', 'ascii', 9

@unittest.expectedFailure # TODO: RUSTPYTHON; fails on encoding testing : TypeError: Expected type 'str' but 'builtin_function_or_method' found
@unittest.expectedFailure # TODO: RUSTPYTHON; fails on encoding testing : TypeError: Expected type 'str' but 'builtin_function_or_method' found

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the double space before the comment intentional?

# used to be
@unittest.expectedFailure # TODO: RUSTPYTHON; ...
# now it's
@unittest.expectedFailure  # TODO: RUSTPYTHON; ...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the tradition from PEP-8#inline-comments

... Inline comments should be separated by at least two spaces from the statement. They should start with a # and a single space.

def test_custom_strenum(self):
class CustomStrEnum(str, Enum):
pass
Expand Down Expand Up @@ -3125,8 +3102,7 @@ class ThirdFailedStrEnum(CustomStrEnum):
one = '1'
two = b'2', 'ascii', 9

@unittest.expectedFailure # TODO: RUSTPYTHON
# RuntimeError: Error calling __set_name__ on '_proto_member' instance key_type in 'Combined'
@unittest.expectedFailure # TODO: RUSTPYTHON; RuntimeError: Error calling __set_name__ on '_proto_member' instance key_type in 'Combined'
def test_missing_value_error(self):
with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
class Combined(str, Enum):
Expand Down Expand Up @@ -3413,8 +3389,7 @@ def __new__(cls, c):
self.assertEqual(FlagFromChar.a, 158456325028528675187087900672)
self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673)

@unittest.expectedFailure # TODO: RUSTPYTHON
# RuntimeError: Error calling __set_name__ on '_proto_member' instance A in 'MyEnum'
@unittest.expectedFailure # TODO: RUSTPYTHON; RuntimeError: Error calling __set_name__ on '_proto_member' instance A in 'MyEnum'
def test_init_exception(self):
class Base:
def __new__(cls, *args):
Expand Down Expand Up @@ -4003,7 +3978,7 @@ class Color(StrMixin, AllMixin, Flag):
self.assertEqual(Color.ALL.value, 7)
self.assertEqual(str(Color.BLUE), 'blue')

@unittest.skip('TODO: RUSTPYTHON; flaky test')
@unittest.skip("TODO: RUSTPYTHON; flaky test")
@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_unique_composite(self):
Expand Down Expand Up @@ -4524,7 +4499,7 @@ class Color(StrMixin, AllMixin, IntFlag):
self.assertEqual(Color.ALL.value, 7)
self.assertEqual(str(Color.BLUE), 'blue')

@unittest.skip('TODO: RUSTPYTHON; flaky test')
@unittest.skip("TODO: RUSTPYTHON; flaky test")
@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_unique_composite(self):
Expand Down Expand Up @@ -5073,7 +5048,7 @@ class Color(Enum):
MAGENTA = 2
YELLOW = 3

@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON; | is a read-only view of the internal mapping.
def test_pydoc(self):
# indirectly test __objclass__
if StrEnum.__doc__ is None:
Expand Down Expand Up @@ -5185,7 +5160,6 @@ def test_inspect_classify_class_attrs(self):
if failed:
self.fail("result does not equal expected, see print above")

@unittest.expectedFailure # TODO: RUSTPYTHON; Enum.__signature__ is @classmethod instead of @property
def test_inspect_signatures(self):
from inspect import signature, Signature, Parameter
self.assertEqual(
Expand Down Expand Up @@ -5326,6 +5300,10 @@ class MiscTestCase(unittest.TestCase):
def test__all__(self):
support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})

@cpython_only
def test_lazy_import(self):
ensure_lazy_imports("enum", {"functools", "warnings", "inspect", "re"})

def test_doc_1(self):
class Single(Enum):
ONE = 1
Expand Down
Loading