summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_enum.py
diff options
context:
space:
mode:
authorEthan Furman <ethan@stoneleaf.us>2022-01-16 06:41:43 (GMT)
committerGitHub <noreply@github.com>2022-01-16 06:41:43 (GMT)
commitacf7403f9baea3ae1119fc6b4a3298522188bf96 (patch)
treefcffbb83c601353ac1fce9b35b0f2424c8ce9899 /Lib/test/test_enum.py
parent37eab55ac9da6b6361f136a1da15bfcef12ed954 (diff)
downloadcpython-acf7403f9baea3ae1119fc6b4a3298522188bf96.zip
cpython-acf7403f9baea3ae1119fc6b4a3298522188bf96.tar.gz
cpython-acf7403f9baea3ae1119fc6b4a3298522188bf96.tar.bz2
bpo-40066: [Enum] update str() and format() output (GH-30582)
Undo rejected PEP-663 changes: - restore `repr()` to its 3.10 status - restore `str()` to its 3.10 status New changes: - `IntEnum` and `IntFlag` now leave `__str__` as the original `int.__str__` so that str() and format() return the same result - zero-valued flags without a name have a slightly changed repr(), e.g. `repr(Color(0)) == '<Color: 0>'` - update `dir()` for mixed-in types to return all the methods and attributes of the mixed-in type - added `_numeric_repr_` to `Flag` to control display of unnamed values - enums without doc strings have a more comprehensive doc string added - `ReprEnum` added -- inheriting from this makes it so only `__repr__` is replaced, not `__str__` nor `__format__`; `IntEnum`, `IntFlag`, and `StrEnum` all inherit from `ReprEnum`
Diffstat (limited to 'Lib/test/test_enum.py')
-rw-r--r--Lib/test/test_enum.py2864
1 files changed, 1359 insertions, 1505 deletions
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index 43f98c1..a0953fb 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -6,15 +6,18 @@ 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
+from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
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]
@@ -107,6 +110,12 @@ 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
@@ -116,21 +125,36 @@ class TestHelpers(unittest.TestCase):
setattr(obj, attr, 1)
self.assertTrue(enum._is_descriptor(obj))
- def test_is_sunder(self):
+ 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)
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_is_dunder(self):
+ 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)
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:
@@ -166,473 +190,658 @@ class HeadlightsC(IntFlag, boundary=enum.CONFORM):
# tests
-class TestEnum(unittest.TestCase):
+class _EnumTests:
+ """
+ Test for behavior that is the same across the different types of enumerations.
+ """
+
+ values = None
def setUp(self):
- class Season(Enum):
- SPRING = 1
- SUMMER = 2
- AUTUMN = 3
- WINTER = 4
- self.Season = Season
+ 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
- class Konstants(float, Enum):
- E = 2.7182818
- PI = 3.1415926
- TAU = 2 * PI
- self.Konstants = Konstants
+ def assertFormatIsValue(self, spec, member):
+ self.assertEqual(spec.format(member), spec.format(member.value))
- class Grades(IntEnum):
- A = 5
- B = 4
- C = 3
- D = 2
- F = 0
- self.Grades = Grades
+ def assertFormatIsStr(self, spec, member):
+ self.assertEqual(spec.format(member), spec.format(str(member)))
- class Directional(str, Enum):
- EAST = 'east'
- WEST = 'west'
- NORTH = 'north'
- SOUTH = 'south'
- self.Directional = Directional
+ 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
- from datetime import date
- class Holiday(date, Enum):
- NEW_YEAR = 2013, 1, 1
- IDES_OF_MARCH = 2013, 3, 15
- self.Holiday = Holiday
+ 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 DateEnum(date, Enum): pass
- self.DateEnum = DateEnum
+ 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 FloatEnum(float, Enum): pass
- self.FloatEnum = FloatEnum
+ def test_changing_member_fails(self):
+ MainEnum = self.MainEnum
+ with self.assertRaises(AttributeError):
+ self.MainEnum.second = 'really first'
- class Wowser(Enum):
- this = 'that'
- these = 'those'
- def wowser(self):
- """Wowser docstring"""
- return ("Wowser! I'm %s!" % self.name)
- @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
+ @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 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
+ @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)
- 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_class(self):
+ TE = self.MainEnum
+ self.assertEqual(set(dir(TE)), set(enum_dir(TE)))
+ def test_dir_on_item(self):
+ TE = self.MainEnum
+ self.assertEqual(set(dir(TE.first)), set(member_dir(TE.first)))
+
+ def test_dir_with_added_behavior(self):
+ class Test(self.enum_type):
+ this = auto()
+ these = auto()
+ def wowser(self):
+ return ("Wowser! I'm %s!" % self.name)
+ self.assertTrue('wowser' not in dir(Test))
+ self.assertTrue('wowser' in dir(Test.this))
+
+ def test_dir_on_sub_with_behavior_on_super(self):
# see issue22506
- class SuperEnum1(Enum):
+ class SuperEnum(self.enum_type):
def invisible(self):
return "did you see me?"
- class SubEnum1(SuperEnum1):
- sample = 5
- self.SubEnum1 = SubEnum1
+ class SubEnum(SuperEnum):
+ sample = auto()
+ self.assertTrue('invisible' not in dir(SubEnum))
+ self.assertTrue('invisible' in dir(SubEnum.sample))
- class SuperEnum2(IntEnum):
- def __new__(cls, value, description=""):
- obj = int.__new__(cls, value)
- obj._value_ = value
- obj.description = description
+ 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'
return obj
- 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
- ))
+ 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))
- 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_enum_in_enum_out(self):
+ Main = self.MainEnum
+ self.assertIs(Main(Main.first), Main.first)
- 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_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())
+
+ 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)))
- first_enum_base = next(
- base for base in enum_cls.__mro__
- if is_from_enum_module(base)
+ 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)))
+
+ 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,
)
+ 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))
- 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_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))
- def test_dir_on_sub_with_behavior_on_super(self):
- # see issue22506
+ 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)
self.assertEqual(
- set(dir(self.SubEnum1.sample)),
- set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
+ [MinorEnum.june, MinorEnum.july, MinorEnum.august],
+ lst,
)
+ 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_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
- # see issue40084
- self.assertTrue({'description'} <= set(dir(self.SubEnum2.sample)))
+ 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_enum_in_enum_out(self):
- Season = self.Season
- self.assertIs(Season(Season.WINTER), Season.WINTER)
+ 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_value(self):
- Season = self.Season
- self.assertEqual(Season.SPRING.value, 1)
+ 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_intenum_value(self):
- self.assertEqual(IntStooges.CURLY.value, 2)
+ 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_enum(self):
- Season = self.Season
- lst = list(Season)
- self.assertEqual(len(lst), len(Season))
- self.assertEqual(len(Season), 4, Season)
+ def test_reversed_iteration_order(self):
self.assertEqual(
- [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
+ list(reversed(self.MainEnum)),
+ [self.MainEnum.third, self.MainEnum.second, self.MainEnum.first],
+ )
- 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 _PlainOutputTests:
- def test_changing_member(self):
- Season = self.Season
- with self.assertRaises(AttributeError):
- Season.WINTER = 'really cold'
+ 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_attribute_deletion(self):
- class Season(Enum):
- SPRING = 1
- SUMMER = 2
- AUTUMN = 3
- WINTER = 4
+ 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 spam(cls):
- pass
+ 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")
- self.assertTrue(hasattr(Season, 'spam'))
- del Season.spam
- self.assertFalse(hasattr(Season, 'spam'))
+ 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)
- 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 _MixedOutputTests:
- def test_bool_of_member(self):
- class Count(Enum):
- zero = 0
- one = 1
- two = 2
- for member in Count:
- self.assertTrue(bool(member))
+ 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
- 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
+
+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]
+
+ class enum_type(float, Enum):
+ def _generate_next_value_(name, start, count, last_values):
+ values = [1.1, 2.2, 3.3]
+ return values[count]
+
+
+class TestMinimalFloat(_EnumTests, _MinimalOutputTests, unittest.TestCase):
+
+ values = [4.4, 5.5, 6.6]
+
+ class enum_type(float, ReprEnum):
+ def _generate_next_value_(name, start, count, last_values):
+ values = [4.4, 5.5, 6.6]
+ return values[count]
+
+
+class TestSpecial(unittest.TestCase):
+ """
+ various operations that are not attributable to every possible enum
+ """
+
+ 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_bool(self):
# plain Enum members are always True
@@ -656,92 +865,56 @@ class TestEnum(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_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_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_duplicate_name(self):
+ def test_duplicate_name_error(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
@@ -749,232 +922,45 @@ class TestEnum(unittest.TestCase):
blue = 3
def red(self):
return 'red'
-
+ #
with self.assertRaises(TypeError):
class Color(Enum):
- @property
+ @enum.property
def red(self):
return 'redder'
red = 1
green = 2
blue = 3
- def test_reserved__sunder_(self):
- with self.assertRaisesRegex(
- ValueError,
- '_sunder_ names, such as ._bad_., are reserved',
- ):
- class Bad(Enum):
- _bad_ = 1
+ def test_enum_function_with_qualname(self):
+ if isinstance(Theory, Exception):
+ raise Theory
+ self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
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'
@@ -990,7 +976,7 @@ class TestEnum(unittest.TestCase):
test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
test_pickle_dump_load(self.assertIs, MyOtherEnum)
#
- # This did not work in 3.9, but does now with pickling by name
+ # This did not work in 3.10, but does now with pickling by name
class UnBrokenInt(int):
__qualname__ = 'UnBrokenInt'
def __new__(cls, value):
@@ -1007,6 +993,124 @@ class TestEnum(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):
@@ -1022,122 +1126,6 @@ class TestEnum(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):
@@ -1169,12 +1157,7 @@ class TestEnum(unittest.TestCase):
test_pickle_dump_load(self.assertIs, Question.who)
test_pickle_dump_load(self.assertIs, Question)
- 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):
+ def test_pickle_nested_class(self):
# would normally just have this directly in the class namespace
class NestedEnum(Enum):
twigs = 'common'
@@ -1192,7 +1175,7 @@ class TestEnum(unittest.TestCase):
for proto in range(HIGHEST_PROTOCOL):
self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
- def test_exploding_pickle(self):
+ def test_pickle_explodes(self):
BadPickle = Enum(
'BadPickle', 'dill sweet bread-n-butter', module=__name__)
globals()['BadPickle'] = BadPickle
@@ -1233,185 +1216,6 @@ class TestEnum(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
@@ -1425,15 +1229,18 @@ class TestEnum(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, "EvenMoreColor: cannot extend enumeration 'Color'"):
+ #
+ with self.assertRaisesRegex(TypeError, "<enum .EvenMoreColor.> cannot extend <enum .Color.>"):
class EvenMoreColor(Color, IntEnum):
chartruese = 7
- with self.assertRaisesRegex(TypeError, "Foo: cannot extend enumeration 'Color'"):
+ #
+ with self.assertRaisesRegex(TypeError, "<enum .Foo.> cannot extend <enum .Color.>"):
Color('Foo', ('pink', 'black'))
def test_exclude_methods(self):
@@ -1537,27 +1344,7 @@ class TestEnum(unittest.TestCase):
with self.assertRaises(KeyError):
Color['chartreuse']
- 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.")
+ # tests that need to be evalualted for moving
def test_multiple_mixin_mro(self):
class auto_enum(type(Enum)):
@@ -1610,7 +1397,7 @@ class TestEnum(unittest.TestCase):
return self
def __getnewargs__(self):
return self._args
- @property
+ @bltns.property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1670,7 +1457,7 @@ class TestEnum(unittest.TestCase):
return self
def __getnewargs_ex__(self):
return self._args, {}
- @property
+ @bltns.property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1730,7 +1517,7 @@ class TestEnum(unittest.TestCase):
return self
def __reduce__(self):
return self.__class__, self._args
- @property
+ @bltns.property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1790,7 +1577,7 @@ class TestEnum(unittest.TestCase):
return self
def __reduce_ex__(self, proto):
return self.__class__, self._args
- @property
+ @bltns.property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1847,7 +1634,7 @@ class TestEnum(unittest.TestCase):
self._intname = name
self._args = _args
return self
- @property
+ @bltns.property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1902,7 +1689,7 @@ class TestEnum(unittest.TestCase):
self._intname = name
self._args = _args
return self
- @property
+ @bltns.property
def __name__(self):
return self._intname
def __repr__(self):
@@ -2091,6 +1878,7 @@ class TestEnum(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):
@@ -2098,6 +1886,7 @@ class TestEnum(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):
@@ -2134,7 +1923,7 @@ class TestEnum(unittest.TestCase):
def __init__(self, mass, radius):
self.mass = mass # in kilograms
self.radius = radius # in meters
- @property
+ @enum.property
def surface_gravity(self):
# universal gravitational constant (m3 kg-1 s-2)
G = 6.67300E-11
@@ -2204,90 +1993,7 @@ class TestEnum(unittest.TestCase):
self.assertEqual(LabelledList.unprocessed, 1)
self.assertEqual(LabelledList(1), LabelledList.unprocessed)
- 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):
+ def test_default_missing_no_chained_exception(self):
class Color(Enum):
RED = 1
GREEN = 2
@@ -2299,7 +2005,7 @@ class TestEnum(unittest.TestCase):
else:
raise Exception('Exception not raised.')
- def test_missing(self):
+ def test_missing_override(self):
class Color(Enum):
red = 1
green = 2
@@ -2363,9 +2069,9 @@ class TestEnum(unittest.TestCase):
class_1_ref = weakref.ref(Class1())
class_2_ref = weakref.ref(Class2())
#
- # The exception raised by Enum creates a reference loop and thus
- # Class2 instances will stick around until the next garbage collection
- # cycle, unlike Class1.
+ # 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.
gc.collect() # For PyPy or other GCs.
self.assertIs(class_1_ref(), None)
self.assertIs(class_2_ref(), None)
@@ -2396,11 +2102,12 @@ class TestEnum(unittest.TestCase):
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 3)
self.assertEqual(Color.MAX, 3)
- self.assertEqual(str(Color.BLUE), 'BLUE')
+ self.assertEqual(str(Color.BLUE), 'Color.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)
@@ -2410,6 +2117,7 @@ class TestEnum(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)
@@ -2419,6 +2127,7 @@ class TestEnum(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)
@@ -2428,6 +2137,7 @@ class TestEnum(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)
@@ -2438,6 +2148,7 @@ class TestEnum(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)
@@ -2448,6 +2159,7 @@ class TestEnum(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)
@@ -2458,6 +2170,7 @@ class TestEnum(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)
@@ -2490,11 +2203,12 @@ class TestEnum(unittest.TestCase):
return hex(self)
class MyIntEnum(HexMixin, MyInt, enum.Enum):
- pass
+ __repr__ = HexMixin.__repr__
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):
@@ -2506,7 +2220,7 @@ class TestEnum(unittest.TestCase):
return member
self.assertEqual(Fee.TEST, 2)
- def test_miltuple_mixin_with_common_data_type(self):
+ def test_multiple_mixin_with_common_data_type(self):
class CaseInsensitiveStrEnum(str, Enum):
@classmethod
def _missing_(cls, value):
@@ -2526,7 +2240,7 @@ class TestEnum(unittest.TestCase):
unknown._value_ = value
cls._member_map_[value] = unknown
return unknown
- @property
+ @enum.property
def valid(self):
return self._valid
#
@@ -2570,7 +2284,7 @@ class TestEnum(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')
+ self.assertEqual(repr(GoodStrEnum.one), "<GoodStrEnum.one: '1'>")
#
class DumbMixin:
def __str__(self):
@@ -2579,6 +2293,7 @@ class TestEnum(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")
#
@@ -2620,74 +2335,6 @@ class TestEnum(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
@@ -2697,9 +2344,9 @@ class TestEnum(unittest.TestCase):
three = b'3', 'ascii'
four = b'4', 'latin1', 'strict'
self.assertEqual(OkayEnum.one, '1')
- self.assertEqual(str(OkayEnum.one), 'one')
- self.assertEqual('{}'.format(OkayEnum.one), 'one')
- self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
+ self.assertEqual(str(OkayEnum.one), 'OkayEnum.one')
+ self.assertEqual('{}'.format(OkayEnum.one), 'OkayEnum.one')
+ self.assertEqual(repr(OkayEnum.one), "<OkayEnum.one: '1'>")
#
class DumbMixin:
def __str__(self):
@@ -2708,6 +2355,7 @@ class TestEnum(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")
#
@@ -2717,7 +2365,7 @@ class TestEnum(unittest.TestCase):
class HelloEnum(EnumMixin, CustomStrEnum):
eight = '8'
self.assertEqual(HelloEnum.eight, '8')
- self.assertEqual(str(HelloEnum.eight), 'eight')
+ self.assertEqual(str(HelloEnum.eight), 'HelloEnum.eight')
#
class GoodbyeMixin:
def goodbye(self):
@@ -2725,7 +2373,7 @@ class TestEnum(unittest.TestCase):
class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
nine = '9'
self.assertEqual(GoodbyeEnum.nine, '9')
- self.assertEqual(str(GoodbyeEnum.nine), 'nine')
+ self.assertEqual(str(GoodbyeEnum.nine), 'GoodbyeEnum.nine')
#
class FirstFailedStrEnum(CustomStrEnum):
one = 1 # this will become '1'
@@ -2771,21 +2419,6 @@ class TestEnum(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):
@@ -2794,35 +2427,13 @@ class TestEnum(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, "Di: no instance attribute .NO."):
+ with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no 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):
#
@@ -2839,7 +2450,7 @@ class TestEnum(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
@@ -2851,8 +2462,42 @@ class TestEnum(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):
@@ -2914,7 +2559,7 @@ class TestOrder(unittest.TestCase):
verde = green
-class TestFlag(unittest.TestCase):
+class OldTestFlag(unittest.TestCase):
"""Tests of the Flags."""
class Perm(Flag):
@@ -2937,65 +2582,6 @@ class TestFlag(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:
@@ -3088,7 +2674,7 @@ class TestFlag(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)
@@ -3297,7 +2883,7 @@ class TestFlag(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()
@@ -3332,11 +2918,12 @@ class TestFlag(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), 'BLUE')
+ self.assertEqual(str(Color.BLUE), 'Color.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)
@@ -3346,6 +2933,7 @@ class TestFlag(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)
@@ -3426,21 +3014,8 @@ class TestFlag(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 TestIntFlag(unittest.TestCase):
+class OldTestIntFlag(unittest.TestCase):
"""Tests of the IntFlags."""
class Perm(IntFlag):
@@ -3485,73 +3060,6 @@ class TestIntFlag(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)),
@@ -3559,11 +3067,11 @@ class TestIntFlag(unittest.TestCase):
)
self.assertEqual(
repr(HeadlightsK(2**0 + 2**2 + 2**3)),
- '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE},
+ '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|8' % {'m': SHORT_MODULE},
)
self.assertEqual(
repr(HeadlightsK(2**3)),
- '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
+ '%(m)s.HeadlightsK(8)' % {'m': SHORT_MODULE},
)
def test_global_repr_conform1(self):
@@ -3705,7 +3213,7 @@ class TestIntFlag(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)
@@ -3942,11 +3450,12 @@ class TestIntFlag(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), 'BLUE')
+ self.assertEqual(str(Color.BLUE), '4')
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)
@@ -3956,6 +3465,7 @@ class TestIntFlag(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)
@@ -4000,19 +3510,6 @@ class TestIntFlag(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):
@@ -4229,6 +3726,89 @@ 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
@@ -4238,7 +3818,35 @@ 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
- | An enumeration.
+ | 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.
|\x20\x20
| Method resolution order:
| Color
@@ -4247,11 +3855,11 @@ class Color(enum.Enum)
|\x20\x20
| Data and other attributes defined here:
|\x20\x20
- | blue = Color.blue
+ | CYAN = <Color.CYAN: 1>
|\x20\x20
- | green = Color.green
+ | MAGENTA = <Color.MAGENTA: 2>
|\x20\x20
- | red = Color.red
+ | YELLOW = <Color.YELLOW: 3>
|\x20\x20
| ----------------------------------------------------------------------
| Data descriptors inherited from enum.Enum:
@@ -4263,6 +3871,25 @@ 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__
@@ -4284,11 +3911,11 @@ class Color(enum.Enum)
|\x20\x20
| Data and other attributes defined here:
|\x20\x20
- | blue = Color.blue
+ | YELLOW = <Color.YELLOW: 3>
|\x20\x20
- | green = Color.green
+ | MAGENTA = <Color.MAGENTA: 2>
|\x20\x20
- | red = Color.red
+ | CYAN = <Color.CYAN: 1>
|\x20\x20
| ----------------------------------------------------------------------
| Data descriptors inherited from enum.Enum:
@@ -4307,9 +3934,9 @@ class TestStdLib(unittest.TestCase):
maxDiff = None
class Color(Enum):
- red = 1
- green = 2
- blue = 3
+ CYAN = 1
+ MAGENTA = 2
+ YELLOW = 3
def test_pydoc(self):
# indirectly test __objclass__
@@ -4321,24 +3948,34 @@ class TestStdLib(unittest.TestCase):
helper = pydoc.Helper(output=output)
helper(self.Color)
result = output.getvalue().strip()
- self.assertEqual(result, expected_text)
+ self.assertEqual(result, expected_text, result)
def test_inspect_getmembers(self):
values = dict((
('__class__', EnumType),
- ('__doc__', 'An enumeration.'),
+ ('__doc__', '...'),
('__members__', self.Color.__members__),
('__module__', __name__),
- ('blue', self.Color.blue),
- ('green', self.Color.green),
+ ('YELLOW', self.Color.YELLOW),
+ ('MAGENTA', self.Color.MAGENTA),
+ ('CYAN', self.Color.CYAN),
('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' %
@@ -4353,23 +3990,42 @@ 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='An enumeration.'),
+ 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__),
Attribute(name='__members__', kind='property',
defining_class=EnumType, object=EnumType.__members__),
Attribute(name='__module__', kind='data',
defining_class=self.Color, object=__name__),
- 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=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='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)
@@ -4379,7 +4035,15 @@ class TestStdLib(unittest.TestCase):
)
failed = False
for v, r in zip(values, result):
- if r != v:
+ 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:
print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
failed = True
if failed:
@@ -4388,15 +4052,15 @@ class TestStdLib(unittest.TestCase):
def test_test_simple_enum(self):
@_simple_enum(Enum)
class SimpleColor:
- RED = 1
- GREEN = 2
- BLUE = 3
+ CYAN = 1
+ MAGENTA = 2
+ YELLOW = 3
class CheckedColor(Enum):
- RED = 1
- GREEN = 2
- BLUE = 3
+ CYAN = 1
+ MAGENTA = 2
+ YELLOW = 3
self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
- SimpleColor.GREEN._value_ = 9
+ SimpleColor.MAGENTA._value_ = 9
self.assertRaisesRegex(
TypeError, "enum mismatch",
_test_simple_enum, CheckedColor, SimpleColor,
@@ -4422,9 +4086,165 @@ 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.
@@ -4442,6 +4262,10 @@ 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
@@ -4453,32 +4277,40 @@ 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 TestIntEnumConvert(unittest.TestCase):
+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
+
def test_convert_value_lookup_priority(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_'))
+ 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(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_'))
+ def test_convert_int(self):
+ 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)
@@ -4487,43 +4319,57 @@ class TestIntEnumConvert(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.
- 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.')
+ 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.',
+ )
def test_convert_uncomparable(self):
- # 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_'))
-
+ 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):
- with support.swap_item(
- sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
- ):
- uncomp = enum.Enum._convert_(
- 'Uncomparable',
- MODULE,
- filter=lambda x: x.startswith('COMPLEX_'))
-
+ 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):
@@ -4533,50 +4379,58 @@ class TestIntEnumConvert(unittest.TestCase):
filter=lambda x: x.startswith('CONVERT_TEST_'))
def test_convert_repr_and_str(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_STRING_TEST_'))
+ test_type = enum.IntEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_STRING_TEST_'),
+ as_global=True)
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), 'CONVERT_STRING_TEST_NAME_A')
+ self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), '5')
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'
-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.')
+# helpers
- 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')
+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)
+
+missing = object()
if __name__ == '__main__':