summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_enum.py
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-01-17 12:58:40 (GMT)
committerGitHub <noreply@github.com>2022-01-17 12:58:40 (GMT)
commit42a64c03ec5c443f2a5c2ee4284622f5d1f5326c (patch)
treed5fffd97234c4a8481ee3f07a69107188f1faa7d /Lib/test/test_enum.py
parent7f4b69b9076bdbcea31f6ad16eb125ee99cf0175 (diff)
downloadcpython-42a64c03ec5c443f2a5c2ee4284622f5d1f5326c.zip
cpython-42a64c03ec5c443f2a5c2ee4284622f5d1f5326c.tar.gz
cpython-42a64c03ec5c443f2a5c2ee4284622f5d1f5326c.tar.bz2
Revert "bpo-40066: [Enum] update str() and format() output (GH-30582)" (GH-30632)
This reverts commit acf7403f9baea3ae1119fc6b4a3298522188bf96.
Diffstat (limited to 'Lib/test/test_enum.py')
-rw-r--r--Lib/test/test_enum.py2864
1 files changed, 1505 insertions, 1359 deletions
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index a0953fb..43f98c1 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -6,18 +6,15 @@ import pydoc
import sys
import unittest
import threading
-import builtins as bltns
from collections import OrderedDict
-from datetime import date
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 verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
+from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS
from io import StringIO
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
from test import support
from test.support import ALWAYS_EQ
from test.support import threading_helper
-from textwrap import dedent
from datetime import timedelta
python_version = sys.version_info[:2]
@@ -110,12 +107,6 @@ def test_pickle_exception(assertion, exception, obj):
class TestHelpers(unittest.TestCase):
# _is_descriptor, _is_sunder, _is_dunder
- sunder_names = '_bad_', '_good_', '_what_ho_'
- dunder_names = '__mal__', '__bien__', '__que_que__'
- private_names = '_MyEnum__private', '_MyEnum__still_private'
- private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
- random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
-
def test_is_descriptor(self):
class foo:
pass
@@ -125,36 +116,21 @@ class TestHelpers(unittest.TestCase):
setattr(obj, attr, 1)
self.assertTrue(enum._is_descriptor(obj))
- def test_sunder(self):
- for name in self.sunder_names + self.private_and_sunder_names:
- self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
- for name in self.dunder_names + self.private_names + self.random_names:
- self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
+ def test_is_sunder(self):
for s in ('_a_', '_aa_'):
self.assertTrue(enum._is_sunder(s))
+
for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
'__', '___', '____', '_____',):
self.assertFalse(enum._is_sunder(s))
- def test_dunder(self):
- for name in self.dunder_names:
- self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
- for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
- self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
+ def test_is_dunder(self):
for s in ('__a__', '__aa__'):
self.assertTrue(enum._is_dunder(s))
for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
'__', '___', '____', '_____',):
self.assertFalse(enum._is_dunder(s))
-
- def test_is_private(self):
- for name in self.private_names + self.private_and_sunder_names:
- self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
- for name in self.sunder_names + self.dunder_names + self.random_names:
- self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
-
-
# for subclassing tests
class classproperty:
@@ -190,658 +166,473 @@ class HeadlightsC(IntFlag, boundary=enum.CONFORM):
# tests
-class _EnumTests:
- """
- Test for behavior that is the same across the different types of enumerations.
- """
-
- values = None
+class TestEnum(unittest.TestCase):
def setUp(self):
- class BaseEnum(self.enum_type):
- @enum.property
- def first(self):
- return '%s is first!' % self.name
- class MainEnum(BaseEnum):
- first = auto()
- second = auto()
- third = auto()
- if issubclass(self.enum_type, Flag):
- dupe = 3
- else:
- dupe = third
- self.MainEnum = MainEnum
- #
- class NewStrEnum(self.enum_type):
- def __str__(self):
- return self.name.upper()
- first = auto()
- self.NewStrEnum = NewStrEnum
- #
- class NewFormatEnum(self.enum_type):
- def __format__(self, spec):
- return self.name.upper()
- first = auto()
- self.NewFormatEnum = NewFormatEnum
- #
- class NewStrFormatEnum(self.enum_type):
- def __str__(self):
- return self.name.title()
- def __format__(self, spec):
- return ''.join(reversed(self.name))
- first = auto()
- self.NewStrFormatEnum = NewStrFormatEnum
- #
- class NewBaseEnum(self.enum_type):
- def __str__(self):
- return self.name.title()
- def __format__(self, spec):
- return ''.join(reversed(self.name))
- class NewSubEnum(NewBaseEnum):
- first = auto()
- self.NewSubEnum = NewSubEnum
- #
- self.is_flag = False
- self.names = ['first', 'second', 'third']
- if issubclass(MainEnum, StrEnum):
- self.values = self.names
- elif MainEnum._member_type_ is str:
- self.values = ['1', '2', '3']
- elif issubclass(self.enum_type, Flag):
- self.values = [1, 2, 4]
- self.is_flag = True
- self.dupe2 = MainEnum(5)
- else:
- self.values = self.values or [1, 2, 3]
- #
- if not getattr(self, 'source_values', False):
- self.source_values = self.values
-
- def assertFormatIsValue(self, spec, member):
- self.assertEqual(spec.format(member), spec.format(member.value))
-
- def assertFormatIsStr(self, spec, member):
- self.assertEqual(spec.format(member), spec.format(str(member)))
-
- def test_attribute_deletion(self):
- class Season(self.enum_type):
- SPRING = auto()
- SUMMER = auto()
- AUTUMN = auto()
- #
- def spam(cls):
- pass
- #
- self.assertTrue(hasattr(Season, 'spam'))
- del Season.spam
- self.assertFalse(hasattr(Season, 'spam'))
- #
- with self.assertRaises(AttributeError):
- del Season.SPRING
- with self.assertRaises(AttributeError):
- del Season.DRY
- with self.assertRaises(AttributeError):
- del Season.SPRING.name
-
- def test_basics(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(repr(TE), "<flag 'MainEnum'>")
- self.assertEqual(str(TE), "<flag 'MainEnum'>")
- self.assertEqual(format(TE), "<flag 'MainEnum'>")
- self.assertTrue(TE(5) is self.dupe2)
- else:
- self.assertEqual(repr(TE), "<enum 'MainEnum'>")
- self.assertEqual(str(TE), "<enum 'MainEnum'>")
- self.assertEqual(format(TE), "<enum 'MainEnum'>")
- self.assertEqual(list(TE), [TE.first, TE.second, TE.third])
- self.assertEqual(
- [m.name for m in TE],
- self.names,
- )
- self.assertEqual(
- [m.value for m in TE],
- self.values,
- )
- self.assertEqual(
- [m.first for m in TE],
- ['first is first!', 'second is first!', 'third is first!']
- )
- for member, name in zip(TE, self.names, strict=True):
- self.assertIs(TE[name], member)
- for member, value in zip(TE, self.values, strict=True):
- self.assertIs(TE(value), member)
- if issubclass(TE, StrEnum):
- self.assertTrue(TE.dupe is TE('third') is TE['dupe'])
- elif TE._member_type_ is str:
- self.assertTrue(TE.dupe is TE('3') is TE['dupe'])
- elif issubclass(TE, Flag):
- self.assertTrue(TE.dupe is TE(3) is TE['dupe'])
- else:
- self.assertTrue(TE.dupe is TE(self.values[2]) is TE['dupe'])
+ class Season(Enum):
+ SPRING = 1
+ SUMMER = 2
+ AUTUMN = 3
+ WINTER = 4
+ self.Season = Season
- def test_bool_is_true(self):
- class Empty(self.enum_type):
- pass
- self.assertTrue(Empty)
- #
- self.assertTrue(self.MainEnum)
- for member in self.MainEnum:
- self.assertTrue(member)
+ class Konstants(float, Enum):
+ E = 2.7182818
+ PI = 3.1415926
+ TAU = 2 * PI
+ self.Konstants = Konstants
- def test_changing_member_fails(self):
- MainEnum = self.MainEnum
- with self.assertRaises(AttributeError):
- self.MainEnum.second = 'really first'
+ class Grades(IntEnum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ self.Grades = Grades
- @unittest.skipIf(
- python_version >= (3, 12),
- '__contains__ now returns True/False for all inputs',
- )
- def test_contains_er(self):
- MainEnum = self.MainEnum
- self.assertIn(MainEnum.third, MainEnum)
- with self.assertRaises(TypeError):
- with self.assertWarns(DeprecationWarning):
- self.source_values[1] in MainEnum
- with self.assertRaises(TypeError):
- with self.assertWarns(DeprecationWarning):
- 'first' in MainEnum
- val = MainEnum.dupe
- self.assertIn(val, MainEnum)
- #
- class OtherEnum(Enum):
- one = auto()
- two = auto()
- self.assertNotIn(OtherEnum.two, MainEnum)
+ class Directional(str, Enum):
+ EAST = 'east'
+ WEST = 'west'
+ NORTH = 'north'
+ SOUTH = 'south'
+ self.Directional = Directional
- @unittest.skipIf(
- python_version < (3, 12),
- '__contains__ works only with enum memmbers before 3.12',
- )
- def test_contains_tf(self):
- MainEnum = self.MainEnum
- self.assertIn(MainEnum.first, MainEnum)
- self.assertTrue(self.source_values[0] in MainEnum)
- self.assertFalse('first' in MainEnum)
- val = MainEnum.dupe
- self.assertIn(val, MainEnum)
- #
- class OtherEnum(Enum):
- one = auto()
- two = auto()
- self.assertNotIn(OtherEnum.two, MainEnum)
+ from datetime import date
+ class Holiday(date, Enum):
+ NEW_YEAR = 2013, 1, 1
+ IDES_OF_MARCH = 2013, 3, 15
+ self.Holiday = Holiday
- def test_dir_on_class(self):
- TE = self.MainEnum
- self.assertEqual(set(dir(TE)), set(enum_dir(TE)))
+ class DateEnum(date, Enum): pass
+ self.DateEnum = DateEnum
- def test_dir_on_item(self):
- TE = self.MainEnum
- self.assertEqual(set(dir(TE.first)), set(member_dir(TE.first)))
+ class FloatEnum(float, Enum): pass
+ self.FloatEnum = FloatEnum
- def test_dir_with_added_behavior(self):
- class Test(self.enum_type):
- this = auto()
- these = auto()
+ class Wowser(Enum):
+ this = 'that'
+ these = 'those'
def wowser(self):
+ """Wowser docstring"""
return ("Wowser! I'm %s!" % self.name)
- self.assertTrue('wowser' not in dir(Test))
- self.assertTrue('wowser' in dir(Test.this))
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.Wowser = Wowser
+
+ class IntWowser(IntEnum):
+ this = 1
+ these = 2
+ def wowser(self):
+ """Wowser docstring"""
+ return ("Wowser! I'm %s!" % self.name)
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.IntWowser = IntWowser
+
+ class FloatWowser(float, Enum):
+ this = 3.14
+ these = 4.2
+ def wowser(self):
+ """Wowser docstring"""
+ return ("Wowser! I'm %s!" % self.name)
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.FloatWowser = FloatWowser
+
+ class WowserNoMembers(Enum):
+ def wowser(self): pass
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ class SubclassOfWowserNoMembers(WowserNoMembers): pass
+ self.WowserNoMembers = WowserNoMembers
+ self.SubclassOfWowserNoMembers = SubclassOfWowserNoMembers
+
+ class IntWowserNoMembers(IntEnum):
+ def wowser(self): pass
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.IntWowserNoMembers = IntWowserNoMembers
+
+ class FloatWowserNoMembers(float, Enum):
+ def wowser(self): pass
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.FloatWowserNoMembers = FloatWowserNoMembers
+
+ class EnumWithInit(Enum):
+ def __init__(self, greeting, farewell):
+ self.greeting = greeting
+ self.farewell = farewell
+ ENGLISH = 'hello', 'goodbye'
+ GERMAN = 'Guten Morgen', 'Auf Wiedersehen'
+ def some_method(self): pass
+ self.EnumWithInit = EnumWithInit
- def test_dir_on_sub_with_behavior_on_super(self):
# see issue22506
- class SuperEnum(self.enum_type):
+ class SuperEnum1(Enum):
def invisible(self):
return "did you see me?"
- class SubEnum(SuperEnum):
- sample = auto()
- self.assertTrue('invisible' not in dir(SubEnum))
- self.assertTrue('invisible' in dir(SubEnum.sample))
+ class SubEnum1(SuperEnum1):
+ sample = 5
+ self.SubEnum1 = SubEnum1
- def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
- # see issue40084
- class SuperEnum(self.enum_type):
- def __new__(cls, *value, **kwds):
- new = self.enum_type._member_type_.__new__
- if self.enum_type._member_type_ is object:
- obj = new(cls)
- else:
- if isinstance(value[0], tuple):
- create_value ,= value[0]
- else:
- create_value = value
- obj = new(cls, *create_value)
- obj._value_ = value[0] if len(value) == 1 else value
- obj.description = 'test description'
+ class SuperEnum2(IntEnum):
+ def __new__(cls, value, description=""):
+ obj = int.__new__(cls, value)
+ obj._value_ = value
+ obj.description = description
return obj
- class SubEnum(SuperEnum):
- sample = self.source_values[1]
- self.assertTrue('description' not in dir(SubEnum))
- self.assertTrue('description' in dir(SubEnum.sample), dir(SubEnum.sample))
-
- def test_enum_in_enum_out(self):
- Main = self.MainEnum
- self.assertIs(Main(Main.first), Main.first)
-
- def test_hash(self):
- MainEnum = self.MainEnum
- mapping = {}
- mapping[MainEnum.first] = '1225'
- mapping[MainEnum.second] = '0315'
- mapping[MainEnum.third] = '0704'
- self.assertEqual(mapping[MainEnum.second], '0315')
-
- def test_invalid_names(self):
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- mro = 9
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _create_= 11
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _get_mixins_ = 9
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _find_new_ = 1
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _any_name_ = 9
-
- def test_object_str_override(self):
- "check that setting __str__ to object's is not reset to Enum's"
- class Generic(self.enum_type):
- item = self.source_values[2]
- def __repr__(self):
- return "%s.test" % (self._name_, )
- __str__ = object.__str__
- self.assertEqual(str(Generic.item), 'item.test')
-
- def test_overridden_str(self):
- NS = self.NewStrEnum
- self.assertEqual(str(NS.first), NS.first.name.upper())
- self.assertEqual(format(NS.first), NS.first.name.upper())
+ class SubEnum2(SuperEnum2):
+ sample = 5
+ self.SubEnum2 = SubEnum2
+
+ def test_dir_basics_for_all_enums(self):
+ enums_for_tests = (
+ # Generic enums in enum.py
+ Enum,
+ IntEnum,
+ StrEnum,
+ # Generic enums defined outside of enum.py
+ self.DateEnum,
+ self.FloatEnum,
+ # Concrete enums derived from enum.py generics
+ self.Grades,
+ self.Season,
+ # Concrete enums derived from generics defined outside of enum.py
+ self.Konstants,
+ self.Holiday,
+ # Standard enum with added behaviour & members
+ self.Wowser,
+ # Mixin-enum-from-enum.py with added behaviour & members
+ self.IntWowser,
+ # Mixin-enum-from-oustide-enum.py with added behaviour & members
+ self.FloatWowser,
+ # Equivalents of the three immediately above, but with no members
+ self.WowserNoMembers,
+ self.IntWowserNoMembers,
+ self.FloatWowserNoMembers,
+ # Enum with members and an __init__ method
+ self.EnumWithInit,
+ # Special cases to test
+ self.SubEnum1,
+ self.SubEnum2
+ )
+
+ for cls in enums_for_tests:
+ with self.subTest(cls=cls):
+ cls_dir = dir(cls)
+ # test that dir is deterministic
+ self.assertEqual(cls_dir, dir(cls))
+ # test that dir is sorted
+ self.assertEqual(list(cls_dir), sorted(cls_dir))
+ # test that there are no dupes in dir
+ self.assertEqual(len(cls_dir), len(set(cls_dir)))
+ # test that there are no sunders in dir
+ self.assertFalse(any(enum._is_sunder(attr) for attr in cls_dir))
+ self.assertNotIn('__new__', cls_dir)
+
+ for attr in ('__class__', '__doc__', '__members__', '__module__'):
+ with self.subTest(attr=attr):
+ self.assertIn(attr, cls_dir)
+
+ def test_dir_for_enum_with_members(self):
+ enums_for_test = (
+ # Enum with members
+ self.Season,
+ # IntEnum with members
+ self.Grades,
+ # Two custom-mixin enums with members
+ self.Konstants,
+ self.Holiday,
+ # several enums-with-added-behaviour and members
+ self.Wowser,
+ self.IntWowser,
+ self.FloatWowser,
+ # An enum with an __init__ method and members
+ self.EnumWithInit,
+ # Special cases to test
+ self.SubEnum1,
+ self.SubEnum2
+ )
+
+ for cls in enums_for_test:
+ cls_dir = dir(cls)
+ member_names = cls._member_names_
+ with self.subTest(cls=cls):
+ self.assertTrue(all(member_name in cls_dir for member_name in member_names))
+ for member in cls:
+ member_dir = dir(member)
+ # test that dir is deterministic
+ self.assertEqual(member_dir, dir(member))
+ # test that dir is sorted
+ self.assertEqual(list(member_dir), sorted(member_dir))
+ # test that there are no dupes in dir
+ self.assertEqual(len(member_dir), len(set(member_dir)))
+
+ for attr_name in cls_dir:
+ with self.subTest(attr_name=attr_name):
+ if attr_name in {'__members__', '__init__', '__new__', *member_names}:
+ self.assertNotIn(attr_name, member_dir)
+ else:
+ self.assertIn(attr_name, member_dir)
+
+ self.assertFalse(any(enum._is_sunder(attr) for attr in member_dir))
+
+ def test_dir_for_enums_with_added_behaviour(self):
+ enums_for_test = (
+ self.Wowser,
+ self.IntWowser,
+ self.FloatWowser,
+ self.WowserNoMembers,
+ self.SubclassOfWowserNoMembers,
+ self.IntWowserNoMembers,
+ self.FloatWowserNoMembers
+ )
+
+ for cls in enums_for_test:
+ with self.subTest(cls=cls):
+ self.assertIn('wowser', dir(cls))
+ self.assertIn('classmethod_wowser', dir(cls))
+ self.assertIn('staticmethod_wowser', dir(cls))
+ self.assertTrue(all(
+ all(attr in dir(member) for attr in ('wowser', 'classmethod_wowser', 'staticmethod_wowser'))
+ for member in cls
+ ))
- def test_overridden_str_format(self):
- NSF = self.NewStrFormatEnum
- self.assertEqual(str(NSF.first), NSF.first.name.title())
- self.assertEqual(format(NSF.first), ''.join(reversed(NSF.first.name)))
+ self.assertEqual(dir(self.WowserNoMembers), dir(self.SubclassOfWowserNoMembers))
+ # Check classmethods are present
+ self.assertIn('from_bytes', dir(self.IntWowser))
+ self.assertIn('from_bytes', dir(self.IntWowserNoMembers))
+
+ def test_help_output_on_enum_members(self):
+ added_behaviour_enums = (
+ self.Wowser,
+ self.IntWowser,
+ self.FloatWowser
+ )
+
+ for cls in added_behaviour_enums:
+ with self.subTest(cls=cls):
+ rendered_doc = pydoc.render_doc(cls.this)
+ self.assertIn('Wowser docstring', rendered_doc)
+ if cls in {self.IntWowser, self.FloatWowser}:
+ self.assertIn('float(self)', rendered_doc)
+
+ def test_dir_for_enum_with_init(self):
+ EnumWithInit = self.EnumWithInit
+
+ cls_dir = dir(EnumWithInit)
+ self.assertIn('__init__', cls_dir)
+ self.assertIn('some_method', cls_dir)
+ self.assertNotIn('greeting', cls_dir)
+ self.assertNotIn('farewell', cls_dir)
+
+ member_dir = dir(EnumWithInit.ENGLISH)
+ self.assertNotIn('__init__', member_dir)
+ self.assertIn('some_method', member_dir)
+ self.assertIn('greeting', member_dir)
+ self.assertIn('farewell', member_dir)
+
+ def test_mixin_dirs(self):
+ from datetime import date
- def test_overridden_str_format_inherited(self):
- NSE = self.NewSubEnum
- self.assertEqual(str(NSE.first), NSE.first.name.title())
- self.assertEqual(format(NSE.first), ''.join(reversed(NSE.first.name)))
+ enums_for_test = (
+ # generic mixins from enum.py
+ (IntEnum, int),
+ (StrEnum, str),
+ # generic mixins from outside enum.py
+ (self.FloatEnum, float),
+ (self.DateEnum, date),
+ # concrete mixin from enum.py
+ (self.Grades, int),
+ # concrete mixin from outside enum.py
+ (self.Holiday, date),
+ # concrete mixin from enum.py with added behaviour
+ (self.IntWowser, int),
+ # concrete mixin from outside enum.py with added behaviour
+ (self.FloatWowser, float)
+ )
+
+ enum_dict = Enum.__dict__
+ enum_dir = dir(Enum)
+ enum_module_names = enum.__all__
+ is_from_enum_module = lambda cls: cls.__name__ in enum_module_names
+ is_enum_dunder = lambda attr: enum._is_dunder(attr) and attr in enum_dict
+
+ def attr_is_inherited_from_object(cls, attr_name):
+ for base in cls.__mro__:
+ if attr_name in base.__dict__:
+ return base is object
+ return False
+
+ # General tests
+ for enum_cls, mixin_cls in enums_for_test:
+ with self.subTest(enum_cls=enum_cls):
+ cls_dir = dir(enum_cls)
+ cls_dict = enum_cls.__dict__
+
+ mixin_attrs = [
+ x for x in dir(mixin_cls)
+ if not attr_is_inherited_from_object(cls=mixin_cls, attr_name=x)
+ ]
- def test_programmatic_function_string(self):
- MinorEnum = self.enum_type('MinorEnum', 'june july august')
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
+ first_enum_base = next(
+ base for base in enum_cls.__mro__
+ if is_from_enum_module(base)
)
- values = self.values
- if self.enum_type is StrEnum:
- values = ['june','july','august']
- for month, av in zip('june july august'.split(), values):
- e = MinorEnum[month]
- self.assertEqual(e.value, av, list(MinorEnum))
- self.assertEqual(e.name, month)
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
- def test_programmatic_function_string_list(self):
- MinorEnum = self.enum_type('MinorEnum', ['june', 'july', 'august'])
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- values = self.values
- if self.enum_type is StrEnum:
- values = ['june','july','august']
- for month, av in zip('june july august'.split(), values):
- e = MinorEnum[month]
- self.assertEqual(e.value, av)
- self.assertEqual(e.name, month)
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
+ for attr in mixin_attrs:
+ with self.subTest(attr=attr):
+ if enum._is_sunder(attr):
+ # Unlikely, but no harm in testing
+ self.assertNotIn(attr, cls_dir)
+ elif attr in {'__class__', '__doc__', '__members__', '__module__'}:
+ self.assertIn(attr, cls_dir)
+ elif is_enum_dunder(attr):
+ if is_from_enum_module(enum_cls):
+ self.assertNotIn(attr, cls_dir)
+ elif getattr(enum_cls, attr) is getattr(first_enum_base, attr):
+ self.assertNotIn(attr, cls_dir)
+ else:
+ self.assertIn(attr, cls_dir)
+ else:
+ self.assertIn(attr, cls_dir)
+
+ # Some specific examples
+ int_enum_dir = dir(IntEnum)
+ self.assertIn('imag', int_enum_dir)
+ self.assertIn('__rfloordiv__', int_enum_dir)
+ self.assertNotIn('__format__', int_enum_dir)
+ self.assertNotIn('__hash__', int_enum_dir)
+ self.assertNotIn('__init_subclass__', int_enum_dir)
+ self.assertNotIn('__subclasshook__', int_enum_dir)
+
+ class OverridesFormatOutsideEnumModule(Enum):
+ def __format__(self, *args, **kwargs):
+ return super().__format__(*args, **kwargs)
+ SOME_MEMBER = 1
+
+ self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule))
+ self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule.SOME_MEMBER))
- def test_programmatic_function_iterable(self):
- MinorEnum = self.enum_type(
- 'MinorEnum',
- (('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2]))
- )
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
+ def test_dir_on_sub_with_behavior_on_super(self):
+ # see issue22506
self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
+ set(dir(self.SubEnum1.sample)),
+ set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
)
- for month, av in zip('june july august'.split(), self.values):
- e = MinorEnum[month]
- self.assertEqual(e.value, av)
- self.assertEqual(e.name, month)
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
- def test_programmatic_function_from_dict(self):
- MinorEnum = self.enum_type(
- 'MinorEnum',
- OrderedDict((('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2])))
- )
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for month, av in zip('june july august'.split(), self.values):
- e = MinorEnum[month]
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
+ def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
+ # see issue40084
+ self.assertTrue({'description'} <= set(dir(self.SubEnum2.sample)))
- def test_repr(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(repr(TE(0)), "<MainEnum: 0>")
- self.assertEqual(repr(TE.dupe), "<MainEnum.dupe: 3>")
- self.assertEqual(repr(self.dupe2), "<MainEnum.first|third: 5>")
- elif issubclass(TE, StrEnum):
- self.assertEqual(repr(TE.dupe), "<MainEnum.third: 'third'>")
- else:
- self.assertEqual(repr(TE.dupe), "<MainEnum.third: %r>" % (self.values[2], ), TE._value_repr_)
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(repr(member), "<MainEnum.%s: %r>" % (member.name, member.value))
+ def test_enum_in_enum_out(self):
+ Season = self.Season
+ self.assertIs(Season(Season.WINTER), Season.WINTER)
- def test_repr_override(self):
- class Generic(self.enum_type):
- first = auto()
- second = auto()
- third = auto()
- def __repr__(self):
- return "don't you just love shades of %s?" % self.name
- self.assertEqual(
- repr(Generic.third),
- "don't you just love shades of third?",
- )
+ def test_enum_value(self):
+ Season = self.Season
+ self.assertEqual(Season.SPRING.value, 1)
- def test_inherited_repr(self):
- class MyEnum(self.enum_type):
- def __repr__(self):
- return "My name is %s." % self.name
- class MySubEnum(MyEnum):
- this = auto()
- that = auto()
- theother = auto()
- self.assertEqual(repr(MySubEnum.that), "My name is that.")
+ def test_intenum_value(self):
+ self.assertEqual(IntStooges.CURLY.value, 2)
- def test_reversed_iteration_order(self):
+ def test_enum(self):
+ Season = self.Season
+ lst = list(Season)
+ self.assertEqual(len(lst), len(Season))
+ self.assertEqual(len(Season), 4, Season)
self.assertEqual(
- list(reversed(self.MainEnum)),
- [self.MainEnum.third, self.MainEnum.second, self.MainEnum.first],
- )
+ [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
-class _PlainOutputTests:
-
- def test_str(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(str(TE.dupe), "MainEnum.dupe")
- self.assertEqual(str(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(str(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
-
- def test_format(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(format(TE.dupe), "MainEnum.dupe")
- self.assertEqual(format(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(format(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
-
- def test_overridden_format(self):
- NF = self.NewFormatEnum
- self.assertEqual(str(NF.first), "NewFormatEnum.first", '%s %r' % (NF.__str__, NF.first))
- self.assertEqual(format(NF.first), "FIRST")
-
- def test_format_specs(self):
- TE = self.MainEnum
- self.assertFormatIsStr('{}', TE.second)
- self.assertFormatIsStr('{:}', TE.second)
- self.assertFormatIsStr('{:20}', TE.second)
- self.assertFormatIsStr('{:^20}', TE.second)
- self.assertFormatIsStr('{:>20}', TE.second)
- self.assertFormatIsStr('{:<20}', TE.second)
- self.assertFormatIsStr('{:5.2}', TE.second)
-
-
-class _MixedOutputTests:
-
- def test_str(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(str(TE.dupe), "MainEnum.dupe")
- self.assertEqual(str(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(str(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
-
- def test_format(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(format(TE.dupe), "MainEnum.dupe")
- self.assertEqual(format(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(format(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
-
- def test_overridden_format(self):
- NF = self.NewFormatEnum
- self.assertEqual(str(NF.first), "NewFormatEnum.first")
- self.assertEqual(format(NF.first), "FIRST")
-
- def test_format_specs(self):
- TE = self.MainEnum
- self.assertFormatIsStr('{}', TE.first)
- self.assertFormatIsStr('{:}', TE.first)
- self.assertFormatIsStr('{:20}', TE.first)
- self.assertFormatIsStr('{:^20}', TE.first)
- self.assertFormatIsStr('{:>20}', TE.first)
- self.assertFormatIsStr('{:<20}', TE.first)
- self.assertFormatIsStr('{:5.2}', TE.first)
-
-
-class _MinimalOutputTests:
-
- def test_str(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(str(TE.dupe), "3")
- self.assertEqual(str(self.dupe2), "5")
- else:
- self.assertEqual(str(TE.dupe), str(self.values[2]))
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(str(member), str(value))
-
- def test_format(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(format(TE.dupe), "3")
- self.assertEqual(format(self.dupe2), "5")
- else:
- self.assertEqual(format(TE.dupe), format(self.values[2]))
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(format(member), format(value))
-
- def test_overridden_format(self):
- NF = self.NewFormatEnum
- self.assertEqual(str(NF.first), str(self.values[0]))
- self.assertEqual(format(NF.first), "FIRST")
-
- def test_format_specs(self):
- TE = self.MainEnum
- self.assertFormatIsValue('{}', TE.third)
- self.assertFormatIsValue('{:}', TE.third)
- self.assertFormatIsValue('{:20}', TE.third)
- self.assertFormatIsValue('{:^20}', TE.third)
- self.assertFormatIsValue('{:>20}', TE.third)
- self.assertFormatIsValue('{:<20}', TE.third)
- if TE._member_type_ is float:
- self.assertFormatIsValue('{:n}', TE.third)
- self.assertFormatIsValue('{:5.2}', TE.third)
- self.assertFormatIsValue('{:f}', TE.third)
-
-
-class _FlagTests:
-
- def test_default_missing_with_wrong_type_value(self):
- with self.assertRaisesRegex(
- ValueError,
- "'RED' is not a valid TestFlag.Color",
- ) as ctx:
- self.MainEnum('RED')
- self.assertIs(ctx.exception.__context__, None)
-
-class TestPlainEnum(_EnumTests, _PlainOutputTests, unittest.TestCase):
- enum_type = Enum
-
-
-class TestPlainFlag(_EnumTests, _PlainOutputTests, unittest.TestCase):
- enum_type = Flag
-
-
-class TestIntEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
- enum_type = IntEnum
-
-
-class TestStrEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
- enum_type = StrEnum
-
-
-class TestIntFlag(_EnumTests, _MinimalOutputTests, unittest.TestCase):
- enum_type = IntFlag
-
-
-class TestMixedInt(_EnumTests, _MixedOutputTests, unittest.TestCase):
- class enum_type(int, Enum): pass
-
-
-class TestMixedStr(_EnumTests, _MixedOutputTests, unittest.TestCase):
- class enum_type(str, Enum): pass
-
-
-class TestMixedIntFlag(_EnumTests, _MixedOutputTests, unittest.TestCase):
- class enum_type(int, Flag): pass
-
-
-class TestMixedDate(_EnumTests, _MixedOutputTests, unittest.TestCase):
-
- values = [date(2021, 12, 25), date(2020, 3, 15), date(2019, 11, 27)]
- source_values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
-
- class enum_type(date, Enum):
- def _generate_next_value_(name, start, count, last_values):
- values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
- return values[count]
-
-
-class TestMinimalDate(_EnumTests, _MinimalOutputTests, unittest.TestCase):
-
- values = [date(2023, 12, 1), date(2016, 2, 29), date(2009, 1, 1)]
- source_values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
-
- class enum_type(date, ReprEnum):
- def _generate_next_value_(name, start, count, last_values):
- values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
- return values[count]
-
-
-class TestMixedFloat(_EnumTests, _MixedOutputTests, unittest.TestCase):
-
- values = [1.1, 2.2, 3.3]
+ for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
+ e = Season(i)
+ self.assertEqual(e, getattr(Season, season))
+ self.assertEqual(e.value, i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, season)
+ self.assertIn(e, Season)
+ self.assertIs(type(e), Season)
+ self.assertIsInstance(e, Season)
+ self.assertEqual(str(e), season)
+ self.assertEqual(repr(e), 'Season.{0}'.format(season))
+
+ def test_value_name(self):
+ Season = self.Season
+ self.assertEqual(Season.SPRING.name, 'SPRING')
+ self.assertEqual(Season.SPRING.value, 1)
+ with self.assertRaises(AttributeError):
+ Season.SPRING.name = 'invierno'
+ with self.assertRaises(AttributeError):
+ Season.SPRING.value = 2
- class enum_type(float, Enum):
- def _generate_next_value_(name, start, count, last_values):
- values = [1.1, 2.2, 3.3]
- return values[count]
+ def test_changing_member(self):
+ Season = self.Season
+ with self.assertRaises(AttributeError):
+ Season.WINTER = 'really cold'
+ def test_attribute_deletion(self):
+ class Season(Enum):
+ SPRING = 1
+ SUMMER = 2
+ AUTUMN = 3
+ WINTER = 4
-class TestMinimalFloat(_EnumTests, _MinimalOutputTests, unittest.TestCase):
+ def spam(cls):
+ pass
- values = [4.4, 5.5, 6.6]
+ self.assertTrue(hasattr(Season, 'spam'))
+ del Season.spam
+ self.assertFalse(hasattr(Season, 'spam'))
- class enum_type(float, ReprEnum):
- def _generate_next_value_(name, start, count, last_values):
- values = [4.4, 5.5, 6.6]
- return values[count]
+ with self.assertRaises(AttributeError):
+ del Season.SPRING
+ with self.assertRaises(AttributeError):
+ del Season.DRY
+ with self.assertRaises(AttributeError):
+ del Season.SPRING.name
+ def test_bool_of_class(self):
+ class Empty(Enum):
+ pass
+ self.assertTrue(bool(Empty))
-class TestSpecial(unittest.TestCase):
- """
- various operations that are not attributable to every possible enum
- """
+ def test_bool_of_member(self):
+ class Count(Enum):
+ zero = 0
+ one = 1
+ two = 2
+ for member in Count:
+ self.assertTrue(bool(member))
- def setUp(self):
- class Season(Enum):
- SPRING = 1
- SUMMER = 2
- AUTUMN = 3
- WINTER = 4
- self.Season = Season
- #
- class Grades(IntEnum):
- A = 5
- B = 4
- C = 3
- D = 2
- F = 0
- self.Grades = Grades
- #
- class Directional(str, Enum):
- EAST = 'east'
- WEST = 'west'
- NORTH = 'north'
- SOUTH = 'south'
- self.Directional = Directional
- #
- from datetime import date
- class Holiday(date, Enum):
- NEW_YEAR = 2013, 1, 1
- IDES_OF_MARCH = 2013, 3, 15
- self.Holiday = Holiday
+ def test_invalid_names(self):
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ mro = 9
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _create_= 11
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _get_mixins_ = 9
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _find_new_ = 1
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _any_name_ = 9
def test_bool(self):
# plain Enum members are always True
@@ -865,56 +656,92 @@ class TestSpecial(unittest.TestCase):
self.assertTrue(IntLogic.true)
self.assertFalse(IntLogic.false)
+ @unittest.skipIf(
+ python_version >= (3, 12),
+ '__contains__ now returns True/False for all inputs',
+ )
+ def test_contains_er(self):
+ Season = self.Season
+ self.assertIn(Season.AUTUMN, Season)
+ with self.assertRaises(TypeError):
+ with self.assertWarns(DeprecationWarning):
+ 3 in Season
+ with self.assertRaises(TypeError):
+ with self.assertWarns(DeprecationWarning):
+ 'AUTUMN' in Season
+ val = Season(3)
+ self.assertIn(val, Season)
+ #
+ class OtherEnum(Enum):
+ one = 1; two = 2
+ self.assertNotIn(OtherEnum.two, Season)
+
+ @unittest.skipIf(
+ python_version < (3, 12),
+ '__contains__ only works with enum memmbers before 3.12',
+ )
+ def test_contains_tf(self):
+ Season = self.Season
+ self.assertIn(Season.AUTUMN, Season)
+ self.assertTrue(3 in Season)
+ self.assertFalse('AUTUMN' in Season)
+ val = Season(3)
+ self.assertIn(val, Season)
+ #
+ class OtherEnum(Enum):
+ one = 1; two = 2
+ self.assertNotIn(OtherEnum.two, Season)
+
def test_comparisons(self):
Season = self.Season
with self.assertRaises(TypeError):
Season.SPRING < Season.WINTER
with self.assertRaises(TypeError):
Season.SPRING > 4
- #
+
self.assertNotEqual(Season.SPRING, 1)
- #
+
class Part(Enum):
SPRING = 1
CLIP = 2
BARREL = 3
- #
+
self.assertNotEqual(Season.SPRING, Part.SPRING)
with self.assertRaises(TypeError):
Season.SPRING < Part.CLIP
- def test_dir_with_custom_dunders(self):
- class PlainEnum(Enum):
- pass
- cls_dir = dir(PlainEnum)
- self.assertNotIn('__repr__', cls_dir)
- self.assertNotIn('__str__', cls_dir)
- self.assertNotIn('__repr__', cls_dir)
- self.assertNotIn('__repr__', cls_dir)
- #
- class MyEnum(Enum):
- def __repr__(self):
- return object.__repr__(self)
- def __str__(self):
- return object.__repr__(self)
- def __format__(self):
- return object.__repr__(self)
- def __init__(self):
- pass
- cls_dir = dir(MyEnum)
- self.assertIn('__repr__', cls_dir)
- self.assertIn('__str__', cls_dir)
- self.assertIn('__repr__', cls_dir)
- self.assertIn('__repr__', cls_dir)
+ def test_enum_duplicates(self):
+ class Season(Enum):
+ SPRING = 1
+ SUMMER = 2
+ AUTUMN = FALL = 3
+ WINTER = 4
+ ANOTHER_SPRING = 1
+ lst = list(Season)
+ self.assertEqual(
+ lst,
+ [Season.SPRING, Season.SUMMER,
+ Season.AUTUMN, Season.WINTER,
+ ])
+ self.assertIs(Season.FALL, Season.AUTUMN)
+ self.assertEqual(Season.FALL.value, 3)
+ self.assertEqual(Season.AUTUMN.value, 3)
+ self.assertIs(Season(3), Season.AUTUMN)
+ self.assertIs(Season(1), Season.SPRING)
+ self.assertEqual(Season.FALL.name, 'AUTUMN')
+ self.assertEqual(
+ [k for k,v in Season.__members__.items() if v.name != k],
+ ['FALL', 'ANOTHER_SPRING'],
+ )
- def test_duplicate_name_error(self):
+ def test_duplicate_name(self):
with self.assertRaises(TypeError):
class Color(Enum):
red = 1
green = 2
blue = 3
red = 4
- #
+
with self.assertRaises(TypeError):
class Color(Enum):
red = 1
@@ -922,45 +749,232 @@ class TestSpecial(unittest.TestCase):
blue = 3
def red(self):
return 'red'
- #
+
with self.assertRaises(TypeError):
class Color(Enum):
- @enum.property
+ @property
def red(self):
return 'redder'
red = 1
green = 2
blue = 3
- def test_enum_function_with_qualname(self):
- if isinstance(Theory, Exception):
- raise Theory
- self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
+ def test_reserved__sunder_(self):
+ with self.assertRaisesRegex(
+ ValueError,
+ '_sunder_ names, such as ._bad_., are reserved',
+ ):
+ class Bad(Enum):
+ _bad_ = 1
def test_enum_with_value_name(self):
class Huh(Enum):
name = 1
value = 2
- self.assertEqual(list(Huh), [Huh.name, Huh.value])
+ self.assertEqual(
+ list(Huh),
+ [Huh.name, Huh.value],
+ )
self.assertIs(type(Huh.name), Huh)
self.assertEqual(Huh.name.name, 'name')
self.assertEqual(Huh.name.value, 1)
+ def test_format_enum(self):
+ Season = self.Season
+ self.assertEqual('{}'.format(Season.SPRING),
+ '{}'.format(str(Season.SPRING)))
+ self.assertEqual( '{:}'.format(Season.SPRING),
+ '{:}'.format(str(Season.SPRING)))
+ self.assertEqual('{:20}'.format(Season.SPRING),
+ '{:20}'.format(str(Season.SPRING)))
+ self.assertEqual('{:^20}'.format(Season.SPRING),
+ '{:^20}'.format(str(Season.SPRING)))
+ self.assertEqual('{:>20}'.format(Season.SPRING),
+ '{:>20}'.format(str(Season.SPRING)))
+ self.assertEqual('{:<20}'.format(Season.SPRING),
+ '{:<20}'.format(str(Season.SPRING)))
+
+ def test_str_override_enum(self):
+ class EnumWithStrOverrides(Enum):
+ one = auto()
+ two = auto()
+
+ def __str__(self):
+ return 'Str!'
+ self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
+ self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
+
+ def test_format_override_enum(self):
+ class EnumWithFormatOverride(Enum):
+ one = 1.0
+ two = 2.0
+ def __format__(self, spec):
+ return 'Format!!'
+ self.assertEqual(str(EnumWithFormatOverride.one), 'one')
+ self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
+
+ def test_str_and_format_override_enum(self):
+ class EnumWithStrFormatOverrides(Enum):
+ one = auto()
+ two = auto()
+ def __str__(self):
+ return 'Str!'
+ def __format__(self, spec):
+ return 'Format!'
+ self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
+ self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
+
+ def test_str_override_mixin(self):
+ class MixinEnumWithStrOverride(float, Enum):
+ one = 1.0
+ two = 2.0
+ def __str__(self):
+ return 'Overridden!'
+ self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
+ self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
+
+ def test_str_and_format_override_mixin(self):
+ class MixinWithStrFormatOverrides(float, Enum):
+ one = 1.0
+ two = 2.0
+ def __str__(self):
+ return 'Str!'
+ def __format__(self, spec):
+ return 'Format!'
+ self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
+ self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
+
+ def test_format_override_mixin(self):
+ class TestFloat(float, Enum):
+ one = 1.0
+ two = 2.0
+ def __format__(self, spec):
+ return 'TestFloat success!'
+ self.assertEqual(str(TestFloat.one), 'one')
+ self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
+
+ @unittest.skipIf(
+ python_version < (3, 12),
+ 'mixin-format is still using member.value',
+ )
+ def test_mixin_format_warning(self):
+ class Grades(int, Enum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ self.assertEqual(f'{self.Grades.B}', 'B')
+
+ @unittest.skipIf(
+ python_version >= (3, 12),
+ 'mixin-format now uses member instead of member.value',
+ )
+ def test_mixin_format_warning(self):
+ class Grades(int, Enum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(f'{Grades.B}', '4')
+
+ def assertFormatIsValue(self, spec, member):
+ if python_version < (3, 12) and (not spec or spec in ('{}','{:}')):
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(spec.format(member), spec.format(member.value))
+ else:
+ self.assertEqual(spec.format(member), spec.format(member.value))
+
+ def test_format_enum_date(self):
+ Holiday = self.Holiday
+ self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
+
+ def test_format_enum_float(self):
+ Konstants = self.Konstants
+ self.assertFormatIsValue('{}', Konstants.TAU)
+ self.assertFormatIsValue('{:}', Konstants.TAU)
+ self.assertFormatIsValue('{:20}', Konstants.TAU)
+ self.assertFormatIsValue('{:^20}', Konstants.TAU)
+ self.assertFormatIsValue('{:>20}', Konstants.TAU)
+ self.assertFormatIsValue('{:<20}', Konstants.TAU)
+ self.assertFormatIsValue('{:n}', Konstants.TAU)
+ self.assertFormatIsValue('{:5.2}', Konstants.TAU)
+ self.assertFormatIsValue('{:f}', Konstants.TAU)
+
+ def test_format_enum_int(self):
+ class Grades(int, Enum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ self.assertFormatIsValue('{}', Grades.C)
+ self.assertFormatIsValue('{:}', Grades.C)
+ self.assertFormatIsValue('{:20}', Grades.C)
+ self.assertFormatIsValue('{:^20}', Grades.C)
+ self.assertFormatIsValue('{:>20}', Grades.C)
+ self.assertFormatIsValue('{:<20}', Grades.C)
+ self.assertFormatIsValue('{:+}', Grades.C)
+ self.assertFormatIsValue('{:08X}', Grades.C)
+ self.assertFormatIsValue('{:b}', Grades.C)
+
+ def test_format_enum_str(self):
+ Directional = self.Directional
+ self.assertFormatIsValue('{}', Directional.WEST)
+ self.assertFormatIsValue('{:}', Directional.WEST)
+ self.assertFormatIsValue('{:20}', Directional.WEST)
+ self.assertFormatIsValue('{:^20}', Directional.WEST)
+ self.assertFormatIsValue('{:>20}', Directional.WEST)
+ self.assertFormatIsValue('{:<20}', Directional.WEST)
+
+ def test_object_str_override(self):
+ class Colors(Enum):
+ RED, GREEN, BLUE = 1, 2, 3
+ def __repr__(self):
+ return "test.%s" % (self._name_, )
+ __str__ = object.__str__
+ self.assertEqual(str(Colors.RED), 'test.RED')
+
+ def test_enum_str_override(self):
+ class MyStrEnum(Enum):
+ def __str__(self):
+ return 'MyStr'
+ class MyMethodEnum(Enum):
+ def hello(self):
+ return 'Hello! My name is %s' % self.name
+ class Test1Enum(MyMethodEnum, int, MyStrEnum):
+ One = 1
+ Two = 2
+ self.assertTrue(Test1Enum._member_type_ is int)
+ self.assertEqual(str(Test1Enum.One), 'MyStr')
+ self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
+ #
+ class Test2Enum(MyStrEnum, MyMethodEnum):
+ One = 1
+ Two = 2
+ self.assertEqual(str(Test2Enum.One), 'MyStr')
+ self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
+
def test_inherited_data_type(self):
class HexInt(int):
- __qualname__ = 'HexInt'
def __repr__(self):
return hex(self)
class MyEnum(HexInt, enum.Enum):
- __qualname__ = 'MyEnum'
A = 1
B = 2
C = 3
+ def __repr__(self):
+ return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
- globals()['HexInt'] = HexInt
- globals()['MyEnum'] = MyEnum
- test_pickle_dump_load(self.assertIs, MyEnum.A)
- test_pickle_dump_load(self.assertIs, MyEnum)
#
class SillyInt(HexInt):
__qualname__ = 'SillyInt'
@@ -976,7 +990,7 @@ class TestSpecial(unittest.TestCase):
test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
test_pickle_dump_load(self.assertIs, MyOtherEnum)
#
- # This did not work in 3.10, but does now with pickling by name
+ # This did not work in 3.9, but does now with pickling by name
class UnBrokenInt(int):
__qualname__ = 'UnBrokenInt'
def __new__(cls, value):
@@ -993,124 +1007,6 @@ class TestSpecial(unittest.TestCase):
test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
- def test_floatenum_fromhex(self):
- h = float.hex(FloatStooges.MOE.value)
- self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
- h = float.hex(FloatStooges.MOE.value + 0.01)
- with self.assertRaises(ValueError):
- FloatStooges.fromhex(h)
-
- def test_programmatic_function_type(self):
- MinorEnum = Enum('MinorEnum', 'june july august', type=int)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 1):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_string_with_start(self):
- MinorEnum = Enum('MinorEnum', 'june july august', start=10)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 10):
- e = MinorEnum(i)
- self.assertEqual(int(e.value), i)
- self.assertNotEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_type_with_start(self):
- MinorEnum = Enum('MinorEnum', 'june july august', type=int, start=30)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 30):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_string_list_with_start(self):
- MinorEnum = Enum('MinorEnum', ['june', 'july', 'august'], start=20)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 20):
- e = MinorEnum(i)
- self.assertEqual(int(e.value), i)
- self.assertNotEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_type_from_subclass(self):
- MinorEnum = IntEnum('MinorEnum', 'june july august')
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 1):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_type_from_subclass_with_start(self):
- MinorEnum = IntEnum('MinorEnum', 'june july august', start=40)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 40):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_intenum_from_bytes(self):
- self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
- with self.assertRaises(ValueError):
- IntStooges.from_bytes(b'\x00\x05', 'big')
-
- def test_reserved_sunder_error(self):
- with self.assertRaisesRegex(
- ValueError,
- '_sunder_ names, such as ._bad_., are reserved',
- ):
- class Bad(Enum):
- _bad_ = 1
-
def test_too_many_data_types(self):
with self.assertRaisesRegex(TypeError, 'too many data types'):
class Huh(str, int, Enum):
@@ -1126,6 +1022,122 @@ class TestSpecial(unittest.TestCase):
class Huh(MyStr, MyInt, Enum):
One = 1
+ def test_value_auto_assign(self):
+ class Some(Enum):
+ def __new__(cls, val):
+ return object.__new__(cls)
+ x = 1
+ y = 2
+
+ self.assertEqual(Some.x.value, 1)
+ self.assertEqual(Some.y.value, 2)
+
+ def test_hash(self):
+ Season = self.Season
+ dates = {}
+ dates[Season.WINTER] = '1225'
+ dates[Season.SPRING] = '0315'
+ dates[Season.SUMMER] = '0704'
+ dates[Season.AUTUMN] = '1031'
+ self.assertEqual(dates[Season.AUTUMN], '1031')
+
+ def test_intenum_from_scratch(self):
+ class phy(int, Enum):
+ pi = 3
+ tau = 2 * pi
+ self.assertTrue(phy.pi < phy.tau)
+
+ def test_intenum_inherited(self):
+ class IntEnum(int, Enum):
+ pass
+ class phy(IntEnum):
+ pi = 3
+ tau = 2 * pi
+ self.assertTrue(phy.pi < phy.tau)
+
+ def test_floatenum_from_scratch(self):
+ class phy(float, Enum):
+ pi = 3.1415926
+ tau = 2 * pi
+ self.assertTrue(phy.pi < phy.tau)
+
+ def test_floatenum_inherited(self):
+ class FloatEnum(float, Enum):
+ pass
+ class phy(FloatEnum):
+ pi = 3.1415926
+ tau = 2 * pi
+ self.assertTrue(phy.pi < phy.tau)
+
+ def test_strenum_from_scratch(self):
+ class phy(str, Enum):
+ pi = 'Pi'
+ tau = 'Tau'
+ self.assertTrue(phy.pi < phy.tau)
+
+ def test_strenum_inherited_methods(self):
+ class phy(StrEnum):
+ pi = 'Pi'
+ tau = 'Tau'
+ self.assertTrue(phy.pi < phy.tau)
+ self.assertEqual(phy.pi.upper(), 'PI')
+ self.assertEqual(phy.tau.count('a'), 1)
+
+ def test_intenum(self):
+ class WeekDay(IntEnum):
+ SUNDAY = 1
+ MONDAY = 2
+ TUESDAY = 3
+ WEDNESDAY = 4
+ THURSDAY = 5
+ FRIDAY = 6
+ SATURDAY = 7
+
+ self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
+ self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
+
+ lst = list(WeekDay)
+ self.assertEqual(len(lst), len(WeekDay))
+ self.assertEqual(len(WeekDay), 7)
+ target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
+ target = target.split()
+ for i, weekday in enumerate(target, 1):
+ e = WeekDay(i)
+ self.assertEqual(e, i)
+ self.assertEqual(int(e), i)
+ self.assertEqual(e.name, weekday)
+ self.assertIn(e, WeekDay)
+ self.assertEqual(lst.index(e)+1, i)
+ self.assertTrue(0 < e < 8)
+ self.assertIs(type(e), WeekDay)
+ self.assertIsInstance(e, int)
+ self.assertIsInstance(e, Enum)
+
+ def test_intenum_duplicates(self):
+ class WeekDay(IntEnum):
+ SUNDAY = 1
+ MONDAY = 2
+ TUESDAY = TEUSDAY = 3
+ WEDNESDAY = 4
+ THURSDAY = 5
+ FRIDAY = 6
+ SATURDAY = 7
+ self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
+ self.assertEqual(WeekDay(3).name, 'TUESDAY')
+ self.assertEqual([k for k,v in WeekDay.__members__.items()
+ if v.name != k], ['TEUSDAY', ])
+
+ def test_intenum_from_bytes(self):
+ self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
+ with self.assertRaises(ValueError):
+ IntStooges.from_bytes(b'\x00\x05', 'big')
+
+ def test_floatenum_fromhex(self):
+ h = float.hex(FloatStooges.MOE.value)
+ self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
+ h = float.hex(FloatStooges.MOE.value + 0.01)
+ with self.assertRaises(ValueError):
+ FloatStooges.fromhex(h)
def test_pickle_enum(self):
if isinstance(Stooges, Exception):
@@ -1157,7 +1169,12 @@ class TestSpecial(unittest.TestCase):
test_pickle_dump_load(self.assertIs, Question.who)
test_pickle_dump_load(self.assertIs, Question)
- def test_pickle_nested_class(self):
+ def test_enum_function_with_qualname(self):
+ if isinstance(Theory, Exception):
+ raise Theory
+ self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
+
+ def test_class_nested_enum_and_pickle_protocol_four(self):
# would normally just have this directly in the class namespace
class NestedEnum(Enum):
twigs = 'common'
@@ -1175,7 +1192,7 @@ class TestSpecial(unittest.TestCase):
for proto in range(HIGHEST_PROTOCOL):
self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
- def test_pickle_explodes(self):
+ def test_exploding_pickle(self):
BadPickle = Enum(
'BadPickle', 'dill sweet bread-n-butter', module=__name__)
globals()['BadPickle'] = BadPickle
@@ -1216,6 +1233,185 @@ class TestSpecial(unittest.TestCase):
[Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
)
+ def test_reversed_iteration_order(self):
+ self.assertEqual(
+ list(reversed(self.Season)),
+ [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
+ self.Season.SPRING]
+ )
+
+ def test_programmatic_function_string(self):
+ SummerMonth = Enum('SummerMonth', 'june july august')
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_string_with_start(self):
+ SummerMonth = Enum('SummerMonth', 'june july august', start=10)
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 10):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_string_list(self):
+ SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_string_list_with_start(self):
+ SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 20):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_iterable(self):
+ SummerMonth = Enum(
+ 'SummerMonth',
+ (('june', 1), ('july', 2), ('august', 3))
+ )
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_from_dict(self):
+ SummerMonth = Enum(
+ 'SummerMonth',
+ OrderedDict((('june', 1), ('july', 2), ('august', 3)))
+ )
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_type(self):
+ SummerMonth = Enum('SummerMonth', 'june july august', type=int)
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_type_with_start(self):
+ SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 30):
+ e = SummerMonth(i)
+ self.assertEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_type_from_subclass(self):
+ SummerMonth = IntEnum('SummerMonth', 'june july august')
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_type_from_subclass_with_start(self):
+ SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
+ lst = list(SummerMonth)
+ self.assertEqual(len(lst), len(SummerMonth))
+ self.assertEqual(len(SummerMonth), 3, SummerMonth)
+ self.assertEqual(
+ [SummerMonth.june, SummerMonth.july, SummerMonth.august],
+ lst,
+ )
+ for i, month in enumerate('june july august'.split(), 40):
+ e = SummerMonth(i)
+ self.assertEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
def test_subclassing(self):
if isinstance(Name, Exception):
raise Name
@@ -1229,18 +1425,15 @@ class TestSpecial(unittest.TestCase):
red = 1
green = 2
blue = 3
- #
with self.assertRaises(TypeError):
class MoreColor(Color):
cyan = 4
magenta = 5
yellow = 6
- #
- with self.assertRaisesRegex(TypeError, "<enum .EvenMoreColor.> cannot extend <enum .Color.>"):
+ with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
class EvenMoreColor(Color, IntEnum):
chartruese = 7
- #
- with self.assertRaisesRegex(TypeError, "<enum .Foo.> cannot extend <enum .Color.>"):
+ with self.assertRaisesRegex(TypeError, "Foo: cannot extend enumeration 'Color'"):
Color('Foo', ('pink', 'black'))
def test_exclude_methods(self):
@@ -1344,7 +1537,27 @@ class TestSpecial(unittest.TestCase):
with self.assertRaises(KeyError):
Color['chartreuse']
- # tests that need to be evalualted for moving
+ def test_new_repr(self):
+ class Color(Enum):
+ red = 1
+ green = 2
+ blue = 3
+ def __repr__(self):
+ return "don't you just love shades of %s?" % self.name
+ self.assertEqual(
+ repr(Color.blue),
+ "don't you just love shades of blue?",
+ )
+
+ def test_inherited_repr(self):
+ class MyEnum(Enum):
+ def __repr__(self):
+ return "My name is %s." % self.name
+ class MyIntEnum(int, MyEnum):
+ this = 1
+ that = 2
+ theother = 3
+ self.assertEqual(repr(MyIntEnum.that), "My name is that.")
def test_multiple_mixin_mro(self):
class auto_enum(type(Enum)):
@@ -1397,7 +1610,7 @@ class TestSpecial(unittest.TestCase):
return self
def __getnewargs__(self):
return self._args
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1457,7 +1670,7 @@ class TestSpecial(unittest.TestCase):
return self
def __getnewargs_ex__(self):
return self._args, {}
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1517,7 +1730,7 @@ class TestSpecial(unittest.TestCase):
return self
def __reduce__(self):
return self.__class__, self._args
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1577,7 +1790,7 @@ class TestSpecial(unittest.TestCase):
return self
def __reduce_ex__(self, proto):
return self.__class__, self._args
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1634,7 +1847,7 @@ class TestSpecial(unittest.TestCase):
self._intname = name
self._args = _args
return self
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1689,7 +1902,7 @@ class TestSpecial(unittest.TestCase):
self._intname = name
self._args = _args
return self
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1878,7 +2091,6 @@ class TestSpecial(unittest.TestCase):
class Test(Base):
test = 1
self.assertEqual(Test.test.test, 'dynamic')
- self.assertEqual(Test.test.value, 1)
class Base2(Enum):
@enum.property
def flash(self):
@@ -1886,7 +2098,6 @@ class TestSpecial(unittest.TestCase):
class Test(Base2):
flash = 1
self.assertEqual(Test.flash.flash, 'flashy dynamic')
- self.assertEqual(Test.flash.value, 1)
def test_no_duplicates(self):
class UniqueEnum(Enum):
@@ -1923,7 +2134,7 @@ class TestSpecial(unittest.TestCase):
def __init__(self, mass, radius):
self.mass = mass # in kilograms
self.radius = radius # in meters
- @enum.property
+ @property
def surface_gravity(self):
# universal gravitational constant (m3 kg-1 s-2)
G = 6.67300E-11
@@ -1993,7 +2204,90 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(LabelledList.unprocessed, 1)
self.assertEqual(LabelledList(1), LabelledList.unprocessed)
- def test_default_missing_no_chained_exception(self):
+ def test_auto_number(self):
+ class Color(Enum):
+ red = auto()
+ blue = auto()
+ green = auto()
+
+ self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+ self.assertEqual(Color.red.value, 1)
+ self.assertEqual(Color.blue.value, 2)
+ self.assertEqual(Color.green.value, 3)
+
+ def test_auto_name(self):
+ class Color(Enum):
+ def _generate_next_value_(name, start, count, last):
+ return name
+ red = auto()
+ blue = auto()
+ green = auto()
+
+ self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+ self.assertEqual(Color.red.value, 'red')
+ self.assertEqual(Color.blue.value, 'blue')
+ self.assertEqual(Color.green.value, 'green')
+
+ def test_auto_name_inherit(self):
+ class AutoNameEnum(Enum):
+ def _generate_next_value_(name, start, count, last):
+ return name
+ class Color(AutoNameEnum):
+ red = auto()
+ blue = auto()
+ green = auto()
+
+ self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+ self.assertEqual(Color.red.value, 'red')
+ self.assertEqual(Color.blue.value, 'blue')
+ self.assertEqual(Color.green.value, 'green')
+
+ def test_auto_garbage(self):
+ class Color(Enum):
+ red = 'red'
+ blue = auto()
+ self.assertEqual(Color.blue.value, 1)
+
+ def test_auto_garbage_corrected(self):
+ class Color(Enum):
+ red = 'red'
+ blue = 2
+ green = auto()
+
+ self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
+ self.assertEqual(Color.red.value, 'red')
+ self.assertEqual(Color.blue.value, 2)
+ self.assertEqual(Color.green.value, 3)
+
+ def test_auto_order(self):
+ with self.assertRaises(TypeError):
+ class Color(Enum):
+ red = auto()
+ green = auto()
+ blue = auto()
+ def _generate_next_value_(name, start, count, last):
+ return name
+
+ def test_auto_order_wierd(self):
+ weird_auto = auto()
+ weird_auto.value = 'pathological case'
+ class Color(Enum):
+ red = weird_auto
+ def _generate_next_value_(name, start, count, last):
+ return name
+ blue = auto()
+ self.assertEqual(list(Color), [Color.red, Color.blue])
+ self.assertEqual(Color.red.value, 'pathological case')
+ self.assertEqual(Color.blue.value, 'blue')
+
+ def test_duplicate_auto(self):
+ class Dupes(Enum):
+ first = primero = auto()
+ second = auto()
+ third = auto()
+ self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
+
+ def test_default_missing(self):
class Color(Enum):
RED = 1
GREEN = 2
@@ -2005,7 +2299,7 @@ class TestSpecial(unittest.TestCase):
else:
raise Exception('Exception not raised.')
- def test_missing_override(self):
+ def test_missing(self):
class Color(Enum):
red = 1
green = 2
@@ -2069,9 +2363,9 @@ class TestSpecial(unittest.TestCase):
class_1_ref = weakref.ref(Class1())
class_2_ref = weakref.ref(Class2())
#
- # The exception raised by Enum used to create a reference loop and thus
- # Class2 instances would stick around until the next garbage collection
- # cycle, unlike Class1. Verify Class2 no longer does this.
+ # The exception raised by Enum creates a reference loop and thus
+ # Class2 instances will stick around until the next garbage collection
+ # cycle, unlike Class1.
gc.collect() # For PyPy or other GCs.
self.assertIs(class_1_ref(), None)
self.assertIs(class_2_ref(), None)
@@ -2102,12 +2396,11 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 3)
self.assertEqual(Color.MAX, 3)
- self.assertEqual(str(Color.BLUE), 'Color.BLUE')
+ self.assertEqual(str(Color.BLUE), 'BLUE')
class Color(MaxMixin, StrMixin, Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 3)
@@ -2117,7 +2410,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 3)
@@ -2127,7 +2419,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(CoolColor.RED.value, 1)
self.assertEqual(CoolColor.GREEN.value, 2)
self.assertEqual(CoolColor.BLUE.value, 3)
@@ -2137,7 +2428,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(CoolerColor.RED.value, 1)
self.assertEqual(CoolerColor.GREEN.value, 2)
self.assertEqual(CoolerColor.BLUE.value, 3)
@@ -2148,7 +2438,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(CoolestColor.RED.value, 1)
self.assertEqual(CoolestColor.GREEN.value, 2)
self.assertEqual(CoolestColor.BLUE.value, 3)
@@ -2159,7 +2448,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(ConfusedColor.RED.value, 1)
self.assertEqual(ConfusedColor.GREEN.value, 2)
self.assertEqual(ConfusedColor.BLUE.value, 3)
@@ -2170,7 +2458,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(ReformedColor.RED.value, 1)
self.assertEqual(ReformedColor.GREEN.value, 2)
self.assertEqual(ReformedColor.BLUE.value, 3)
@@ -2203,12 +2490,11 @@ class TestSpecial(unittest.TestCase):
return hex(self)
class MyIntEnum(HexMixin, MyInt, enum.Enum):
- __repr__ = HexMixin.__repr__
+ pass
class Foo(MyIntEnum):
TEST = 1
self.assertTrue(isinstance(Foo.TEST, MyInt))
- self.assertEqual(Foo._member_type_, MyInt)
self.assertEqual(repr(Foo.TEST), "0x1")
class Fee(MyIntEnum):
@@ -2220,7 +2506,7 @@ class TestSpecial(unittest.TestCase):
return member
self.assertEqual(Fee.TEST, 2)
- def test_multiple_mixin_with_common_data_type(self):
+ def test_miltuple_mixin_with_common_data_type(self):
class CaseInsensitiveStrEnum(str, Enum):
@classmethod
def _missing_(cls, value):
@@ -2240,7 +2526,7 @@ class TestSpecial(unittest.TestCase):
unknown._value_ = value
cls._member_map_[value] = unknown
return unknown
- @enum.property
+ @property
def valid(self):
return self._valid
#
@@ -2284,7 +2570,7 @@ class TestSpecial(unittest.TestCase):
self.assertEqual('{}'.format(GoodStrEnum.one), '1')
self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
- self.assertEqual(repr(GoodStrEnum.one), "<GoodStrEnum.one: '1'>")
+ self.assertEqual(repr(GoodStrEnum.one), 'GoodStrEnum.one')
#
class DumbMixin:
def __str__(self):
@@ -2293,7 +2579,6 @@ class TestSpecial(unittest.TestCase):
five = '5'
six = '6'
seven = '7'
- __str__ = DumbMixin.__str__ # needed as of 3.11
self.assertEqual(DumbStrEnum.seven, '7')
self.assertEqual(str(DumbStrEnum.seven), "don't do this")
#
@@ -2335,6 +2620,74 @@ class TestSpecial(unittest.TestCase):
one = '1'
two = b'2', 'ascii', 9
+ @unittest.skipIf(
+ python_version >= (3, 12),
+ 'mixin-format now uses member instead of member.value',
+ )
+ def test_custom_strenum_with_warning(self):
+ class CustomStrEnum(str, Enum):
+ pass
+ class OkayEnum(CustomStrEnum):
+ one = '1'
+ two = '2'
+ three = b'3', 'ascii'
+ four = b'4', 'latin1', 'strict'
+ self.assertEqual(OkayEnum.one, '1')
+ self.assertEqual(str(OkayEnum.one), 'one')
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual('{}'.format(OkayEnum.one), '1')
+ self.assertEqual(OkayEnum.one, '{}'.format(OkayEnum.one))
+ self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
+ #
+ class DumbMixin:
+ def __str__(self):
+ return "don't do this"
+ class DumbStrEnum(DumbMixin, CustomStrEnum):
+ five = '5'
+ six = '6'
+ seven = '7'
+ self.assertEqual(DumbStrEnum.seven, '7')
+ self.assertEqual(str(DumbStrEnum.seven), "don't do this")
+ #
+ class EnumMixin(Enum):
+ def hello(self):
+ print('hello from %s' % (self, ))
+ class HelloEnum(EnumMixin, CustomStrEnum):
+ eight = '8'
+ self.assertEqual(HelloEnum.eight, '8')
+ self.assertEqual(str(HelloEnum.eight), 'eight')
+ #
+ class GoodbyeMixin:
+ def goodbye(self):
+ print('%s wishes you a fond farewell')
+ class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
+ nine = '9'
+ self.assertEqual(GoodbyeEnum.nine, '9')
+ self.assertEqual(str(GoodbyeEnum.nine), 'nine')
+ #
+ class FirstFailedStrEnum(CustomStrEnum):
+ one = 1 # this will become '1'
+ two = '2'
+ class SecondFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = 2, # this will become '2'
+ three = '3'
+ class ThirdFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = 2 # this will become '2'
+ with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
+ class ThirdFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = b'2', sys.getdefaultencoding
+ with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
+ class ThirdFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = b'2', 'ascii', 9
+
+ @unittest.skipIf(
+ python_version < (3, 12),
+ 'mixin-format currently uses member.value',
+ )
def test_custom_strenum(self):
class CustomStrEnum(str, Enum):
pass
@@ -2344,9 +2697,9 @@ class TestSpecial(unittest.TestCase):
three = b'3', 'ascii'
four = b'4', 'latin1', 'strict'
self.assertEqual(OkayEnum.one, '1')
- self.assertEqual(str(OkayEnum.one), 'OkayEnum.one')
- self.assertEqual('{}'.format(OkayEnum.one), 'OkayEnum.one')
- self.assertEqual(repr(OkayEnum.one), "<OkayEnum.one: '1'>")
+ self.assertEqual(str(OkayEnum.one), 'one')
+ self.assertEqual('{}'.format(OkayEnum.one), 'one')
+ self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
#
class DumbMixin:
def __str__(self):
@@ -2355,7 +2708,6 @@ class TestSpecial(unittest.TestCase):
five = '5'
six = '6'
seven = '7'
- __str__ = DumbMixin.__str__ # needed as of 3.11
self.assertEqual(DumbStrEnum.seven, '7')
self.assertEqual(str(DumbStrEnum.seven), "don't do this")
#
@@ -2365,7 +2717,7 @@ class TestSpecial(unittest.TestCase):
class HelloEnum(EnumMixin, CustomStrEnum):
eight = '8'
self.assertEqual(HelloEnum.eight, '8')
- self.assertEqual(str(HelloEnum.eight), 'HelloEnum.eight')
+ self.assertEqual(str(HelloEnum.eight), 'eight')
#
class GoodbyeMixin:
def goodbye(self):
@@ -2373,7 +2725,7 @@ class TestSpecial(unittest.TestCase):
class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
nine = '9'
self.assertEqual(GoodbyeEnum.nine, '9')
- self.assertEqual(str(GoodbyeEnum.nine), 'GoodbyeEnum.nine')
+ self.assertEqual(str(GoodbyeEnum.nine), 'nine')
#
class FirstFailedStrEnum(CustomStrEnum):
one = 1 # this will become '1'
@@ -2419,6 +2771,21 @@ class TestSpecial(unittest.TestCase):
code = 'An$(5,1)', 2
description = 'Bn$', 3
+ @unittest.skipUnless(
+ python_version == (3, 9),
+ 'private variables are now normal attributes',
+ )
+ def test_warning_for_private_variables(self):
+ with self.assertWarns(DeprecationWarning):
+ class Private(Enum):
+ __corporal = 'Radar'
+ self.assertEqual(Private._Private__corporal.value, 'Radar')
+ try:
+ with self.assertWarns(DeprecationWarning):
+ class Private(Enum):
+ __major_ = 'Hoolihan'
+ except ValueError:
+ pass
def test_private_variable_is_normal_attribute(self):
class Private(Enum):
@@ -2427,13 +2794,35 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(Private._Private__corporal, 'Radar')
self.assertEqual(Private._Private__major_, 'Hoolihan')
+ @unittest.skipUnless(
+ python_version < (3, 12),
+ 'member-member access now raises an exception',
+ )
+ def test_warning_for_member_from_member_access(self):
+ with self.assertWarns(DeprecationWarning):
+ class Di(Enum):
+ YES = 1
+ NO = 0
+ nope = Di.YES.NO
+ self.assertIs(Di.NO, nope)
+
+ @unittest.skipUnless(
+ python_version >= (3, 12),
+ 'member-member access currently issues a warning',
+ )
def test_exception_for_member_from_member_access(self):
- with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
+ with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
class Di(Enum):
YES = 1
NO = 0
nope = Di.YES.NO
+ def test_strenum_auto(self):
+ class Strings(StrEnum):
+ ONE = auto()
+ TWO = auto()
+ self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
+
def test_dynamic_members_with_static_methods(self):
#
@@ -2450,7 +2839,7 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(Foo.FOO_CAT.value, 'aloof')
self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
#
- with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as 'aloof'"):
+ with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
class FooBar(Enum):
vars().update({
k: v
@@ -2462,42 +2851,8 @@ class TestSpecial(unittest.TestCase):
def upper(self):
return self.value.upper()
- def test_repr_with_dataclass(self):
- "ensure dataclass-mixin has correct repr()"
- from dataclasses import dataclass
- @dataclass
- class Foo:
- __qualname__ = 'Foo'
- a: int = 0
- class Entries(Foo, Enum):
- ENTRY1 = Foo(1)
- self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
-
- def test_repr_with_non_data_type_mixin(self):
- # non-data_type is a mixin that doesn't define __new__
- class Foo:
- def __init__(self, a):
- self.a = a
- def __repr__(self):
- return f'Foo(a={self.a!r})'
- class Entries(Foo, Enum):
- ENTRY1 = Foo(1)
-
- self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
-
- def test_value_backup_assign(self):
- # check that enum will add missing values when custom __new__ does not
- class Some(Enum):
- def __new__(cls, val):
- return object.__new__(cls)
- x = 1
- y = 2
- self.assertEqual(Some.x.value, 1)
- self.assertEqual(Some.y.value, 2)
-
class TestOrder(unittest.TestCase):
- "test usage of the `_order_` attribute"
def test_same_members(self):
class Color(Enum):
@@ -2559,7 +2914,7 @@ class TestOrder(unittest.TestCase):
verde = green
-class OldTestFlag(unittest.TestCase):
+class TestFlag(unittest.TestCase):
"""Tests of the Flags."""
class Perm(Flag):
@@ -2582,6 +2937,65 @@ class OldTestFlag(unittest.TestCase):
WHITE = RED|GREEN|BLUE
BLANCO = RED|GREEN|BLUE
+ def test_str(self):
+ Perm = self.Perm
+ self.assertEqual(str(Perm.R), 'R')
+ self.assertEqual(str(Perm.W), 'W')
+ self.assertEqual(str(Perm.X), 'X')
+ self.assertEqual(str(Perm.R | Perm.W), 'R|W')
+ self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
+ self.assertEqual(str(Perm(0)), 'Perm(0)')
+ self.assertEqual(str(~Perm.R), 'W|X')
+ self.assertEqual(str(~Perm.W), 'R|X')
+ self.assertEqual(str(~Perm.X), 'R|W')
+ self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
+ self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
+ self.assertEqual(str(Perm(~0)), 'R|W|X')
+
+ Open = self.Open
+ self.assertEqual(str(Open.RO), 'RO')
+ self.assertEqual(str(Open.WO), 'WO')
+ self.assertEqual(str(Open.AC), 'AC')
+ self.assertEqual(str(Open.RO | Open.CE), 'CE')
+ self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
+ self.assertEqual(str(~Open.RO), 'WO|RW|CE')
+ self.assertEqual(str(~Open.WO), 'RW|CE')
+ self.assertEqual(str(~Open.AC), 'CE')
+ self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
+ self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
+
+ def test_repr(self):
+ Perm = self.Perm
+ self.assertEqual(repr(Perm.R), 'Perm.R')
+ self.assertEqual(repr(Perm.W), 'Perm.W')
+ self.assertEqual(repr(Perm.X), 'Perm.X')
+ self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
+ self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
+ self.assertEqual(repr(Perm(0)), '0x0')
+ self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
+ self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
+ self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
+ self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
+ self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
+ self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
+
+ Open = self.Open
+ self.assertEqual(repr(Open.RO), 'Open.RO')
+ self.assertEqual(repr(Open.WO), 'Open.WO')
+ self.assertEqual(repr(Open.AC), 'Open.AC')
+ self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
+ self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
+ self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.AC), 'Open.CE')
+ self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
+ self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
+
+ def test_format(self):
+ Perm = self.Perm
+ self.assertEqual(format(Perm.R, ''), 'R')
+ self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
+
def test_or(self):
Perm = self.Perm
for i in Perm:
@@ -2674,7 +3088,7 @@ class OldTestFlag(unittest.TestCase):
c = 4
d = 6
#
- self.assertRaisesRegex(ValueError, 'invalid value 7', Iron, 7)
+ self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
#
self.assertIs(Water(7), Water.ONE|Water.TWO)
self.assertIs(Water(~9), Water.TWO)
@@ -2883,7 +3297,7 @@ class OldTestFlag(unittest.TestCase):
self.assertEqual(Color.green.value, 4)
def test_auto_number_garbage(self):
- with self.assertRaisesRegex(TypeError, 'invalid flag value .not an int.'):
+ with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
class Color(Flag):
red = 'not an int'
blue = auto()
@@ -2918,12 +3332,11 @@ class OldTestFlag(unittest.TestCase):
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
self.assertEqual(Color.ALL.value, 7)
- self.assertEqual(str(Color.BLUE), 'Color.BLUE')
+ self.assertEqual(str(Color.BLUE), 'BLUE')
class Color(AllMixin, StrMixin, Flag):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -2933,7 +3346,6 @@ class OldTestFlag(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -3014,8 +3426,21 @@ class OldTestFlag(unittest.TestCase):
self.assertFalse(NeverEnum.__dict__.get('_test1', False))
self.assertFalse(NeverEnum.__dict__.get('_test2', False))
+ def test_default_missing(self):
+ with self.assertRaisesRegex(
+ ValueError,
+ "'RED' is not a valid TestFlag.Color",
+ ) as ctx:
+ self.Color('RED')
+ self.assertIs(ctx.exception.__context__, None)
+
+ P = Flag('P', 'X Y')
+ with self.assertRaisesRegex(ValueError, "'X' is not a valid P") as ctx:
+ P('X')
+ self.assertIs(ctx.exception.__context__, None)
+
-class OldTestIntFlag(unittest.TestCase):
+class TestIntFlag(unittest.TestCase):
"""Tests of the IntFlags."""
class Perm(IntFlag):
@@ -3060,6 +3485,73 @@ class OldTestIntFlag(unittest.TestCase):
self.assertTrue(isinstance(Open.WO | Open.RW, Open))
self.assertEqual(Open.WO | Open.RW, 3)
+
+ def test_str(self):
+ Perm = self.Perm
+ self.assertEqual(str(Perm.R), 'R')
+ self.assertEqual(str(Perm.W), 'W')
+ self.assertEqual(str(Perm.X), 'X')
+ self.assertEqual(str(Perm.R | Perm.W), 'R|W')
+ self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
+ self.assertEqual(str(Perm.R | 8), '12')
+ self.assertEqual(str(Perm(0)), 'Perm(0)')
+ self.assertEqual(str(Perm(8)), '8')
+ self.assertEqual(str(~Perm.R), 'W|X')
+ self.assertEqual(str(~Perm.W), 'R|X')
+ self.assertEqual(str(~Perm.X), 'R|W')
+ self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
+ self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
+ self.assertEqual(str(~(Perm.R | 8)), '-13')
+ self.assertEqual(str(Perm(~0)), 'R|W|X')
+ self.assertEqual(str(Perm(~8)), '-9')
+
+ Open = self.Open
+ self.assertEqual(str(Open.RO), 'RO')
+ self.assertEqual(str(Open.WO), 'WO')
+ self.assertEqual(str(Open.AC), 'AC')
+ self.assertEqual(str(Open.RO | Open.CE), 'CE')
+ self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
+ self.assertEqual(str(Open(4)), '4')
+ self.assertEqual(str(~Open.RO), 'WO|RW|CE')
+ self.assertEqual(str(~Open.WO), 'RW|CE')
+ self.assertEqual(str(~Open.AC), 'CE')
+ self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
+ self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
+ self.assertEqual(str(Open(~4)), '-5')
+
+ def test_repr(self):
+ Perm = self.Perm
+ self.assertEqual(repr(Perm.R), 'Perm.R')
+ self.assertEqual(repr(Perm.W), 'Perm.W')
+ self.assertEqual(repr(Perm.X), 'Perm.X')
+ self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
+ self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
+ self.assertEqual(repr(Perm.R | 8), '12')
+ self.assertEqual(repr(Perm(0)), '0x0')
+ self.assertEqual(repr(Perm(8)), '8')
+ self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
+ self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
+ self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
+ self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
+ self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
+ self.assertEqual(repr(~(Perm.R | 8)), '-13')
+ self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
+ self.assertEqual(repr(Perm(~8)), '-9')
+
+ Open = self.Open
+ self.assertEqual(repr(Open.RO), 'Open.RO')
+ self.assertEqual(repr(Open.WO), 'Open.WO')
+ self.assertEqual(repr(Open.AC), 'Open.AC')
+ self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
+ self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
+ self.assertEqual(repr(Open(4)), '4')
+ self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.AC), 'Open.CE')
+ self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
+ self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
+ self.assertEqual(repr(Open(~4)), '-5')
+
def test_global_repr_keep(self):
self.assertEqual(
repr(HeadlightsK(0)),
@@ -3067,11 +3559,11 @@ class OldTestIntFlag(unittest.TestCase):
)
self.assertEqual(
repr(HeadlightsK(2**0 + 2**2 + 2**3)),
- '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|8' % {'m': SHORT_MODULE},
+ '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE},
)
self.assertEqual(
repr(HeadlightsK(2**3)),
- '%(m)s.HeadlightsK(8)' % {'m': SHORT_MODULE},
+ '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
)
def test_global_repr_conform1(self):
@@ -3213,7 +3705,7 @@ class OldTestIntFlag(unittest.TestCase):
c = 4
d = 6
#
- self.assertRaisesRegex(ValueError, 'invalid value 5', Iron, 5)
+ self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
#
self.assertIs(Water(7), Water.ONE|Water.TWO)
self.assertIs(Water(~9), Water.TWO)
@@ -3450,12 +3942,11 @@ class OldTestIntFlag(unittest.TestCase):
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
self.assertEqual(Color.ALL.value, 7)
- self.assertEqual(str(Color.BLUE), '4')
+ self.assertEqual(str(Color.BLUE), 'BLUE')
class Color(AllMixin, StrMixin, IntFlag):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -3465,7 +3956,6 @@ class OldTestIntFlag(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -3510,6 +4000,19 @@ class OldTestIntFlag(unittest.TestCase):
'at least one thread failed while creating composite members')
self.assertEqual(256, len(seen), 'too many composite members created')
+ def test_default_missing(self):
+ with self.assertRaisesRegex(
+ ValueError,
+ "'RED' is not a valid TestIntFlag.Color",
+ ) as ctx:
+ self.Color('RED')
+ self.assertIs(ctx.exception.__context__, None)
+
+ P = IntFlag('P', 'X Y')
+ with self.assertRaisesRegex(ValueError, "'X' is not a valid P") as ctx:
+ P('X')
+ self.assertIs(ctx.exception.__context__, None)
+
class TestEmptyAndNonLatinStrings(unittest.TestCase):
@@ -3726,89 +4229,6 @@ class TestHelpers(unittest.TestCase):
for name in self.sunder_names + self.dunder_names + self.random_names:
self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
- def test_auto_number(self):
- class Color(Enum):
- red = auto()
- blue = auto()
- green = auto()
-
- self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
- self.assertEqual(Color.red.value, 1)
- self.assertEqual(Color.blue.value, 2)
- self.assertEqual(Color.green.value, 3)
-
- def test_auto_name(self):
- class Color(Enum):
- def _generate_next_value_(name, start, count, last):
- return name
- red = auto()
- blue = auto()
- green = auto()
-
- self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
- self.assertEqual(Color.red.value, 'red')
- self.assertEqual(Color.blue.value, 'blue')
- self.assertEqual(Color.green.value, 'green')
-
- def test_auto_name_inherit(self):
- class AutoNameEnum(Enum):
- def _generate_next_value_(name, start, count, last):
- return name
- class Color(AutoNameEnum):
- red = auto()
- blue = auto()
- green = auto()
-
- self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
- self.assertEqual(Color.red.value, 'red')
- self.assertEqual(Color.blue.value, 'blue')
- self.assertEqual(Color.green.value, 'green')
-
- def test_auto_garbage(self):
- class Color(Enum):
- red = 'red'
- blue = auto()
- self.assertEqual(Color.blue.value, 1)
-
- def test_auto_garbage_corrected(self):
- class Color(Enum):
- red = 'red'
- blue = 2
- green = auto()
-
- self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
- self.assertEqual(Color.red.value, 'red')
- self.assertEqual(Color.blue.value, 2)
- self.assertEqual(Color.green.value, 3)
-
- def test_auto_order(self):
- with self.assertRaises(TypeError):
- class Color(Enum):
- red = auto()
- green = auto()
- blue = auto()
- def _generate_next_value_(name, start, count, last):
- return name
-
- def test_auto_order_wierd(self):
- weird_auto = auto()
- weird_auto.value = 'pathological case'
- class Color(Enum):
- red = weird_auto
- def _generate_next_value_(name, start, count, last):
- return name
- blue = auto()
- self.assertEqual(list(Color), [Color.red, Color.blue])
- self.assertEqual(Color.red.value, 'pathological case')
- self.assertEqual(Color.blue.value, 'blue')
-
- def test_duplicate_auto(self):
- class Dupes(Enum):
- first = primero = auto()
- second = auto()
- third = auto()
- self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
-
class TestEnumTypeSubclassing(unittest.TestCase):
pass
@@ -3818,35 +4238,7 @@ Help on class Color in module %s:
class Color(enum.Enum)
| Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
|\x20\x20
- | A collection of name/value pairs.
- |\x20\x20
- | Access them by:
- |\x20\x20
- | - attribute access::
- |\x20\x20
- | >>> Color.CYAN
- | <Color.CYAN: 1>
- |\x20\x20
- | - value lookup:
- |\x20\x20
- | >>> Color(1)
- | <Color.CYAN: 1>
- |\x20\x20
- | - name lookup:
- |\x20\x20
- | >>> Color['CYAN']
- | <Color.CYAN: 1>
- |\x20\x20
- | Enumerations can be iterated over, and know how many members they have:
- |\x20\x20
- | >>> len(Color)
- | 3
- |\x20\x20
- | >>> list(Color)
- | [<Color.CYAN: 1>, <Color.MAGENTA: 2>, <Color.YELLOW: 3>]
- |\x20\x20
- | Methods can be added to enumerations, and members can have their own
- | attributes -- see the documentation for details.
+ | An enumeration.
|\x20\x20
| Method resolution order:
| Color
@@ -3855,11 +4247,11 @@ class Color(enum.Enum)
|\x20\x20
| Data and other attributes defined here:
|\x20\x20
- | CYAN = <Color.CYAN: 1>
+ | blue = Color.blue
|\x20\x20
- | MAGENTA = <Color.MAGENTA: 2>
+ | green = Color.green
|\x20\x20
- | YELLOW = <Color.YELLOW: 3>
+ | red = Color.red
|\x20\x20
| ----------------------------------------------------------------------
| Data descriptors inherited from enum.Enum:
@@ -3871,25 +4263,6 @@ class Color(enum.Enum)
| The value of the Enum member.
|\x20\x20
| ----------------------------------------------------------------------
- | Methods inherited from enum.EnumType:
- |\x20\x20
- | __contains__(member) from enum.EnumType
- | Return True if member is a member of this enum
- | raises TypeError if member is not an enum member
- |\x20\x20\x20\x20\x20\x20
- | note: in 3.12 TypeError will no longer be raised, and True will also be
- | returned if member is the value of a member in this enum
- |\x20\x20
- | __getitem__(name) from enum.EnumType
- | Return the member matching `name`.
- |\x20\x20
- | __iter__() from enum.EnumType
- | Return members in definition order.
- |\x20\x20
- | __len__() from enum.EnumType
- | Return the number of members (no aliases)
- |\x20\x20
- | ----------------------------------------------------------------------
| Readonly properties inherited from enum.EnumType:
|\x20\x20
| __members__
@@ -3911,11 +4284,11 @@ class Color(enum.Enum)
|\x20\x20
| Data and other attributes defined here:
|\x20\x20
- | YELLOW = <Color.YELLOW: 3>
+ | blue = Color.blue
|\x20\x20
- | MAGENTA = <Color.MAGENTA: 2>
+ | green = Color.green
|\x20\x20
- | CYAN = <Color.CYAN: 1>
+ | red = Color.red
|\x20\x20
| ----------------------------------------------------------------------
| Data descriptors inherited from enum.Enum:
@@ -3934,9 +4307,9 @@ class TestStdLib(unittest.TestCase):
maxDiff = None
class Color(Enum):
- CYAN = 1
- MAGENTA = 2
- YELLOW = 3
+ red = 1
+ green = 2
+ blue = 3
def test_pydoc(self):
# indirectly test __objclass__
@@ -3948,34 +4321,24 @@ class TestStdLib(unittest.TestCase):
helper = pydoc.Helper(output=output)
helper(self.Color)
result = output.getvalue().strip()
- self.assertEqual(result, expected_text, result)
+ self.assertEqual(result, expected_text)
def test_inspect_getmembers(self):
values = dict((
('__class__', EnumType),
- ('__doc__', '...'),
+ ('__doc__', 'An enumeration.'),
('__members__', self.Color.__members__),
('__module__', __name__),
- ('YELLOW', self.Color.YELLOW),
- ('MAGENTA', self.Color.MAGENTA),
- ('CYAN', self.Color.CYAN),
+ ('blue', self.Color.blue),
+ ('green', self.Color.green),
('name', Enum.__dict__['name']),
+ ('red', self.Color.red),
('value', Enum.__dict__['value']),
- ('__len__', self.Color.__len__),
- ('__contains__', self.Color.__contains__),
- ('__name__', 'Color'),
- ('__getitem__', self.Color.__getitem__),
- ('__qualname__', 'TestStdLib.Color'),
- ('__init_subclass__', getattr(self.Color, '__init_subclass__')),
- ('__iter__', self.Color.__iter__),
))
result = dict(inspect.getmembers(self.Color))
self.assertEqual(set(values.keys()), set(result.keys()))
failed = False
for k in values.keys():
- if k == '__doc__':
- # __doc__ is huge, not comparing
- continue
if result[k] != values[k]:
print()
print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
@@ -3990,42 +4353,23 @@ class TestStdLib(unittest.TestCase):
values = [
Attribute(name='__class__', kind='data',
defining_class=object, object=EnumType),
- Attribute(name='__contains__', kind='method',
- defining_class=EnumType, object=self.Color.__contains__),
Attribute(name='__doc__', kind='data',
- defining_class=self.Color, object='...'),
- Attribute(name='__getitem__', kind='method',
- defining_class=EnumType, object=self.Color.__getitem__),
- Attribute(name='__iter__', kind='method',
- defining_class=EnumType, object=self.Color.__iter__),
- Attribute(name='__init_subclass__', kind='class method',
- defining_class=object, object=getattr(self.Color, '__init_subclass__')),
- Attribute(name='__len__', kind='method',
- defining_class=EnumType, object=self.Color.__len__),
+ defining_class=self.Color, object='An enumeration.'),
Attribute(name='__members__', kind='property',
defining_class=EnumType, object=EnumType.__members__),
Attribute(name='__module__', kind='data',
defining_class=self.Color, object=__name__),
- Attribute(name='__name__', kind='data',
- defining_class=self.Color, object='Color'),
- Attribute(name='__qualname__', kind='data',
- defining_class=self.Color, object='TestStdLib.Color'),
- Attribute(name='YELLOW', kind='data',
- defining_class=self.Color, object=self.Color.YELLOW),
- Attribute(name='MAGENTA', kind='data',
- defining_class=self.Color, object=self.Color.MAGENTA),
- Attribute(name='CYAN', kind='data',
- defining_class=self.Color, object=self.Color.CYAN),
+ Attribute(name='blue', kind='data',
+ defining_class=self.Color, object=self.Color.blue),
+ Attribute(name='green', kind='data',
+ defining_class=self.Color, object=self.Color.green),
+ Attribute(name='red', kind='data',
+ defining_class=self.Color, object=self.Color.red),
Attribute(name='name', kind='data',
defining_class=Enum, object=Enum.__dict__['name']),
Attribute(name='value', kind='data',
defining_class=Enum, object=Enum.__dict__['value']),
]
- for v in values:
- try:
- v.name
- except AttributeError:
- print(v)
values.sort(key=lambda item: item.name)
result = list(inspect.classify_class_attrs(self.Color))
result.sort(key=lambda item: item.name)
@@ -4035,15 +4379,7 @@ class TestStdLib(unittest.TestCase):
)
failed = False
for v, r in zip(values, result):
- if r.name in ('__init_subclass__', '__doc__'):
- # not sure how to make the __init_subclass_ Attributes match
- # so as long as there is one, call it good
- # __doc__ is too big to check exactly, so treat the same as __init_subclass__
- for name in ('name','kind','defining_class'):
- if getattr(v, name) != getattr(r, name):
- print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
- failed = True
- elif r != v:
+ if r != v:
print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
failed = True
if failed:
@@ -4052,15 +4388,15 @@ class TestStdLib(unittest.TestCase):
def test_test_simple_enum(self):
@_simple_enum(Enum)
class SimpleColor:
- CYAN = 1
- MAGENTA = 2
- YELLOW = 3
+ RED = 1
+ GREEN = 2
+ BLUE = 3
class CheckedColor(Enum):
- CYAN = 1
- MAGENTA = 2
- YELLOW = 3
+ RED = 1
+ GREEN = 2
+ BLUE = 3
self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
- SimpleColor.MAGENTA._value_ = 9
+ SimpleColor.GREEN._value_ = 9
self.assertRaisesRegex(
TypeError, "enum mismatch",
_test_simple_enum, CheckedColor, SimpleColor,
@@ -4086,165 +4422,9 @@ class TestStdLib(unittest.TestCase):
class MiscTestCase(unittest.TestCase):
-
def test__all__(self):
support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
- def test_doc_1(self):
- class Single(Enum):
- ONE = 1
- self.assertEqual(
- Single.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Single.ONE
- <Single.ONE: 1>
-
- - value lookup:
-
- >>> Single(1)
- <Single.ONE: 1>
-
- - name lookup:
-
- >>> Single['ONE']
- <Single.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Single)
- 1
-
- >>> list(Single)
- [<Single.ONE: 1>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
- def test_doc_2(self):
- class Double(Enum):
- ONE = 1
- TWO = 2
- self.assertEqual(
- Double.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Double.ONE
- <Double.ONE: 1>
-
- - value lookup:
-
- >>> Double(1)
- <Double.ONE: 1>
-
- - name lookup:
-
- >>> Double['ONE']
- <Double.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Double)
- 2
-
- >>> list(Double)
- [<Double.ONE: 1>, <Double.TWO: 2>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
-
- def test_doc_1(self):
- class Triple(Enum):
- ONE = 1
- TWO = 2
- THREE = 3
- self.assertEqual(
- Triple.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Triple.ONE
- <Triple.ONE: 1>
-
- - value lookup:
-
- >>> Triple(1)
- <Triple.ONE: 1>
-
- - name lookup:
-
- >>> Triple['ONE']
- <Triple.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Triple)
- 3
-
- >>> list(Triple)
- [<Triple.ONE: 1>, <Triple.TWO: 2>, <Triple.THREE: 3>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
- def test_doc_1(self):
- class Quadruple(Enum):
- ONE = 1
- TWO = 2
- THREE = 3
- FOUR = 4
- self.assertEqual(
- Quadruple.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Quadruple.ONE
- <Quadruple.ONE: 1>
-
- - value lookup:
-
- >>> Quadruple(1)
- <Quadruple.ONE: 1>
-
- - name lookup:
-
- >>> Quadruple['ONE']
- <Quadruple.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Quadruple)
- 4
-
- >>> list(Quadruple)[:3]
- [<Quadruple.ONE: 1>, <Quadruple.TWO: 2>, <Quadruple.THREE: 3>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
# These are unordered here on purpose to ensure that declaration order
# makes no difference.
@@ -4262,10 +4442,6 @@ CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
CONVERT_STRING_TEST_NAME_E = 5
CONVERT_STRING_TEST_NAME_F = 5
-# global names for StrEnum._convert_ test
-CONVERT_STR_TEST_2 = 'goodbye'
-CONVERT_STR_TEST_1 = 'hello'
-
# We also need values that cannot be compared:
UNCOMPARABLE_A = 5
UNCOMPARABLE_C = (9, 1) # naming order is broken on purpose
@@ -4277,40 +4453,32 @@ COMPLEX_B = 3j
class _ModuleWrapper:
"""We use this class as a namespace for swapping modules."""
+
def __init__(self, module):
self.__dict__.update(module.__dict__)
-class TestConvert(unittest.TestCase):
- def tearDown(self):
- # Reset the module-level test variables to their original integer
- # values, otherwise the already created enum values get converted
- # instead.
- g = globals()
- for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
- g['CONVERT_TEST_NAME_%s' % suffix] = 5
- g['CONVERT_STRING_TEST_NAME_%s' % suffix] = 5
- for suffix, value in (('A', 5), ('B', (9, 1)), ('C', 'value')):
- g['UNCOMPARABLE_%s' % suffix] = value
- for suffix, value in (('A', 2j), ('B', 3j), ('C', 1j)):
- g['COMPLEX_%s' % suffix] = value
- for suffix, value in (('1', 'hello'), ('2', 'goodbye')):
- g['CONVERT_STR_TEST_%s' % suffix] = value
-
+class TestIntEnumConvert(unittest.TestCase):
def test_convert_value_lookup_priority(self):
- test_type = enum.IntEnum._convert_(
- 'UnittestConvert',
- MODULE,
- filter=lambda x: x.startswith('CONVERT_TEST_'))
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.IntEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_TEST_'))
# We don't want the reverse lookup value to vary when there are
# multiple possible names for a given value. It should always
# report the first lexigraphical name in that case.
self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
- def test_convert_int(self):
- test_type = enum.IntEnum._convert_(
- 'UnittestConvert',
- MODULE,
- filter=lambda x: x.startswith('CONVERT_TEST_'))
+ def test_convert(self):
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.IntEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_TEST_'))
# Ensure that test_type has all of the desired names and values.
self.assertEqual(test_type.CONVERT_TEST_NAME_F,
test_type.CONVERT_TEST_NAME_A)
@@ -4319,57 +4487,43 @@ class TestConvert(unittest.TestCase):
self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
# Ensure that test_type only picked up names matching the filter.
- int_dir = dir(int) + [
- 'CONVERT_TEST_NAME_A', 'CONVERT_TEST_NAME_B', 'CONVERT_TEST_NAME_C',
- 'CONVERT_TEST_NAME_D', 'CONVERT_TEST_NAME_E', 'CONVERT_TEST_NAME_F',
- ]
- self.assertEqual(
- [name for name in dir(test_type) if name not in int_dir],
- [],
- msg='Names other than CONVERT_TEST_* found.',
- )
+ self.assertEqual([name for name in dir(test_type)
+ if name[0:2] not in ('CO', '__')
+ and name not in dir(IntEnum)],
+ [], msg='Names other than CONVERT_TEST_* found.')
def test_convert_uncomparable(self):
- uncomp = enum.Enum._convert_(
- 'Uncomparable',
- MODULE,
- filter=lambda x: x.startswith('UNCOMPARABLE_'))
+ # We swap a module to some other object with `__dict__`
+ # because otherwise refleak is created.
+ # `_convert_` uses a module side effect that does this. See 30472
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ uncomp = enum.Enum._convert_(
+ 'Uncomparable',
+ MODULE,
+ filter=lambda x: x.startswith('UNCOMPARABLE_'))
+
# Should be ordered by `name` only:
self.assertEqual(
list(uncomp),
[uncomp.UNCOMPARABLE_A, uncomp.UNCOMPARABLE_B, uncomp.UNCOMPARABLE_C],
- )
+ )
def test_convert_complex(self):
- uncomp = enum.Enum._convert_(
- 'Uncomparable',
- MODULE,
- filter=lambda x: x.startswith('COMPLEX_'))
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ uncomp = enum.Enum._convert_(
+ 'Uncomparable',
+ MODULE,
+ filter=lambda x: x.startswith('COMPLEX_'))
+
# Should be ordered by `name` only:
self.assertEqual(
list(uncomp),
[uncomp.COMPLEX_A, uncomp.COMPLEX_B, uncomp.COMPLEX_C],
- )
-
- def test_convert_str(self):
- test_type = enum.StrEnum._convert_(
- 'UnittestConvert',
- MODULE,
- filter=lambda x: x.startswith('CONVERT_STR_'),
- as_global=True)
- # Ensure that test_type has all of the desired names and values.
- self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
- self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
- # Ensure that test_type only picked up names matching the filter.
- str_dir = dir(str) + ['CONVERT_STR_TEST_1', 'CONVERT_STR_TEST_2']
- self.assertEqual(
- [name for name in dir(test_type) if name not in str_dir],
- [],
- msg='Names other than CONVERT_STR_* found.',
- )
- self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
- self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
- self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
+ )
def test_convert_raise(self):
with self.assertRaises(AttributeError):
@@ -4379,58 +4533,50 @@ class TestConvert(unittest.TestCase):
filter=lambda x: x.startswith('CONVERT_TEST_'))
def test_convert_repr_and_str(self):
- test_type = enum.IntEnum._convert_(
- 'UnittestConvert',
- MODULE,
- filter=lambda x: x.startswith('CONVERT_STRING_TEST_'),
- as_global=True)
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.IntEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE)
- self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), '5')
+ self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
+# global names for StrEnum._convert_ test
+CONVERT_STR_TEST_2 = 'goodbye'
+CONVERT_STR_TEST_1 = 'hello'
-# helpers
-
-def enum_dir(cls):
- # TODO: check for custom __init__, __new__, __format__, __repr__, __str__, __init_subclass__
- if cls._member_type_ is object:
- interesting = set()
- if cls.__init_subclass__ is not object.__init_subclass__:
- interesting.add('__init_subclass__')
- return sorted(set([
- '__class__', '__contains__', '__doc__', '__getitem__',
- '__iter__', '__len__', '__members__', '__module__',
- '__name__', '__qualname__',
- ]
- + cls._member_names_
- ) | interesting
- )
- else:
- # return whatever mixed-in data type has
- return sorted(set(
- dir(cls._member_type_)
- + cls._member_names_
- ))
-
-def member_dir(member):
- if member.__class__._member_type_ is object:
- allowed = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value'])
- else:
- allowed = set(dir(member))
- for cls in member.__class__.mro():
- for name, obj in cls.__dict__.items():
- if name[0] == '_':
- continue
- if isinstance(obj, enum.property):
- if obj.fget is not None or name not in member._member_map_:
- allowed.add(name)
- else:
- allowed.discard(name)
- else:
- allowed.add(name)
- return sorted(allowed)
+class TestStrEnumConvert(unittest.TestCase):
+ def test_convert(self):
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.StrEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_STR_'))
+ # Ensure that test_type has all of the desired names and values.
+ self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
+ self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
+ # Ensure that test_type only picked up names matching the filter.
+ self.assertEqual([name for name in dir(test_type)
+ if name[0:2] not in ('CO', '__')
+ and name not in dir(StrEnum)],
+ [], msg='Names other than CONVERT_STR_* found.')
-missing = object()
+ def test_convert_repr_and_str(self):
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.StrEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_STR_'))
+ self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
+ self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
+ self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
if __name__ == '__main__':