1import enum 2import doctest 3import inspect 4import os 5import pydoc 6import sys 7import unittest 8import threading 9from collections import OrderedDict 10from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto 11from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum 12from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS 13from io import StringIO 14from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL 15from test import support 16from test.support import ALWAYS_EQ 17from test.support import threading_helper 18from datetime import timedelta 19 20python_version = sys.version_info[:2] 21 22def load_tests(loader, tests, ignore): 23 tests.addTests(doctest.DocTestSuite(enum)) 24 if os.path.exists('Doc/library/enum.rst'): 25 tests.addTests(doctest.DocFileSuite( 26 '../../Doc/library/enum.rst', 27 optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE, 28 )) 29 return tests 30 31MODULE = ('test.test_enum', '__main__')[__name__=='__main__'] 32SHORT_MODULE = MODULE.split('.')[-1] 33 34# for pickle tests 35try: 36 class Stooges(Enum): 37 LARRY = 1 38 CURLY = 2 39 MOE = 3 40except Exception as exc: 41 Stooges = exc 42 43try: 44 class IntStooges(int, Enum): 45 LARRY = 1 46 CURLY = 2 47 MOE = 3 48except Exception as exc: 49 IntStooges = exc 50 51try: 52 class FloatStooges(float, Enum): 53 LARRY = 1.39 54 CURLY = 2.72 55 MOE = 3.142596 56except Exception as exc: 57 FloatStooges = exc 58 59try: 60 class FlagStooges(Flag): 61 LARRY = 1 62 CURLY = 2 63 MOE = 3 64except Exception as exc: 65 FlagStooges = exc 66 67# for pickle test and subclass tests 68class Name(StrEnum): 69 BDFL = 'Guido van Rossum' 70 FLUFL = 'Barry Warsaw' 71 72try: 73 Question = Enum('Question', 'who what when where why', module=__name__) 74except Exception as exc: 75 Question = exc 76 77try: 78 Answer = Enum('Answer', 'him this then there because') 79except Exception as exc: 80 Answer = exc 81 82try: 83 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition') 84except Exception as exc: 85 Theory = exc 86 87# for doctests 88try: 89 class Fruit(Enum): 90 TOMATO = 1 91 BANANA = 2 92 CHERRY = 3 93except Exception: 94 pass 95 96def test_pickle_dump_load(assertion, source, target=None): 97 if target is None: 98 target = source 99 for protocol in range(HIGHEST_PROTOCOL + 1): 100 assertion(loads(dumps(source, protocol=protocol)), target) 101 102def test_pickle_exception(assertion, exception, obj): 103 for protocol in range(HIGHEST_PROTOCOL + 1): 104 with assertion(exception): 105 dumps(obj, protocol=protocol) 106 107class TestHelpers(unittest.TestCase): 108 # _is_descriptor, _is_sunder, _is_dunder 109 110 def test_is_descriptor(self): 111 class foo: 112 pass 113 for attr in ('__get__','__set__','__delete__'): 114 obj = foo() 115 self.assertFalse(enum._is_descriptor(obj)) 116 setattr(obj, attr, 1) 117 self.assertTrue(enum._is_descriptor(obj)) 118 119 def test_is_sunder(self): 120 for s in ('_a_', '_aa_'): 121 self.assertTrue(enum._is_sunder(s)) 122 123 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_', 124 '__', '___', '____', '_____',): 125 self.assertFalse(enum._is_sunder(s)) 126 127 def test_is_dunder(self): 128 for s in ('__a__', '__aa__'): 129 self.assertTrue(enum._is_dunder(s)) 130 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_', 131 '__', '___', '____', '_____',): 132 self.assertFalse(enum._is_dunder(s)) 133 134# for subclassing tests 135 136class classproperty: 137 138 def __init__(self, fget=None, fset=None, fdel=None, doc=None): 139 self.fget = fget 140 self.fset = fset 141 self.fdel = fdel 142 if doc is None and fget is not None: 143 doc = fget.__doc__ 144 self.__doc__ = doc 145 146 def __get__(self, instance, ownerclass): 147 return self.fget(ownerclass) 148 149# for global repr tests 150 151@enum.global_enum 152class HeadlightsK(IntFlag, boundary=enum.KEEP): 153 OFF_K = 0 154 LOW_BEAM_K = auto() 155 HIGH_BEAM_K = auto() 156 FOG_K = auto() 157 158 159@enum.global_enum 160class HeadlightsC(IntFlag, boundary=enum.CONFORM): 161 OFF_C = 0 162 LOW_BEAM_C = auto() 163 HIGH_BEAM_C = auto() 164 FOG_C = auto() 165 166 167# tests 168 169class TestEnum(unittest.TestCase): 170 171 def setUp(self): 172 class Season(Enum): 173 SPRING = 1 174 SUMMER = 2 175 AUTUMN = 3 176 WINTER = 4 177 self.Season = Season 178 179 class Konstants(float, Enum): 180 E = 2.7182818 181 PI = 3.1415926 182 TAU = 2 * PI 183 self.Konstants = Konstants 184 185 class Grades(IntEnum): 186 A = 5 187 B = 4 188 C = 3 189 D = 2 190 F = 0 191 self.Grades = Grades 192 193 class Directional(str, Enum): 194 EAST = 'east' 195 WEST = 'west' 196 NORTH = 'north' 197 SOUTH = 'south' 198 self.Directional = Directional 199 200 from datetime import date 201 class Holiday(date, Enum): 202 NEW_YEAR = 2013, 1, 1 203 IDES_OF_MARCH = 2013, 3, 15 204 self.Holiday = Holiday 205 206 class DateEnum(date, Enum): pass 207 self.DateEnum = DateEnum 208 209 class FloatEnum(float, Enum): pass 210 self.FloatEnum = FloatEnum 211 212 class Wowser(Enum): 213 this = 'that' 214 these = 'those' 215 def wowser(self): 216 """Wowser docstring""" 217 return ("Wowser! I'm %s!" % self.name) 218 @classmethod 219 def classmethod_wowser(cls): pass 220 @staticmethod 221 def staticmethod_wowser(): pass 222 self.Wowser = Wowser 223 224 class IntWowser(IntEnum): 225 this = 1 226 these = 2 227 def wowser(self): 228 """Wowser docstring""" 229 return ("Wowser! I'm %s!" % self.name) 230 @classmethod 231 def classmethod_wowser(cls): pass 232 @staticmethod 233 def staticmethod_wowser(): pass 234 self.IntWowser = IntWowser 235 236 class FloatWowser(float, Enum): 237 this = 3.14 238 these = 4.2 239 def wowser(self): 240 """Wowser docstring""" 241 return ("Wowser! I'm %s!" % self.name) 242 @classmethod 243 def classmethod_wowser(cls): pass 244 @staticmethod 245 def staticmethod_wowser(): pass 246 self.FloatWowser = FloatWowser 247 248 class WowserNoMembers(Enum): 249 def wowser(self): pass 250 @classmethod 251 def classmethod_wowser(cls): pass 252 @staticmethod 253 def staticmethod_wowser(): pass 254 class SubclassOfWowserNoMembers(WowserNoMembers): pass 255 self.WowserNoMembers = WowserNoMembers 256 self.SubclassOfWowserNoMembers = SubclassOfWowserNoMembers 257 258 class IntWowserNoMembers(IntEnum): 259 def wowser(self): pass 260 @classmethod 261 def classmethod_wowser(cls): pass 262 @staticmethod 263 def staticmethod_wowser(): pass 264 self.IntWowserNoMembers = IntWowserNoMembers 265 266 class FloatWowserNoMembers(float, Enum): 267 def wowser(self): pass 268 @classmethod 269 def classmethod_wowser(cls): pass 270 @staticmethod 271 def staticmethod_wowser(): pass 272 self.FloatWowserNoMembers = FloatWowserNoMembers 273 274 class EnumWithInit(Enum): 275 def __init__(self, greeting, farewell): 276 self.greeting = greeting 277 self.farewell = farewell 278 ENGLISH = 'hello', 'goodbye' 279 GERMAN = 'Guten Morgen', 'Auf Wiedersehen' 280 def some_method(self): pass 281 self.EnumWithInit = EnumWithInit 282 283 # see issue22506 284 class SuperEnum1(Enum): 285 def invisible(self): 286 return "did you see me?" 287 class SubEnum1(SuperEnum1): 288 sample = 5 289 self.SubEnum1 = SubEnum1 290 291 class SuperEnum2(IntEnum): 292 def __new__(cls, value, description=""): 293 obj = int.__new__(cls, value) 294 obj._value_ = value 295 obj.description = description 296 return obj 297 class SubEnum2(SuperEnum2): 298 sample = 5 299 self.SubEnum2 = SubEnum2 300 301 def test_dir_basics_for_all_enums(self): 302 enums_for_tests = ( 303 # Generic enums in enum.py 304 Enum, 305 IntEnum, 306 StrEnum, 307 # Generic enums defined outside of enum.py 308 self.DateEnum, 309 self.FloatEnum, 310 # Concrete enums derived from enum.py generics 311 self.Grades, 312 self.Season, 313 # Concrete enums derived from generics defined outside of enum.py 314 self.Konstants, 315 self.Holiday, 316 # Standard enum with added behaviour & members 317 self.Wowser, 318 # Mixin-enum-from-enum.py with added behaviour & members 319 self.IntWowser, 320 # Mixin-enum-from-oustide-enum.py with added behaviour & members 321 self.FloatWowser, 322 # Equivalents of the three immediately above, but with no members 323 self.WowserNoMembers, 324 self.IntWowserNoMembers, 325 self.FloatWowserNoMembers, 326 # Enum with members and an __init__ method 327 self.EnumWithInit, 328 # Special cases to test 329 self.SubEnum1, 330 self.SubEnum2 331 ) 332 333 for cls in enums_for_tests: 334 with self.subTest(cls=cls): 335 cls_dir = dir(cls) 336 # test that dir is deterministic 337 self.assertEqual(cls_dir, dir(cls)) 338 # test that dir is sorted 339 self.assertEqual(list(cls_dir), sorted(cls_dir)) 340 # test that there are no dupes in dir 341 self.assertEqual(len(cls_dir), len(set(cls_dir))) 342 # test that there are no sunders in dir 343 self.assertFalse(any(enum._is_sunder(attr) for attr in cls_dir)) 344 self.assertNotIn('__new__', cls_dir) 345 346 for attr in ('__class__', '__doc__', '__members__', '__module__'): 347 with self.subTest(attr=attr): 348 self.assertIn(attr, cls_dir) 349 350 def test_dir_for_enum_with_members(self): 351 enums_for_test = ( 352 # Enum with members 353 self.Season, 354 # IntEnum with members 355 self.Grades, 356 # Two custom-mixin enums with members 357 self.Konstants, 358 self.Holiday, 359 # several enums-with-added-behaviour and members 360 self.Wowser, 361 self.IntWowser, 362 self.FloatWowser, 363 # An enum with an __init__ method and members 364 self.EnumWithInit, 365 # Special cases to test 366 self.SubEnum1, 367 self.SubEnum2 368 ) 369 370 for cls in enums_for_test: 371 cls_dir = dir(cls) 372 member_names = cls._member_names_ 373 with self.subTest(cls=cls): 374 self.assertTrue(all(member_name in cls_dir for member_name in member_names)) 375 for member in cls: 376 member_dir = dir(member) 377 # test that dir is deterministic 378 self.assertEqual(member_dir, dir(member)) 379 # test that dir is sorted 380 self.assertEqual(list(member_dir), sorted(member_dir)) 381 # test that there are no dupes in dir 382 self.assertEqual(len(member_dir), len(set(member_dir))) 383 384 for attr_name in cls_dir: 385 with self.subTest(attr_name=attr_name): 386 if attr_name in {'__members__', '__init__', '__new__', *member_names}: 387 self.assertNotIn(attr_name, member_dir) 388 else: 389 self.assertIn(attr_name, member_dir) 390 391 self.assertFalse(any(enum._is_sunder(attr) for attr in member_dir)) 392 393 def test_dir_for_enums_with_added_behaviour(self): 394 enums_for_test = ( 395 self.Wowser, 396 self.IntWowser, 397 self.FloatWowser, 398 self.WowserNoMembers, 399 self.SubclassOfWowserNoMembers, 400 self.IntWowserNoMembers, 401 self.FloatWowserNoMembers 402 ) 403 404 for cls in enums_for_test: 405 with self.subTest(cls=cls): 406 self.assertIn('wowser', dir(cls)) 407 self.assertIn('classmethod_wowser', dir(cls)) 408 self.assertIn('staticmethod_wowser', dir(cls)) 409 self.assertTrue(all( 410 all(attr in dir(member) for attr in ('wowser', 'classmethod_wowser', 'staticmethod_wowser')) 411 for member in cls 412 )) 413 414 self.assertEqual(dir(self.WowserNoMembers), dir(self.SubclassOfWowserNoMembers)) 415 # Check classmethods are present 416 self.assertIn('from_bytes', dir(self.IntWowser)) 417 self.assertIn('from_bytes', dir(self.IntWowserNoMembers)) 418 419 def test_help_output_on_enum_members(self): 420 added_behaviour_enums = ( 421 self.Wowser, 422 self.IntWowser, 423 self.FloatWowser 424 ) 425 426 for cls in added_behaviour_enums: 427 with self.subTest(cls=cls): 428 rendered_doc = pydoc.render_doc(cls.this) 429 self.assertIn('Wowser docstring', rendered_doc) 430 if cls in {self.IntWowser, self.FloatWowser}: 431 self.assertIn('float(self)', rendered_doc) 432 433 def test_dir_for_enum_with_init(self): 434 EnumWithInit = self.EnumWithInit 435 436 cls_dir = dir(EnumWithInit) 437 self.assertIn('__init__', cls_dir) 438 self.assertIn('some_method', cls_dir) 439 self.assertNotIn('greeting', cls_dir) 440 self.assertNotIn('farewell', cls_dir) 441 442 member_dir = dir(EnumWithInit.ENGLISH) 443 self.assertNotIn('__init__', member_dir) 444 self.assertIn('some_method', member_dir) 445 self.assertIn('greeting', member_dir) 446 self.assertIn('farewell', member_dir) 447 448 def test_mixin_dirs(self): 449 from datetime import date 450 451 enums_for_test = ( 452 # generic mixins from enum.py 453 (IntEnum, int), 454 (StrEnum, str), 455 # generic mixins from outside enum.py 456 (self.FloatEnum, float), 457 (self.DateEnum, date), 458 # concrete mixin from enum.py 459 (self.Grades, int), 460 # concrete mixin from outside enum.py 461 (self.Holiday, date), 462 # concrete mixin from enum.py with added behaviour 463 (self.IntWowser, int), 464 # concrete mixin from outside enum.py with added behaviour 465 (self.FloatWowser, float) 466 ) 467 468 enum_dict = Enum.__dict__ 469 enum_dir = dir(Enum) 470 enum_module_names = enum.__all__ 471 is_from_enum_module = lambda cls: cls.__name__ in enum_module_names 472 is_enum_dunder = lambda attr: enum._is_dunder(attr) and attr in enum_dict 473 474 def attr_is_inherited_from_object(cls, attr_name): 475 for base in cls.__mro__: 476 if attr_name in base.__dict__: 477 return base is object 478 return False 479 480 # General tests 481 for enum_cls, mixin_cls in enums_for_test: 482 with self.subTest(enum_cls=enum_cls): 483 cls_dir = dir(enum_cls) 484 cls_dict = enum_cls.__dict__ 485 486 mixin_attrs = [ 487 x for x in dir(mixin_cls) 488 if not attr_is_inherited_from_object(cls=mixin_cls, attr_name=x) 489 ] 490 491 first_enum_base = next( 492 base for base in enum_cls.__mro__ 493 if is_from_enum_module(base) 494 ) 495 496 for attr in mixin_attrs: 497 with self.subTest(attr=attr): 498 if enum._is_sunder(attr): 499 # Unlikely, but no harm in testing 500 self.assertNotIn(attr, cls_dir) 501 elif attr in {'__class__', '__doc__', '__members__', '__module__'}: 502 self.assertIn(attr, cls_dir) 503 elif is_enum_dunder(attr): 504 if is_from_enum_module(enum_cls): 505 self.assertNotIn(attr, cls_dir) 506 elif getattr(enum_cls, attr) is getattr(first_enum_base, attr): 507 self.assertNotIn(attr, cls_dir) 508 else: 509 self.assertIn(attr, cls_dir) 510 else: 511 self.assertIn(attr, cls_dir) 512 513 # Some specific examples 514 int_enum_dir = dir(IntEnum) 515 self.assertIn('imag', int_enum_dir) 516 self.assertIn('__rfloordiv__', int_enum_dir) 517 self.assertNotIn('__format__', int_enum_dir) 518 self.assertNotIn('__hash__', int_enum_dir) 519 self.assertNotIn('__init_subclass__', int_enum_dir) 520 self.assertNotIn('__subclasshook__', int_enum_dir) 521 522 class OverridesFormatOutsideEnumModule(Enum): 523 def __format__(self, *args, **kwargs): 524 return super().__format__(*args, **kwargs) 525 SOME_MEMBER = 1 526 527 self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule)) 528 self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule.SOME_MEMBER)) 529 530 def test_dir_on_sub_with_behavior_on_super(self): 531 # see issue22506 532 self.assertEqual( 533 set(dir(self.SubEnum1.sample)), 534 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']), 535 ) 536 537 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self): 538 # see issue40084 539 self.assertTrue({'description'} <= set(dir(self.SubEnum2.sample))) 540 541 def test_enum_in_enum_out(self): 542 Season = self.Season 543 self.assertIs(Season(Season.WINTER), Season.WINTER) 544 545 def test_enum_value(self): 546 Season = self.Season 547 self.assertEqual(Season.SPRING.value, 1) 548 549 def test_intenum_value(self): 550 self.assertEqual(IntStooges.CURLY.value, 2) 551 552 def test_enum(self): 553 Season = self.Season 554 lst = list(Season) 555 self.assertEqual(len(lst), len(Season)) 556 self.assertEqual(len(Season), 4, Season) 557 self.assertEqual( 558 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst) 559 560 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1): 561 e = Season(i) 562 self.assertEqual(e, getattr(Season, season)) 563 self.assertEqual(e.value, i) 564 self.assertNotEqual(e, i) 565 self.assertEqual(e.name, season) 566 self.assertIn(e, Season) 567 self.assertIs(type(e), Season) 568 self.assertIsInstance(e, Season) 569 self.assertEqual(str(e), season) 570 self.assertEqual(repr(e), 'Season.{0}'.format(season)) 571 572 def test_value_name(self): 573 Season = self.Season 574 self.assertEqual(Season.SPRING.name, 'SPRING') 575 self.assertEqual(Season.SPRING.value, 1) 576 with self.assertRaises(AttributeError): 577 Season.SPRING.name = 'invierno' 578 with self.assertRaises(AttributeError): 579 Season.SPRING.value = 2 580 581 def test_changing_member(self): 582 Season = self.Season 583 with self.assertRaises(AttributeError): 584 Season.WINTER = 'really cold' 585 586 def test_attribute_deletion(self): 587 class Season(Enum): 588 SPRING = 1 589 SUMMER = 2 590 AUTUMN = 3 591 WINTER = 4 592 593 def spam(cls): 594 pass 595 596 self.assertTrue(hasattr(Season, 'spam')) 597 del Season.spam 598 self.assertFalse(hasattr(Season, 'spam')) 599 600 with self.assertRaises(AttributeError): 601 del Season.SPRING 602 with self.assertRaises(AttributeError): 603 del Season.DRY 604 with self.assertRaises(AttributeError): 605 del Season.SPRING.name 606 607 def test_bool_of_class(self): 608 class Empty(Enum): 609 pass 610 self.assertTrue(bool(Empty)) 611 612 def test_bool_of_member(self): 613 class Count(Enum): 614 zero = 0 615 one = 1 616 two = 2 617 for member in Count: 618 self.assertTrue(bool(member)) 619 620 def test_invalid_names(self): 621 with self.assertRaises(ValueError): 622 class Wrong(Enum): 623 mro = 9 624 with self.assertRaises(ValueError): 625 class Wrong(Enum): 626 _create_= 11 627 with self.assertRaises(ValueError): 628 class Wrong(Enum): 629 _get_mixins_ = 9 630 with self.assertRaises(ValueError): 631 class Wrong(Enum): 632 _find_new_ = 1 633 with self.assertRaises(ValueError): 634 class Wrong(Enum): 635 _any_name_ = 9 636 637 def test_bool(self): 638 # plain Enum members are always True 639 class Logic(Enum): 640 true = True 641 false = False 642 self.assertTrue(Logic.true) 643 self.assertTrue(Logic.false) 644 # unless overridden 645 class RealLogic(Enum): 646 true = True 647 false = False 648 def __bool__(self): 649 return bool(self._value_) 650 self.assertTrue(RealLogic.true) 651 self.assertFalse(RealLogic.false) 652 # mixed Enums depend on mixed-in type 653 class IntLogic(int, Enum): 654 true = 1 655 false = 0 656 self.assertTrue(IntLogic.true) 657 self.assertFalse(IntLogic.false) 658 659 @unittest.skipIf( 660 python_version >= (3, 12), 661 '__contains__ now returns True/False for all inputs', 662 ) 663 def test_contains_er(self): 664 Season = self.Season 665 self.assertIn(Season.AUTUMN, Season) 666 with self.assertRaises(TypeError): 667 with self.assertWarns(DeprecationWarning): 668 3 in Season 669 with self.assertRaises(TypeError): 670 with self.assertWarns(DeprecationWarning): 671 'AUTUMN' in Season 672 val = Season(3) 673 self.assertIn(val, Season) 674 # 675 class OtherEnum(Enum): 676 one = 1; two = 2 677 self.assertNotIn(OtherEnum.two, Season) 678 679 @unittest.skipIf( 680 python_version < (3, 12), 681 '__contains__ only works with enum memmbers before 3.12', 682 ) 683 def test_contains_tf(self): 684 Season = self.Season 685 self.assertIn(Season.AUTUMN, Season) 686 self.assertTrue(3 in Season) 687 self.assertFalse('AUTUMN' in Season) 688 val = Season(3) 689 self.assertIn(val, Season) 690 # 691 class OtherEnum(Enum): 692 one = 1; two = 2 693 self.assertNotIn(OtherEnum.two, Season) 694 695 def test_comparisons(self): 696 Season = self.Season 697 with self.assertRaises(TypeError): 698 Season.SPRING < Season.WINTER 699 with self.assertRaises(TypeError): 700 Season.SPRING > 4 701 702 self.assertNotEqual(Season.SPRING, 1) 703 704 class Part(Enum): 705 SPRING = 1 706 CLIP = 2 707 BARREL = 3 708 709 self.assertNotEqual(Season.SPRING, Part.SPRING) 710 with self.assertRaises(TypeError): 711 Season.SPRING < Part.CLIP 712 713 def test_enum_duplicates(self): 714 class Season(Enum): 715 SPRING = 1 716 SUMMER = 2 717 AUTUMN = FALL = 3 718 WINTER = 4 719 ANOTHER_SPRING = 1 720 lst = list(Season) 721 self.assertEqual( 722 lst, 723 [Season.SPRING, Season.SUMMER, 724 Season.AUTUMN, Season.WINTER, 725 ]) 726 self.assertIs(Season.FALL, Season.AUTUMN) 727 self.assertEqual(Season.FALL.value, 3) 728 self.assertEqual(Season.AUTUMN.value, 3) 729 self.assertIs(Season(3), Season.AUTUMN) 730 self.assertIs(Season(1), Season.SPRING) 731 self.assertEqual(Season.FALL.name, 'AUTUMN') 732 self.assertEqual( 733 [k for k,v in Season.__members__.items() if v.name != k], 734 ['FALL', 'ANOTHER_SPRING'], 735 ) 736 737 def test_duplicate_name(self): 738 with self.assertRaises(TypeError): 739 class Color(Enum): 740 red = 1 741 green = 2 742 blue = 3 743 red = 4 744 745 with self.assertRaises(TypeError): 746 class Color(Enum): 747 red = 1 748 green = 2 749 blue = 3 750 def red(self): 751 return 'red' 752 753 with self.assertRaises(TypeError): 754 class Color(Enum): 755 @property 756 def red(self): 757 return 'redder' 758 red = 1 759 green = 2 760 blue = 3 761 762 def test_reserved__sunder_(self): 763 with self.assertRaisesRegex( 764 ValueError, 765 '_sunder_ names, such as ._bad_., are reserved', 766 ): 767 class Bad(Enum): 768 _bad_ = 1 769 770 def test_enum_with_value_name(self): 771 class Huh(Enum): 772 name = 1 773 value = 2 774 self.assertEqual( 775 list(Huh), 776 [Huh.name, Huh.value], 777 ) 778 self.assertIs(type(Huh.name), Huh) 779 self.assertEqual(Huh.name.name, 'name') 780 self.assertEqual(Huh.name.value, 1) 781 782 def test_format_enum(self): 783 Season = self.Season 784 self.assertEqual('{}'.format(Season.SPRING), 785 '{}'.format(str(Season.SPRING))) 786 self.assertEqual( '{:}'.format(Season.SPRING), 787 '{:}'.format(str(Season.SPRING))) 788 self.assertEqual('{:20}'.format(Season.SPRING), 789 '{:20}'.format(str(Season.SPRING))) 790 self.assertEqual('{:^20}'.format(Season.SPRING), 791 '{:^20}'.format(str(Season.SPRING))) 792 self.assertEqual('{:>20}'.format(Season.SPRING), 793 '{:>20}'.format(str(Season.SPRING))) 794 self.assertEqual('{:<20}'.format(Season.SPRING), 795 '{:<20}'.format(str(Season.SPRING))) 796 797 def test_str_override_enum(self): 798 class EnumWithStrOverrides(Enum): 799 one = auto() 800 two = auto() 801 802 def __str__(self): 803 return 'Str!' 804 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!') 805 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!') 806 807 def test_format_override_enum(self): 808 class EnumWithFormatOverride(Enum): 809 one = 1.0 810 two = 2.0 811 def __format__(self, spec): 812 return 'Format!!' 813 self.assertEqual(str(EnumWithFormatOverride.one), 'one') 814 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!') 815 816 def test_str_and_format_override_enum(self): 817 class EnumWithStrFormatOverrides(Enum): 818 one = auto() 819 two = auto() 820 def __str__(self): 821 return 'Str!' 822 def __format__(self, spec): 823 return 'Format!' 824 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!') 825 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!') 826 827 def test_str_override_mixin(self): 828 class MixinEnumWithStrOverride(float, Enum): 829 one = 1.0 830 two = 2.0 831 def __str__(self): 832 return 'Overridden!' 833 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!') 834 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!') 835 836 def test_str_and_format_override_mixin(self): 837 class MixinWithStrFormatOverrides(float, Enum): 838 one = 1.0 839 two = 2.0 840 def __str__(self): 841 return 'Str!' 842 def __format__(self, spec): 843 return 'Format!' 844 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!') 845 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!') 846 847 def test_format_override_mixin(self): 848 class TestFloat(float, Enum): 849 one = 1.0 850 two = 2.0 851 def __format__(self, spec): 852 return 'TestFloat success!' 853 self.assertEqual(str(TestFloat.one), 'one') 854 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!') 855 856 @unittest.skipIf( 857 python_version < (3, 12), 858 'mixin-format is still using member.value', 859 ) 860 def test_mixin_format_warning(self): 861 class Grades(int, Enum): 862 A = 5 863 B = 4 864 C = 3 865 D = 2 866 F = 0 867 self.assertEqual(f'{self.Grades.B}', 'B') 868 869 @unittest.skipIf( 870 python_version >= (3, 12), 871 'mixin-format now uses member instead of member.value', 872 ) 873 def test_mixin_format_warning(self): 874 class Grades(int, Enum): 875 A = 5 876 B = 4 877 C = 3 878 D = 2 879 F = 0 880 with self.assertWarns(DeprecationWarning): 881 self.assertEqual(f'{Grades.B}', '4') 882 883 def assertFormatIsValue(self, spec, member): 884 if python_version < (3, 12) and (not spec or spec in ('{}','{:}')): 885 with self.assertWarns(DeprecationWarning): 886 self.assertEqual(spec.format(member), spec.format(member.value)) 887 else: 888 self.assertEqual(spec.format(member), spec.format(member.value)) 889 890 def test_format_enum_date(self): 891 Holiday = self.Holiday 892 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH) 893 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH) 894 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH) 895 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH) 896 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH) 897 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH) 898 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH) 899 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH) 900 901 def test_format_enum_float(self): 902 Konstants = self.Konstants 903 self.assertFormatIsValue('{}', Konstants.TAU) 904 self.assertFormatIsValue('{:}', Konstants.TAU) 905 self.assertFormatIsValue('{:20}', Konstants.TAU) 906 self.assertFormatIsValue('{:^20}', Konstants.TAU) 907 self.assertFormatIsValue('{:>20}', Konstants.TAU) 908 self.assertFormatIsValue('{:<20}', Konstants.TAU) 909 self.assertFormatIsValue('{:n}', Konstants.TAU) 910 self.assertFormatIsValue('{:5.2}', Konstants.TAU) 911 self.assertFormatIsValue('{:f}', Konstants.TAU) 912 913 def test_format_enum_int(self): 914 class Grades(int, Enum): 915 A = 5 916 B = 4 917 C = 3 918 D = 2 919 F = 0 920 self.assertFormatIsValue('{}', Grades.C) 921 self.assertFormatIsValue('{:}', Grades.C) 922 self.assertFormatIsValue('{:20}', Grades.C) 923 self.assertFormatIsValue('{:^20}', Grades.C) 924 self.assertFormatIsValue('{:>20}', Grades.C) 925 self.assertFormatIsValue('{:<20}', Grades.C) 926 self.assertFormatIsValue('{:+}', Grades.C) 927 self.assertFormatIsValue('{:08X}', Grades.C) 928 self.assertFormatIsValue('{:b}', Grades.C) 929 930 def test_format_enum_str(self): 931 Directional = self.Directional 932 self.assertFormatIsValue('{}', Directional.WEST) 933 self.assertFormatIsValue('{:}', Directional.WEST) 934 self.assertFormatIsValue('{:20}', Directional.WEST) 935 self.assertFormatIsValue('{:^20}', Directional.WEST) 936 self.assertFormatIsValue('{:>20}', Directional.WEST) 937 self.assertFormatIsValue('{:<20}', Directional.WEST) 938 939 def test_object_str_override(self): 940 class Colors(Enum): 941 RED, GREEN, BLUE = 1, 2, 3 942 def __repr__(self): 943 return "test.%s" % (self._name_, ) 944 __str__ = object.__str__ 945 self.assertEqual(str(Colors.RED), 'test.RED') 946 947 def test_enum_str_override(self): 948 class MyStrEnum(Enum): 949 def __str__(self): 950 return 'MyStr' 951 class MyMethodEnum(Enum): 952 def hello(self): 953 return 'Hello! My name is %s' % self.name 954 class Test1Enum(MyMethodEnum, int, MyStrEnum): 955 One = 1 956 Two = 2 957 self.assertTrue(Test1Enum._member_type_ is int) 958 self.assertEqual(str(Test1Enum.One), 'MyStr') 959 self.assertEqual(format(Test1Enum.One, ''), 'MyStr') 960 # 961 class Test2Enum(MyStrEnum, MyMethodEnum): 962 One = 1 963 Two = 2 964 self.assertEqual(str(Test2Enum.One), 'MyStr') 965 self.assertEqual(format(Test1Enum.One, ''), 'MyStr') 966 967 def test_inherited_data_type(self): 968 class HexInt(int): 969 def __repr__(self): 970 return hex(self) 971 class MyEnum(HexInt, enum.Enum): 972 A = 1 973 B = 2 974 C = 3 975 def __repr__(self): 976 return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_) 977 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>') 978 # 979 class SillyInt(HexInt): 980 __qualname__ = 'SillyInt' 981 pass 982 class MyOtherEnum(SillyInt, enum.Enum): 983 __qualname__ = 'MyOtherEnum' 984 D = 4 985 E = 5 986 F = 6 987 self.assertIs(MyOtherEnum._member_type_, SillyInt) 988 globals()['SillyInt'] = SillyInt 989 globals()['MyOtherEnum'] = MyOtherEnum 990 test_pickle_dump_load(self.assertIs, MyOtherEnum.E) 991 test_pickle_dump_load(self.assertIs, MyOtherEnum) 992 # 993 # This did not work in 3.9, but does now with pickling by name 994 class UnBrokenInt(int): 995 __qualname__ = 'UnBrokenInt' 996 def __new__(cls, value): 997 return int.__new__(cls, value) 998 class MyUnBrokenEnum(UnBrokenInt, Enum): 999 __qualname__ = 'MyUnBrokenEnum' 1000 G = 7 1001 H = 8 1002 I = 9 1003 self.assertIs(MyUnBrokenEnum._member_type_, UnBrokenInt) 1004 self.assertIs(MyUnBrokenEnum(7), MyUnBrokenEnum.G) 1005 globals()['UnBrokenInt'] = UnBrokenInt 1006 globals()['MyUnBrokenEnum'] = MyUnBrokenEnum 1007 test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I) 1008 test_pickle_dump_load(self.assertIs, MyUnBrokenEnum) 1009 1010 def test_too_many_data_types(self): 1011 with self.assertRaisesRegex(TypeError, 'too many data types'): 1012 class Huh(str, int, Enum): 1013 One = 1 1014 1015 class MyStr(str): 1016 def hello(self): 1017 return 'hello, %s' % self 1018 class MyInt(int): 1019 def repr(self): 1020 return hex(self) 1021 with self.assertRaisesRegex(TypeError, 'too many data types'): 1022 class Huh(MyStr, MyInt, Enum): 1023 One = 1 1024 1025 def test_hash(self): 1026 Season = self.Season 1027 dates = {} 1028 dates[Season.WINTER] = '1225' 1029 dates[Season.SPRING] = '0315' 1030 dates[Season.SUMMER] = '0704' 1031 dates[Season.AUTUMN] = '1031' 1032 self.assertEqual(dates[Season.AUTUMN], '1031') 1033 1034 def test_intenum_from_scratch(self): 1035 class phy(int, Enum): 1036 pi = 3 1037 tau = 2 * pi 1038 self.assertTrue(phy.pi < phy.tau) 1039 1040 def test_intenum_inherited(self): 1041 class IntEnum(int, Enum): 1042 pass 1043 class phy(IntEnum): 1044 pi = 3 1045 tau = 2 * pi 1046 self.assertTrue(phy.pi < phy.tau) 1047 1048 def test_floatenum_from_scratch(self): 1049 class phy(float, Enum): 1050 pi = 3.1415926 1051 tau = 2 * pi 1052 self.assertTrue(phy.pi < phy.tau) 1053 1054 def test_floatenum_inherited(self): 1055 class FloatEnum(float, Enum): 1056 pass 1057 class phy(FloatEnum): 1058 pi = 3.1415926 1059 tau = 2 * pi 1060 self.assertTrue(phy.pi < phy.tau) 1061 1062 def test_strenum_from_scratch(self): 1063 class phy(str, Enum): 1064 pi = 'Pi' 1065 tau = 'Tau' 1066 self.assertTrue(phy.pi < phy.tau) 1067 1068 def test_strenum_inherited_methods(self): 1069 class phy(StrEnum): 1070 pi = 'Pi' 1071 tau = 'Tau' 1072 self.assertTrue(phy.pi < phy.tau) 1073 self.assertEqual(phy.pi.upper(), 'PI') 1074 self.assertEqual(phy.tau.count('a'), 1) 1075 1076 def test_intenum(self): 1077 class WeekDay(IntEnum): 1078 SUNDAY = 1 1079 MONDAY = 2 1080 TUESDAY = 3 1081 WEDNESDAY = 4 1082 THURSDAY = 5 1083 FRIDAY = 6 1084 SATURDAY = 7 1085 1086 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c') 1087 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2]) 1088 1089 lst = list(WeekDay) 1090 self.assertEqual(len(lst), len(WeekDay)) 1091 self.assertEqual(len(WeekDay), 7) 1092 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY' 1093 target = target.split() 1094 for i, weekday in enumerate(target, 1): 1095 e = WeekDay(i) 1096 self.assertEqual(e, i) 1097 self.assertEqual(int(e), i) 1098 self.assertEqual(e.name, weekday) 1099 self.assertIn(e, WeekDay) 1100 self.assertEqual(lst.index(e)+1, i) 1101 self.assertTrue(0 < e < 8) 1102 self.assertIs(type(e), WeekDay) 1103 self.assertIsInstance(e, int) 1104 self.assertIsInstance(e, Enum) 1105 1106 def test_intenum_duplicates(self): 1107 class WeekDay(IntEnum): 1108 SUNDAY = 1 1109 MONDAY = 2 1110 TUESDAY = TEUSDAY = 3 1111 WEDNESDAY = 4 1112 THURSDAY = 5 1113 FRIDAY = 6 1114 SATURDAY = 7 1115 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY) 1116 self.assertEqual(WeekDay(3).name, 'TUESDAY') 1117 self.assertEqual([k for k,v in WeekDay.__members__.items() 1118 if v.name != k], ['TEUSDAY', ]) 1119 1120 def test_intenum_from_bytes(self): 1121 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE) 1122 with self.assertRaises(ValueError): 1123 IntStooges.from_bytes(b'\x00\x05', 'big') 1124 1125 def test_floatenum_fromhex(self): 1126 h = float.hex(FloatStooges.MOE.value) 1127 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE) 1128 h = float.hex(FloatStooges.MOE.value + 0.01) 1129 with self.assertRaises(ValueError): 1130 FloatStooges.fromhex(h) 1131 1132 def test_pickle_enum(self): 1133 if isinstance(Stooges, Exception): 1134 raise Stooges 1135 test_pickle_dump_load(self.assertIs, Stooges.CURLY) 1136 test_pickle_dump_load(self.assertIs, Stooges) 1137 1138 def test_pickle_int(self): 1139 if isinstance(IntStooges, Exception): 1140 raise IntStooges 1141 test_pickle_dump_load(self.assertIs, IntStooges.CURLY) 1142 test_pickle_dump_load(self.assertIs, IntStooges) 1143 1144 def test_pickle_float(self): 1145 if isinstance(FloatStooges, Exception): 1146 raise FloatStooges 1147 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY) 1148 test_pickle_dump_load(self.assertIs, FloatStooges) 1149 1150 def test_pickle_enum_function(self): 1151 if isinstance(Answer, Exception): 1152 raise Answer 1153 test_pickle_dump_load(self.assertIs, Answer.him) 1154 test_pickle_dump_load(self.assertIs, Answer) 1155 1156 def test_pickle_enum_function_with_module(self): 1157 if isinstance(Question, Exception): 1158 raise Question 1159 test_pickle_dump_load(self.assertIs, Question.who) 1160 test_pickle_dump_load(self.assertIs, Question) 1161 1162 def test_enum_function_with_qualname(self): 1163 if isinstance(Theory, Exception): 1164 raise Theory 1165 self.assertEqual(Theory.__qualname__, 'spanish_inquisition') 1166 1167 def test_class_nested_enum_and_pickle_protocol_four(self): 1168 # would normally just have this directly in the class namespace 1169 class NestedEnum(Enum): 1170 twigs = 'common' 1171 shiny = 'rare' 1172 1173 self.__class__.NestedEnum = NestedEnum 1174 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__ 1175 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs) 1176 1177 def test_pickle_by_name(self): 1178 class ReplaceGlobalInt(IntEnum): 1179 ONE = 1 1180 TWO = 2 1181 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_global_name 1182 for proto in range(HIGHEST_PROTOCOL): 1183 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO') 1184 1185 def test_exploding_pickle(self): 1186 BadPickle = Enum( 1187 'BadPickle', 'dill sweet bread-n-butter', module=__name__) 1188 globals()['BadPickle'] = BadPickle 1189 # now break BadPickle to test exception raising 1190 enum._make_class_unpicklable(BadPickle) 1191 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill) 1192 test_pickle_exception(self.assertRaises, PicklingError, BadPickle) 1193 1194 def test_string_enum(self): 1195 class SkillLevel(str, Enum): 1196 master = 'what is the sound of one hand clapping?' 1197 journeyman = 'why did the chicken cross the road?' 1198 apprentice = 'knock, knock!' 1199 self.assertEqual(SkillLevel.apprentice, 'knock, knock!') 1200 1201 def test_getattr_getitem(self): 1202 class Period(Enum): 1203 morning = 1 1204 noon = 2 1205 evening = 3 1206 night = 4 1207 self.assertIs(Period(2), Period.noon) 1208 self.assertIs(getattr(Period, 'night'), Period.night) 1209 self.assertIs(Period['morning'], Period.morning) 1210 1211 def test_getattr_dunder(self): 1212 Season = self.Season 1213 self.assertTrue(getattr(Season, '__eq__')) 1214 1215 def test_iteration_order(self): 1216 class Season(Enum): 1217 SUMMER = 2 1218 WINTER = 4 1219 AUTUMN = 3 1220 SPRING = 1 1221 self.assertEqual( 1222 list(Season), 1223 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING], 1224 ) 1225 1226 def test_reversed_iteration_order(self): 1227 self.assertEqual( 1228 list(reversed(self.Season)), 1229 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER, 1230 self.Season.SPRING] 1231 ) 1232 1233 def test_programmatic_function_string(self): 1234 SummerMonth = Enum('SummerMonth', 'june july august') 1235 lst = list(SummerMonth) 1236 self.assertEqual(len(lst), len(SummerMonth)) 1237 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1238 self.assertEqual( 1239 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1240 lst, 1241 ) 1242 for i, month in enumerate('june july august'.split(), 1): 1243 e = SummerMonth(i) 1244 self.assertEqual(int(e.value), i) 1245 self.assertNotEqual(e, i) 1246 self.assertEqual(e.name, month) 1247 self.assertIn(e, SummerMonth) 1248 self.assertIs(type(e), SummerMonth) 1249 1250 def test_programmatic_function_string_with_start(self): 1251 SummerMonth = Enum('SummerMonth', 'june july august', start=10) 1252 lst = list(SummerMonth) 1253 self.assertEqual(len(lst), len(SummerMonth)) 1254 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1255 self.assertEqual( 1256 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1257 lst, 1258 ) 1259 for i, month in enumerate('june july august'.split(), 10): 1260 e = SummerMonth(i) 1261 self.assertEqual(int(e.value), i) 1262 self.assertNotEqual(e, i) 1263 self.assertEqual(e.name, month) 1264 self.assertIn(e, SummerMonth) 1265 self.assertIs(type(e), SummerMonth) 1266 1267 def test_programmatic_function_string_list(self): 1268 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august']) 1269 lst = list(SummerMonth) 1270 self.assertEqual(len(lst), len(SummerMonth)) 1271 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1272 self.assertEqual( 1273 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1274 lst, 1275 ) 1276 for i, month in enumerate('june july august'.split(), 1): 1277 e = SummerMonth(i) 1278 self.assertEqual(int(e.value), i) 1279 self.assertNotEqual(e, i) 1280 self.assertEqual(e.name, month) 1281 self.assertIn(e, SummerMonth) 1282 self.assertIs(type(e), SummerMonth) 1283 1284 def test_programmatic_function_string_list_with_start(self): 1285 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20) 1286 lst = list(SummerMonth) 1287 self.assertEqual(len(lst), len(SummerMonth)) 1288 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1289 self.assertEqual( 1290 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1291 lst, 1292 ) 1293 for i, month in enumerate('june july august'.split(), 20): 1294 e = SummerMonth(i) 1295 self.assertEqual(int(e.value), i) 1296 self.assertNotEqual(e, i) 1297 self.assertEqual(e.name, month) 1298 self.assertIn(e, SummerMonth) 1299 self.assertIs(type(e), SummerMonth) 1300 1301 def test_programmatic_function_iterable(self): 1302 SummerMonth = Enum( 1303 'SummerMonth', 1304 (('june', 1), ('july', 2), ('august', 3)) 1305 ) 1306 lst = list(SummerMonth) 1307 self.assertEqual(len(lst), len(SummerMonth)) 1308 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1309 self.assertEqual( 1310 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1311 lst, 1312 ) 1313 for i, month in enumerate('june july august'.split(), 1): 1314 e = SummerMonth(i) 1315 self.assertEqual(int(e.value), i) 1316 self.assertNotEqual(e, i) 1317 self.assertEqual(e.name, month) 1318 self.assertIn(e, SummerMonth) 1319 self.assertIs(type(e), SummerMonth) 1320 1321 def test_programmatic_function_from_dict(self): 1322 SummerMonth = Enum( 1323 'SummerMonth', 1324 OrderedDict((('june', 1), ('july', 2), ('august', 3))) 1325 ) 1326 lst = list(SummerMonth) 1327 self.assertEqual(len(lst), len(SummerMonth)) 1328 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1329 self.assertEqual( 1330 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1331 lst, 1332 ) 1333 for i, month in enumerate('june july august'.split(), 1): 1334 e = SummerMonth(i) 1335 self.assertEqual(int(e.value), i) 1336 self.assertNotEqual(e, i) 1337 self.assertEqual(e.name, month) 1338 self.assertIn(e, SummerMonth) 1339 self.assertIs(type(e), SummerMonth) 1340 1341 def test_programmatic_function_type(self): 1342 SummerMonth = Enum('SummerMonth', 'june july august', type=int) 1343 lst = list(SummerMonth) 1344 self.assertEqual(len(lst), len(SummerMonth)) 1345 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1346 self.assertEqual( 1347 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1348 lst, 1349 ) 1350 for i, month in enumerate('june july august'.split(), 1): 1351 e = SummerMonth(i) 1352 self.assertEqual(e, i) 1353 self.assertEqual(e.name, month) 1354 self.assertIn(e, SummerMonth) 1355 self.assertIs(type(e), SummerMonth) 1356 1357 def test_programmatic_function_type_with_start(self): 1358 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30) 1359 lst = list(SummerMonth) 1360 self.assertEqual(len(lst), len(SummerMonth)) 1361 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1362 self.assertEqual( 1363 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1364 lst, 1365 ) 1366 for i, month in enumerate('june july august'.split(), 30): 1367 e = SummerMonth(i) 1368 self.assertEqual(e, i) 1369 self.assertEqual(e.name, month) 1370 self.assertIn(e, SummerMonth) 1371 self.assertIs(type(e), SummerMonth) 1372 1373 def test_programmatic_function_type_from_subclass(self): 1374 SummerMonth = IntEnum('SummerMonth', 'june july august') 1375 lst = list(SummerMonth) 1376 self.assertEqual(len(lst), len(SummerMonth)) 1377 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1378 self.assertEqual( 1379 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1380 lst, 1381 ) 1382 for i, month in enumerate('june july august'.split(), 1): 1383 e = SummerMonth(i) 1384 self.assertEqual(e, i) 1385 self.assertEqual(e.name, month) 1386 self.assertIn(e, SummerMonth) 1387 self.assertIs(type(e), SummerMonth) 1388 1389 def test_programmatic_function_type_from_subclass_with_start(self): 1390 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40) 1391 lst = list(SummerMonth) 1392 self.assertEqual(len(lst), len(SummerMonth)) 1393 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1394 self.assertEqual( 1395 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1396 lst, 1397 ) 1398 for i, month in enumerate('june july august'.split(), 40): 1399 e = SummerMonth(i) 1400 self.assertEqual(e, i) 1401 self.assertEqual(e.name, month) 1402 self.assertIn(e, SummerMonth) 1403 self.assertIs(type(e), SummerMonth) 1404 1405 def test_subclassing(self): 1406 if isinstance(Name, Exception): 1407 raise Name 1408 self.assertEqual(Name.BDFL, 'Guido van Rossum') 1409 self.assertTrue(Name.BDFL, Name('Guido van Rossum')) 1410 self.assertIs(Name.BDFL, getattr(Name, 'BDFL')) 1411 test_pickle_dump_load(self.assertIs, Name.BDFL) 1412 1413 def test_extending(self): 1414 class Color(Enum): 1415 red = 1 1416 green = 2 1417 blue = 3 1418 with self.assertRaises(TypeError): 1419 class MoreColor(Color): 1420 cyan = 4 1421 magenta = 5 1422 yellow = 6 1423 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"): 1424 class EvenMoreColor(Color, IntEnum): 1425 chartruese = 7 1426 1427 def test_exclude_methods(self): 1428 class whatever(Enum): 1429 this = 'that' 1430 these = 'those' 1431 def really(self): 1432 return 'no, not %s' % self.value 1433 self.assertIsNot(type(whatever.really), whatever) 1434 self.assertEqual(whatever.this.really(), 'no, not that') 1435 1436 def test_wrong_inheritance_order(self): 1437 with self.assertRaises(TypeError): 1438 class Wrong(Enum, str): 1439 NotHere = 'error before this point' 1440 1441 def test_intenum_transitivity(self): 1442 class number(IntEnum): 1443 one = 1 1444 two = 2 1445 three = 3 1446 class numero(IntEnum): 1447 uno = 1 1448 dos = 2 1449 tres = 3 1450 self.assertEqual(number.one, numero.uno) 1451 self.assertEqual(number.two, numero.dos) 1452 self.assertEqual(number.three, numero.tres) 1453 1454 def test_wrong_enum_in_call(self): 1455 class Monochrome(Enum): 1456 black = 0 1457 white = 1 1458 class Gender(Enum): 1459 male = 0 1460 female = 1 1461 self.assertRaises(ValueError, Monochrome, Gender.male) 1462 1463 def test_wrong_enum_in_mixed_call(self): 1464 class Monochrome(IntEnum): 1465 black = 0 1466 white = 1 1467 class Gender(Enum): 1468 male = 0 1469 female = 1 1470 self.assertRaises(ValueError, Monochrome, Gender.male) 1471 1472 def test_mixed_enum_in_call_1(self): 1473 class Monochrome(IntEnum): 1474 black = 0 1475 white = 1 1476 class Gender(IntEnum): 1477 male = 0 1478 female = 1 1479 self.assertIs(Monochrome(Gender.female), Monochrome.white) 1480 1481 def test_mixed_enum_in_call_2(self): 1482 class Monochrome(Enum): 1483 black = 0 1484 white = 1 1485 class Gender(IntEnum): 1486 male = 0 1487 female = 1 1488 self.assertIs(Monochrome(Gender.male), Monochrome.black) 1489 1490 def test_flufl_enum(self): 1491 class Fluflnum(Enum): 1492 def __int__(self): 1493 return int(self.value) 1494 class MailManOptions(Fluflnum): 1495 option1 = 1 1496 option2 = 2 1497 option3 = 3 1498 self.assertEqual(int(MailManOptions.option1), 1) 1499 1500 def test_introspection(self): 1501 class Number(IntEnum): 1502 one = 100 1503 two = 200 1504 self.assertIs(Number.one._member_type_, int) 1505 self.assertIs(Number._member_type_, int) 1506 class String(str, Enum): 1507 yarn = 'soft' 1508 rope = 'rough' 1509 wire = 'hard' 1510 self.assertIs(String.yarn._member_type_, str) 1511 self.assertIs(String._member_type_, str) 1512 class Plain(Enum): 1513 vanilla = 'white' 1514 one = 1 1515 self.assertIs(Plain.vanilla._member_type_, object) 1516 self.assertIs(Plain._member_type_, object) 1517 1518 def test_no_such_enum_member(self): 1519 class Color(Enum): 1520 red = 1 1521 green = 2 1522 blue = 3 1523 with self.assertRaises(ValueError): 1524 Color(4) 1525 with self.assertRaises(KeyError): 1526 Color['chartreuse'] 1527 1528 def test_new_repr(self): 1529 class Color(Enum): 1530 red = 1 1531 green = 2 1532 blue = 3 1533 def __repr__(self): 1534 return "don't you just love shades of %s?" % self.name 1535 self.assertEqual( 1536 repr(Color.blue), 1537 "don't you just love shades of blue?", 1538 ) 1539 1540 def test_inherited_repr(self): 1541 class MyEnum(Enum): 1542 def __repr__(self): 1543 return "My name is %s." % self.name 1544 class MyIntEnum(int, MyEnum): 1545 this = 1 1546 that = 2 1547 theother = 3 1548 self.assertEqual(repr(MyIntEnum.that), "My name is that.") 1549 1550 def test_multiple_mixin_mro(self): 1551 class auto_enum(type(Enum)): 1552 def __new__(metacls, cls, bases, classdict): 1553 temp = type(classdict)() 1554 temp._cls_name = cls 1555 names = set(classdict._member_names) 1556 i = 0 1557 for k in classdict._member_names: 1558 v = classdict[k] 1559 if v is Ellipsis: 1560 v = i 1561 else: 1562 i = v 1563 i += 1 1564 temp[k] = v 1565 for k, v in classdict.items(): 1566 if k not in names: 1567 temp[k] = v 1568 return super(auto_enum, metacls).__new__( 1569 metacls, cls, bases, temp) 1570 1571 class AutoNumberedEnum(Enum, metaclass=auto_enum): 1572 pass 1573 1574 class AutoIntEnum(IntEnum, metaclass=auto_enum): 1575 pass 1576 1577 class TestAutoNumber(AutoNumberedEnum): 1578 a = ... 1579 b = 3 1580 c = ... 1581 1582 class TestAutoInt(AutoIntEnum): 1583 a = ... 1584 b = 3 1585 c = ... 1586 1587 def test_subclasses_with_getnewargs(self): 1588 class NamedInt(int): 1589 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1590 def __new__(cls, *args): 1591 _args = args 1592 name, *args = args 1593 if len(args) == 0: 1594 raise TypeError("name and value must be specified") 1595 self = int.__new__(cls, *args) 1596 self._intname = name 1597 self._args = _args 1598 return self 1599 def __getnewargs__(self): 1600 return self._args 1601 @property 1602 def __name__(self): 1603 return self._intname 1604 def __repr__(self): 1605 # repr() is updated to include the name and type info 1606 return "{}({!r}, {})".format( 1607 type(self).__name__, 1608 self.__name__, 1609 int.__repr__(self), 1610 ) 1611 def __str__(self): 1612 # str() is unchanged, even if it relies on the repr() fallback 1613 base = int 1614 base_str = base.__str__ 1615 if base_str.__objclass__ is object: 1616 return base.__repr__(self) 1617 return base_str(self) 1618 # for simplicity, we only define one operator that 1619 # propagates expressions 1620 def __add__(self, other): 1621 temp = int(self) + int( other) 1622 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1623 return NamedInt( 1624 '({0} + {1})'.format(self.__name__, other.__name__), 1625 temp, 1626 ) 1627 else: 1628 return temp 1629 1630 class NEI(NamedInt, Enum): 1631 __qualname__ = 'NEI' # needed for pickle protocol 4 1632 x = ('the-x', 1) 1633 y = ('the-y', 2) 1634 1635 1636 self.assertIs(NEI.__new__, Enum.__new__) 1637 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1638 globals()['NamedInt'] = NamedInt 1639 globals()['NEI'] = NEI 1640 NI5 = NamedInt('test', 5) 1641 self.assertEqual(NI5, 5) 1642 test_pickle_dump_load(self.assertEqual, NI5, 5) 1643 self.assertEqual(NEI.y.value, 2) 1644 test_pickle_dump_load(self.assertIs, NEI.y) 1645 test_pickle_dump_load(self.assertIs, NEI) 1646 1647 def test_subclasses_with_getnewargs_ex(self): 1648 class NamedInt(int): 1649 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1650 def __new__(cls, *args): 1651 _args = args 1652 name, *args = args 1653 if len(args) == 0: 1654 raise TypeError("name and value must be specified") 1655 self = int.__new__(cls, *args) 1656 self._intname = name 1657 self._args = _args 1658 return self 1659 def __getnewargs_ex__(self): 1660 return self._args, {} 1661 @property 1662 def __name__(self): 1663 return self._intname 1664 def __repr__(self): 1665 # repr() is updated to include the name and type info 1666 return "{}({!r}, {})".format( 1667 type(self).__name__, 1668 self.__name__, 1669 int.__repr__(self), 1670 ) 1671 def __str__(self): 1672 # str() is unchanged, even if it relies on the repr() fallback 1673 base = int 1674 base_str = base.__str__ 1675 if base_str.__objclass__ is object: 1676 return base.__repr__(self) 1677 return base_str(self) 1678 # for simplicity, we only define one operator that 1679 # propagates expressions 1680 def __add__(self, other): 1681 temp = int(self) + int( other) 1682 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1683 return NamedInt( 1684 '({0} + {1})'.format(self.__name__, other.__name__), 1685 temp, 1686 ) 1687 else: 1688 return temp 1689 1690 class NEI(NamedInt, Enum): 1691 __qualname__ = 'NEI' # needed for pickle protocol 4 1692 x = ('the-x', 1) 1693 y = ('the-y', 2) 1694 1695 1696 self.assertIs(NEI.__new__, Enum.__new__) 1697 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1698 globals()['NamedInt'] = NamedInt 1699 globals()['NEI'] = NEI 1700 NI5 = NamedInt('test', 5) 1701 self.assertEqual(NI5, 5) 1702 test_pickle_dump_load(self.assertEqual, NI5, 5) 1703 self.assertEqual(NEI.y.value, 2) 1704 test_pickle_dump_load(self.assertIs, NEI.y) 1705 test_pickle_dump_load(self.assertIs, NEI) 1706 1707 def test_subclasses_with_reduce(self): 1708 class NamedInt(int): 1709 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1710 def __new__(cls, *args): 1711 _args = args 1712 name, *args = args 1713 if len(args) == 0: 1714 raise TypeError("name and value must be specified") 1715 self = int.__new__(cls, *args) 1716 self._intname = name 1717 self._args = _args 1718 return self 1719 def __reduce__(self): 1720 return self.__class__, self._args 1721 @property 1722 def __name__(self): 1723 return self._intname 1724 def __repr__(self): 1725 # repr() is updated to include the name and type info 1726 return "{}({!r}, {})".format( 1727 type(self).__name__, 1728 self.__name__, 1729 int.__repr__(self), 1730 ) 1731 def __str__(self): 1732 # str() is unchanged, even if it relies on the repr() fallback 1733 base = int 1734 base_str = base.__str__ 1735 if base_str.__objclass__ is object: 1736 return base.__repr__(self) 1737 return base_str(self) 1738 # for simplicity, we only define one operator that 1739 # propagates expressions 1740 def __add__(self, other): 1741 temp = int(self) + int( other) 1742 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1743 return NamedInt( 1744 '({0} + {1})'.format(self.__name__, other.__name__), 1745 temp, 1746 ) 1747 else: 1748 return temp 1749 1750 class NEI(NamedInt, Enum): 1751 __qualname__ = 'NEI' # needed for pickle protocol 4 1752 x = ('the-x', 1) 1753 y = ('the-y', 2) 1754 1755 1756 self.assertIs(NEI.__new__, Enum.__new__) 1757 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1758 globals()['NamedInt'] = NamedInt 1759 globals()['NEI'] = NEI 1760 NI5 = NamedInt('test', 5) 1761 self.assertEqual(NI5, 5) 1762 test_pickle_dump_load(self.assertEqual, NI5, 5) 1763 self.assertEqual(NEI.y.value, 2) 1764 test_pickle_dump_load(self.assertIs, NEI.y) 1765 test_pickle_dump_load(self.assertIs, NEI) 1766 1767 def test_subclasses_with_reduce_ex(self): 1768 class NamedInt(int): 1769 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1770 def __new__(cls, *args): 1771 _args = args 1772 name, *args = args 1773 if len(args) == 0: 1774 raise TypeError("name and value must be specified") 1775 self = int.__new__(cls, *args) 1776 self._intname = name 1777 self._args = _args 1778 return self 1779 def __reduce_ex__(self, proto): 1780 return self.__class__, self._args 1781 @property 1782 def __name__(self): 1783 return self._intname 1784 def __repr__(self): 1785 # repr() is updated to include the name and type info 1786 return "{}({!r}, {})".format( 1787 type(self).__name__, 1788 self.__name__, 1789 int.__repr__(self), 1790 ) 1791 def __str__(self): 1792 # str() is unchanged, even if it relies on the repr() fallback 1793 base = int 1794 base_str = base.__str__ 1795 if base_str.__objclass__ is object: 1796 return base.__repr__(self) 1797 return base_str(self) 1798 # for simplicity, we only define one operator that 1799 # propagates expressions 1800 def __add__(self, other): 1801 temp = int(self) + int( other) 1802 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1803 return NamedInt( 1804 '({0} + {1})'.format(self.__name__, other.__name__), 1805 temp, 1806 ) 1807 else: 1808 return temp 1809 1810 class NEI(NamedInt, Enum): 1811 __qualname__ = 'NEI' # needed for pickle protocol 4 1812 x = ('the-x', 1) 1813 y = ('the-y', 2) 1814 1815 self.assertIs(NEI.__new__, Enum.__new__) 1816 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1817 globals()['NamedInt'] = NamedInt 1818 globals()['NEI'] = NEI 1819 NI5 = NamedInt('test', 5) 1820 self.assertEqual(NI5, 5) 1821 test_pickle_dump_load(self.assertEqual, NI5, 5) 1822 self.assertEqual(NEI.y.value, 2) 1823 test_pickle_dump_load(self.assertIs, NEI.y) 1824 test_pickle_dump_load(self.assertIs, NEI) 1825 1826 def test_subclasses_without_direct_pickle_support(self): 1827 class NamedInt(int): 1828 __qualname__ = 'NamedInt' 1829 def __new__(cls, *args): 1830 _args = args 1831 name, *args = args 1832 if len(args) == 0: 1833 raise TypeError("name and value must be specified") 1834 self = int.__new__(cls, *args) 1835 self._intname = name 1836 self._args = _args 1837 return self 1838 @property 1839 def __name__(self): 1840 return self._intname 1841 def __repr__(self): 1842 # repr() is updated to include the name and type info 1843 return "{}({!r}, {})".format( 1844 type(self).__name__, 1845 self.__name__, 1846 int.__repr__(self), 1847 ) 1848 def __str__(self): 1849 # str() is unchanged, even if it relies on the repr() fallback 1850 base = int 1851 base_str = base.__str__ 1852 if base_str.__objclass__ is object: 1853 return base.__repr__(self) 1854 return base_str(self) 1855 # for simplicity, we only define one operator that 1856 # propagates expressions 1857 def __add__(self, other): 1858 temp = int(self) + int( other) 1859 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1860 return NamedInt( 1861 '({0} + {1})'.format(self.__name__, other.__name__), 1862 temp ) 1863 else: 1864 return temp 1865 1866 class NEI(NamedInt, Enum): 1867 __qualname__ = 'NEI' 1868 x = ('the-x', 1) 1869 y = ('the-y', 2) 1870 1871 self.assertIs(NEI.__new__, Enum.__new__) 1872 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1873 globals()['NamedInt'] = NamedInt 1874 globals()['NEI'] = NEI 1875 NI5 = NamedInt('test', 5) 1876 self.assertEqual(NI5, 5) 1877 self.assertEqual(NEI.y.value, 2) 1878 test_pickle_dump_load(self.assertIs, NEI.y) 1879 test_pickle_dump_load(self.assertIs, NEI) 1880 1881 def test_subclasses_with_direct_pickle_support(self): 1882 class NamedInt(int): 1883 __qualname__ = 'NamedInt' 1884 def __new__(cls, *args): 1885 _args = args 1886 name, *args = args 1887 if len(args) == 0: 1888 raise TypeError("name and value must be specified") 1889 self = int.__new__(cls, *args) 1890 self._intname = name 1891 self._args = _args 1892 return self 1893 @property 1894 def __name__(self): 1895 return self._intname 1896 def __repr__(self): 1897 # repr() is updated to include the name and type info 1898 return "{}({!r}, {})".format( 1899 type(self).__name__, 1900 self.__name__, 1901 int.__repr__(self), 1902 ) 1903 def __str__(self): 1904 # str() is unchanged, even if it relies on the repr() fallback 1905 base = int 1906 base_str = base.__str__ 1907 if base_str.__objclass__ is object: 1908 return base.__repr__(self) 1909 return base_str(self) 1910 # for simplicity, we only define one operator that 1911 # propagates expressions 1912 def __add__(self, other): 1913 temp = int(self) + int( other) 1914 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1915 return NamedInt( 1916 '({0} + {1})'.format(self.__name__, other.__name__), 1917 temp, 1918 ) 1919 else: 1920 return temp 1921 1922 class NEI(NamedInt, Enum): 1923 __qualname__ = 'NEI' 1924 x = ('the-x', 1) 1925 y = ('the-y', 2) 1926 def __reduce_ex__(self, proto): 1927 return getattr, (self.__class__, self._name_) 1928 1929 self.assertIs(NEI.__new__, Enum.__new__) 1930 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1931 globals()['NamedInt'] = NamedInt 1932 globals()['NEI'] = NEI 1933 NI5 = NamedInt('test', 5) 1934 self.assertEqual(NI5, 5) 1935 self.assertEqual(NEI.y.value, 2) 1936 test_pickle_dump_load(self.assertIs, NEI.y) 1937 test_pickle_dump_load(self.assertIs, NEI) 1938 1939 def test_tuple_subclass(self): 1940 class SomeTuple(tuple, Enum): 1941 __qualname__ = 'SomeTuple' # needed for pickle protocol 4 1942 first = (1, 'for the money') 1943 second = (2, 'for the show') 1944 third = (3, 'for the music') 1945 self.assertIs(type(SomeTuple.first), SomeTuple) 1946 self.assertIsInstance(SomeTuple.second, tuple) 1947 self.assertEqual(SomeTuple.third, (3, 'for the music')) 1948 globals()['SomeTuple'] = SomeTuple 1949 test_pickle_dump_load(self.assertIs, SomeTuple.first) 1950 1951 def test_duplicate_values_give_unique_enum_items(self): 1952 class AutoNumber(Enum): 1953 first = () 1954 second = () 1955 third = () 1956 def __new__(cls): 1957 value = len(cls.__members__) + 1 1958 obj = object.__new__(cls) 1959 obj._value_ = value 1960 return obj 1961 def __int__(self): 1962 return int(self._value_) 1963 self.assertEqual( 1964 list(AutoNumber), 1965 [AutoNumber.first, AutoNumber.second, AutoNumber.third], 1966 ) 1967 self.assertEqual(int(AutoNumber.second), 2) 1968 self.assertEqual(AutoNumber.third.value, 3) 1969 self.assertIs(AutoNumber(1), AutoNumber.first) 1970 1971 def test_inherited_new_from_enhanced_enum(self): 1972 class AutoNumber(Enum): 1973 def __new__(cls): 1974 value = len(cls.__members__) + 1 1975 obj = object.__new__(cls) 1976 obj._value_ = value 1977 return obj 1978 def __int__(self): 1979 return int(self._value_) 1980 class Color(AutoNumber): 1981 red = () 1982 green = () 1983 blue = () 1984 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) 1985 self.assertEqual(list(map(int, Color)), [1, 2, 3]) 1986 1987 def test_inherited_new_from_mixed_enum(self): 1988 class AutoNumber(IntEnum): 1989 def __new__(cls): 1990 value = len(cls.__members__) + 1 1991 obj = int.__new__(cls, value) 1992 obj._value_ = value 1993 return obj 1994 class Color(AutoNumber): 1995 red = () 1996 green = () 1997 blue = () 1998 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) 1999 self.assertEqual(list(map(int, Color)), [1, 2, 3]) 2000 2001 def test_equality(self): 2002 class OrdinaryEnum(Enum): 2003 a = 1 2004 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a) 2005 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ) 2006 2007 def test_ordered_mixin(self): 2008 class OrderedEnum(Enum): 2009 def __ge__(self, other): 2010 if self.__class__ is other.__class__: 2011 return self._value_ >= other._value_ 2012 return NotImplemented 2013 def __gt__(self, other): 2014 if self.__class__ is other.__class__: 2015 return self._value_ > other._value_ 2016 return NotImplemented 2017 def __le__(self, other): 2018 if self.__class__ is other.__class__: 2019 return self._value_ <= other._value_ 2020 return NotImplemented 2021 def __lt__(self, other): 2022 if self.__class__ is other.__class__: 2023 return self._value_ < other._value_ 2024 return NotImplemented 2025 class Grade(OrderedEnum): 2026 A = 5 2027 B = 4 2028 C = 3 2029 D = 2 2030 F = 1 2031 self.assertGreater(Grade.A, Grade.B) 2032 self.assertLessEqual(Grade.F, Grade.C) 2033 self.assertLess(Grade.D, Grade.A) 2034 self.assertGreaterEqual(Grade.B, Grade.B) 2035 self.assertEqual(Grade.B, Grade.B) 2036 self.assertNotEqual(Grade.C, Grade.D) 2037 2038 def test_extending2(self): 2039 class Shade(Enum): 2040 def shade(self): 2041 print(self.name) 2042 class Color(Shade): 2043 red = 1 2044 green = 2 2045 blue = 3 2046 with self.assertRaises(TypeError): 2047 class MoreColor(Color): 2048 cyan = 4 2049 magenta = 5 2050 yellow = 6 2051 2052 def test_extending3(self): 2053 class Shade(Enum): 2054 def shade(self): 2055 return self.name 2056 class Color(Shade): 2057 def hex(self): 2058 return '%s hexlified!' % self.value 2059 class MoreColor(Color): 2060 cyan = 4 2061 magenta = 5 2062 yellow = 6 2063 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!') 2064 2065 def test_subclass_duplicate_name(self): 2066 class Base(Enum): 2067 def test(self): 2068 pass 2069 class Test(Base): 2070 test = 1 2071 self.assertIs(type(Test.test), Test) 2072 2073 def test_subclass_duplicate_name_dynamic(self): 2074 from types import DynamicClassAttribute 2075 class Base(Enum): 2076 @DynamicClassAttribute 2077 def test(self): 2078 return 'dynamic' 2079 class Test(Base): 2080 test = 1 2081 self.assertEqual(Test.test.test, 'dynamic') 2082 class Base2(Enum): 2083 @enum.property 2084 def flash(self): 2085 return 'flashy dynamic' 2086 class Test(Base2): 2087 flash = 1 2088 self.assertEqual(Test.flash.flash, 'flashy dynamic') 2089 2090 def test_no_duplicates(self): 2091 class UniqueEnum(Enum): 2092 def __init__(self, *args): 2093 cls = self.__class__ 2094 if any(self.value == e.value for e in cls): 2095 a = self.name 2096 e = cls(self.value).name 2097 raise ValueError( 2098 "aliases not allowed in UniqueEnum: %r --> %r" 2099 % (a, e) 2100 ) 2101 class Color(UniqueEnum): 2102 red = 1 2103 green = 2 2104 blue = 3 2105 with self.assertRaises(ValueError): 2106 class Color(UniqueEnum): 2107 red = 1 2108 green = 2 2109 blue = 3 2110 grene = 2 2111 2112 def test_init(self): 2113 class Planet(Enum): 2114 MERCURY = (3.303e+23, 2.4397e6) 2115 VENUS = (4.869e+24, 6.0518e6) 2116 EARTH = (5.976e+24, 6.37814e6) 2117 MARS = (6.421e+23, 3.3972e6) 2118 JUPITER = (1.9e+27, 7.1492e7) 2119 SATURN = (5.688e+26, 6.0268e7) 2120 URANUS = (8.686e+25, 2.5559e7) 2121 NEPTUNE = (1.024e+26, 2.4746e7) 2122 def __init__(self, mass, radius): 2123 self.mass = mass # in kilograms 2124 self.radius = radius # in meters 2125 @property 2126 def surface_gravity(self): 2127 # universal gravitational constant (m3 kg-1 s-2) 2128 G = 6.67300E-11 2129 return G * self.mass / (self.radius * self.radius) 2130 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80) 2131 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6)) 2132 2133 def test_ignore(self): 2134 class Period(timedelta, Enum): 2135 ''' 2136 different lengths of time 2137 ''' 2138 def __new__(cls, value, period): 2139 obj = timedelta.__new__(cls, value) 2140 obj._value_ = value 2141 obj.period = period 2142 return obj 2143 _ignore_ = 'Period i' 2144 Period = vars() 2145 for i in range(13): 2146 Period['month_%d' % i] = i*30, 'month' 2147 for i in range(53): 2148 Period['week_%d' % i] = i*7, 'week' 2149 for i in range(32): 2150 Period['day_%d' % i] = i, 'day' 2151 OneDay = day_1 2152 OneWeek = week_1 2153 OneMonth = month_1 2154 self.assertFalse(hasattr(Period, '_ignore_')) 2155 self.assertFalse(hasattr(Period, 'Period')) 2156 self.assertFalse(hasattr(Period, 'i')) 2157 self.assertTrue(isinstance(Period.day_1, timedelta)) 2158 self.assertTrue(Period.month_1 is Period.day_30) 2159 self.assertTrue(Period.week_4 is Period.day_28) 2160 2161 def test_nonhash_value(self): 2162 class AutoNumberInAList(Enum): 2163 def __new__(cls): 2164 value = [len(cls.__members__) + 1] 2165 obj = object.__new__(cls) 2166 obj._value_ = value 2167 return obj 2168 class ColorInAList(AutoNumberInAList): 2169 red = () 2170 green = () 2171 blue = () 2172 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue]) 2173 for enum, value in zip(ColorInAList, range(3)): 2174 value += 1 2175 self.assertEqual(enum.value, [value]) 2176 self.assertIs(ColorInAList([value]), enum) 2177 2178 def test_conflicting_types_resolved_in_new(self): 2179 class LabelledIntEnum(int, Enum): 2180 def __new__(cls, *args): 2181 value, label = args 2182 obj = int.__new__(cls, value) 2183 obj.label = label 2184 obj._value_ = value 2185 return obj 2186 2187 class LabelledList(LabelledIntEnum): 2188 unprocessed = (1, "Unprocessed") 2189 payment_complete = (2, "Payment Complete") 2190 2191 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete]) 2192 self.assertEqual(LabelledList.unprocessed, 1) 2193 self.assertEqual(LabelledList(1), LabelledList.unprocessed) 2194 2195 def test_auto_number(self): 2196 class Color(Enum): 2197 red = auto() 2198 blue = auto() 2199 green = auto() 2200 2201 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 2202 self.assertEqual(Color.red.value, 1) 2203 self.assertEqual(Color.blue.value, 2) 2204 self.assertEqual(Color.green.value, 3) 2205 2206 def test_auto_name(self): 2207 class Color(Enum): 2208 def _generate_next_value_(name, start, count, last): 2209 return name 2210 red = auto() 2211 blue = auto() 2212 green = auto() 2213 2214 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 2215 self.assertEqual(Color.red.value, 'red') 2216 self.assertEqual(Color.blue.value, 'blue') 2217 self.assertEqual(Color.green.value, 'green') 2218 2219 def test_auto_name_inherit(self): 2220 class AutoNameEnum(Enum): 2221 def _generate_next_value_(name, start, count, last): 2222 return name 2223 class Color(AutoNameEnum): 2224 red = auto() 2225 blue = auto() 2226 green = auto() 2227 2228 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 2229 self.assertEqual(Color.red.value, 'red') 2230 self.assertEqual(Color.blue.value, 'blue') 2231 self.assertEqual(Color.green.value, 'green') 2232 2233 def test_auto_garbage(self): 2234 class Color(Enum): 2235 red = 'red' 2236 blue = auto() 2237 self.assertEqual(Color.blue.value, 1) 2238 2239 def test_auto_garbage_corrected(self): 2240 class Color(Enum): 2241 red = 'red' 2242 blue = 2 2243 green = auto() 2244 2245 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 2246 self.assertEqual(Color.red.value, 'red') 2247 self.assertEqual(Color.blue.value, 2) 2248 self.assertEqual(Color.green.value, 3) 2249 2250 def test_auto_order(self): 2251 with self.assertRaises(TypeError): 2252 class Color(Enum): 2253 red = auto() 2254 green = auto() 2255 blue = auto() 2256 def _generate_next_value_(name, start, count, last): 2257 return name 2258 2259 def test_auto_order_wierd(self): 2260 weird_auto = auto() 2261 weird_auto.value = 'pathological case' 2262 class Color(Enum): 2263 red = weird_auto 2264 def _generate_next_value_(name, start, count, last): 2265 return name 2266 blue = auto() 2267 self.assertEqual(list(Color), [Color.red, Color.blue]) 2268 self.assertEqual(Color.red.value, 'pathological case') 2269 self.assertEqual(Color.blue.value, 'blue') 2270 2271 def test_duplicate_auto(self): 2272 class Dupes(Enum): 2273 first = primero = auto() 2274 second = auto() 2275 third = auto() 2276 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) 2277 2278 def test_default_missing(self): 2279 class Color(Enum): 2280 RED = 1 2281 GREEN = 2 2282 BLUE = 3 2283 try: 2284 Color(7) 2285 except ValueError as exc: 2286 self.assertTrue(exc.__context__ is None) 2287 else: 2288 raise Exception('Exception not raised.') 2289 2290 def test_missing(self): 2291 class Color(Enum): 2292 red = 1 2293 green = 2 2294 blue = 3 2295 @classmethod 2296 def _missing_(cls, item): 2297 if item == 'three': 2298 return cls.blue 2299 elif item == 'bad return': 2300 # trigger internal error 2301 return 5 2302 elif item == 'error out': 2303 raise ZeroDivisionError 2304 else: 2305 # trigger not found 2306 return None 2307 self.assertIs(Color('three'), Color.blue) 2308 try: 2309 Color(7) 2310 except ValueError as exc: 2311 self.assertTrue(exc.__context__ is None) 2312 else: 2313 raise Exception('Exception not raised.') 2314 try: 2315 Color('bad return') 2316 except TypeError as exc: 2317 self.assertTrue(isinstance(exc.__context__, ValueError)) 2318 else: 2319 raise Exception('Exception not raised.') 2320 try: 2321 Color('error out') 2322 except ZeroDivisionError as exc: 2323 self.assertTrue(isinstance(exc.__context__, ValueError)) 2324 else: 2325 raise Exception('Exception not raised.') 2326 2327 def test_missing_exceptions_reset(self): 2328 import gc 2329 import weakref 2330 # 2331 class TestEnum(enum.Enum): 2332 VAL1 = 'val1' 2333 VAL2 = 'val2' 2334 # 2335 class Class1: 2336 def __init__(self): 2337 # Gracefully handle an exception of our own making 2338 try: 2339 raise ValueError() 2340 except ValueError: 2341 pass 2342 # 2343 class Class2: 2344 def __init__(self): 2345 # Gracefully handle an exception of Enum's making 2346 try: 2347 TestEnum('invalid_value') 2348 except ValueError: 2349 pass 2350 # No strong refs here so these are free to die. 2351 class_1_ref = weakref.ref(Class1()) 2352 class_2_ref = weakref.ref(Class2()) 2353 # 2354 # The exception raised by Enum creates a reference loop and thus 2355 # Class2 instances will stick around until the next garbage collection 2356 # cycle, unlike Class1. 2357 gc.collect() # For PyPy or other GCs. 2358 self.assertIs(class_1_ref(), None) 2359 self.assertIs(class_2_ref(), None) 2360 2361 def test_multiple_mixin(self): 2362 class MaxMixin: 2363 @classproperty 2364 def MAX(cls): 2365 max = len(cls) 2366 cls.MAX = max 2367 return max 2368 class StrMixin: 2369 def __str__(self): 2370 return self._name_.lower() 2371 class SomeEnum(Enum): 2372 def behavior(self): 2373 return 'booyah' 2374 class AnotherEnum(Enum): 2375 def behavior(self): 2376 return 'nuhuh!' 2377 def social(self): 2378 return "what's up?" 2379 class Color(MaxMixin, Enum): 2380 RED = auto() 2381 GREEN = auto() 2382 BLUE = auto() 2383 self.assertEqual(Color.RED.value, 1) 2384 self.assertEqual(Color.GREEN.value, 2) 2385 self.assertEqual(Color.BLUE.value, 3) 2386 self.assertEqual(Color.MAX, 3) 2387 self.assertEqual(str(Color.BLUE), 'BLUE') 2388 class Color(MaxMixin, StrMixin, Enum): 2389 RED = auto() 2390 GREEN = auto() 2391 BLUE = auto() 2392 self.assertEqual(Color.RED.value, 1) 2393 self.assertEqual(Color.GREEN.value, 2) 2394 self.assertEqual(Color.BLUE.value, 3) 2395 self.assertEqual(Color.MAX, 3) 2396 self.assertEqual(str(Color.BLUE), 'blue') 2397 class Color(StrMixin, MaxMixin, Enum): 2398 RED = auto() 2399 GREEN = auto() 2400 BLUE = auto() 2401 self.assertEqual(Color.RED.value, 1) 2402 self.assertEqual(Color.GREEN.value, 2) 2403 self.assertEqual(Color.BLUE.value, 3) 2404 self.assertEqual(Color.MAX, 3) 2405 self.assertEqual(str(Color.BLUE), 'blue') 2406 class CoolColor(StrMixin, SomeEnum, Enum): 2407 RED = auto() 2408 GREEN = auto() 2409 BLUE = auto() 2410 self.assertEqual(CoolColor.RED.value, 1) 2411 self.assertEqual(CoolColor.GREEN.value, 2) 2412 self.assertEqual(CoolColor.BLUE.value, 3) 2413 self.assertEqual(str(CoolColor.BLUE), 'blue') 2414 self.assertEqual(CoolColor.RED.behavior(), 'booyah') 2415 class CoolerColor(StrMixin, AnotherEnum, Enum): 2416 RED = auto() 2417 GREEN = auto() 2418 BLUE = auto() 2419 self.assertEqual(CoolerColor.RED.value, 1) 2420 self.assertEqual(CoolerColor.GREEN.value, 2) 2421 self.assertEqual(CoolerColor.BLUE.value, 3) 2422 self.assertEqual(str(CoolerColor.BLUE), 'blue') 2423 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!') 2424 self.assertEqual(CoolerColor.RED.social(), "what's up?") 2425 class CoolestColor(StrMixin, SomeEnum, AnotherEnum): 2426 RED = auto() 2427 GREEN = auto() 2428 BLUE = auto() 2429 self.assertEqual(CoolestColor.RED.value, 1) 2430 self.assertEqual(CoolestColor.GREEN.value, 2) 2431 self.assertEqual(CoolestColor.BLUE.value, 3) 2432 self.assertEqual(str(CoolestColor.BLUE), 'blue') 2433 self.assertEqual(CoolestColor.RED.behavior(), 'booyah') 2434 self.assertEqual(CoolestColor.RED.social(), "what's up?") 2435 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum): 2436 RED = auto() 2437 GREEN = auto() 2438 BLUE = auto() 2439 self.assertEqual(ConfusedColor.RED.value, 1) 2440 self.assertEqual(ConfusedColor.GREEN.value, 2) 2441 self.assertEqual(ConfusedColor.BLUE.value, 3) 2442 self.assertEqual(str(ConfusedColor.BLUE), 'blue') 2443 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!') 2444 self.assertEqual(ConfusedColor.RED.social(), "what's up?") 2445 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum): 2446 RED = auto() 2447 GREEN = auto() 2448 BLUE = auto() 2449 self.assertEqual(ReformedColor.RED.value, 1) 2450 self.assertEqual(ReformedColor.GREEN.value, 2) 2451 self.assertEqual(ReformedColor.BLUE.value, 3) 2452 self.assertEqual(str(ReformedColor.BLUE), 'blue') 2453 self.assertEqual(ReformedColor.RED.behavior(), 'booyah') 2454 self.assertEqual(ConfusedColor.RED.social(), "what's up?") 2455 self.assertTrue(issubclass(ReformedColor, int)) 2456 2457 def test_multiple_inherited_mixin(self): 2458 @unique 2459 class Decision1(StrEnum): 2460 REVERT = "REVERT" 2461 REVERT_ALL = "REVERT_ALL" 2462 RETRY = "RETRY" 2463 class MyEnum(StrEnum): 2464 pass 2465 @unique 2466 class Decision2(MyEnum): 2467 REVERT = "REVERT" 2468 REVERT_ALL = "REVERT_ALL" 2469 RETRY = "RETRY" 2470 2471 def test_multiple_mixin_inherited(self): 2472 class MyInt(int): 2473 def __new__(cls, value): 2474 return super().__new__(cls, value) 2475 2476 class HexMixin: 2477 def __repr__(self): 2478 return hex(self) 2479 2480 class MyIntEnum(HexMixin, MyInt, enum.Enum): 2481 pass 2482 2483 class Foo(MyIntEnum): 2484 TEST = 1 2485 self.assertTrue(isinstance(Foo.TEST, MyInt)) 2486 self.assertEqual(repr(Foo.TEST), "0x1") 2487 2488 class Fee(MyIntEnum): 2489 TEST = 1 2490 def __new__(cls, value): 2491 value += 1 2492 member = int.__new__(cls, value) 2493 member._value_ = value 2494 return member 2495 self.assertEqual(Fee.TEST, 2) 2496 2497 def test_miltuple_mixin_with_common_data_type(self): 2498 class CaseInsensitiveStrEnum(str, Enum): 2499 @classmethod 2500 def _missing_(cls, value): 2501 for member in cls._member_map_.values(): 2502 if member._value_.lower() == value.lower(): 2503 return member 2504 return super()._missing_(value) 2505 # 2506 class LenientStrEnum(str, Enum): 2507 def __init__(self, *args): 2508 self._valid = True 2509 @classmethod 2510 def _missing_(cls, value): 2511 unknown = cls._member_type_.__new__(cls, value) 2512 unknown._valid = False 2513 unknown._name_ = value.upper() 2514 unknown._value_ = value 2515 cls._member_map_[value] = unknown 2516 return unknown 2517 @property 2518 def valid(self): 2519 return self._valid 2520 # 2521 class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum): 2522 ACTIVE = "active" 2523 PENDING = "pending" 2524 TERMINATED = "terminated" 2525 # 2526 JS = JobStatus 2527 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED]) 2528 self.assertEqual(JS.ACTIVE, 'active') 2529 self.assertEqual(JS.ACTIVE.value, 'active') 2530 self.assertIs(JS('Active'), JS.ACTIVE) 2531 self.assertTrue(JS.ACTIVE.valid) 2532 missing = JS('missing') 2533 self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED]) 2534 self.assertEqual(JS.ACTIVE, 'active') 2535 self.assertEqual(JS.ACTIVE.value, 'active') 2536 self.assertIs(JS('Active'), JS.ACTIVE) 2537 self.assertTrue(JS.ACTIVE.valid) 2538 self.assertTrue(isinstance(missing, JS)) 2539 self.assertFalse(missing.valid) 2540 2541 def test_empty_globals(self): 2542 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError 2543 # when using compile and exec because f_globals is empty 2544 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')" 2545 code = compile(code, "<string>", "exec") 2546 global_ns = {} 2547 local_ls = {} 2548 exec(code, global_ns, local_ls) 2549 2550 def test_strenum(self): 2551 class GoodStrEnum(StrEnum): 2552 one = '1' 2553 two = '2' 2554 three = b'3', 'ascii' 2555 four = b'4', 'latin1', 'strict' 2556 self.assertEqual(GoodStrEnum.one, '1') 2557 self.assertEqual(str(GoodStrEnum.one), '1') 2558 self.assertEqual('{}'.format(GoodStrEnum.one), '1') 2559 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one)) 2560 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one)) 2561 self.assertEqual(repr(GoodStrEnum.one), 'GoodStrEnum.one') 2562 # 2563 class DumbMixin: 2564 def __str__(self): 2565 return "don't do this" 2566 class DumbStrEnum(DumbMixin, StrEnum): 2567 five = '5' 2568 six = '6' 2569 seven = '7' 2570 self.assertEqual(DumbStrEnum.seven, '7') 2571 self.assertEqual(str(DumbStrEnum.seven), "don't do this") 2572 # 2573 class EnumMixin(Enum): 2574 def hello(self): 2575 print('hello from %s' % (self, )) 2576 class HelloEnum(EnumMixin, StrEnum): 2577 eight = '8' 2578 self.assertEqual(HelloEnum.eight, '8') 2579 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight)) 2580 # 2581 class GoodbyeMixin: 2582 def goodbye(self): 2583 print('%s wishes you a fond farewell') 2584 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum): 2585 nine = '9' 2586 self.assertEqual(GoodbyeEnum.nine, '9') 2587 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine)) 2588 # 2589 with self.assertRaisesRegex(TypeError, '1 is not a string'): 2590 class FirstFailedStrEnum(StrEnum): 2591 one = 1 2592 two = '2' 2593 with self.assertRaisesRegex(TypeError, "2 is not a string"): 2594 class SecondFailedStrEnum(StrEnum): 2595 one = '1' 2596 two = 2, 2597 three = '3' 2598 with self.assertRaisesRegex(TypeError, '2 is not a string'): 2599 class ThirdFailedStrEnum(StrEnum): 2600 one = '1' 2601 two = 2 2602 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )): 2603 class ThirdFailedStrEnum(StrEnum): 2604 one = '1' 2605 two = b'2', sys.getdefaultencoding 2606 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'): 2607 class ThirdFailedStrEnum(StrEnum): 2608 one = '1' 2609 two = b'2', 'ascii', 9 2610 2611 @unittest.skipIf( 2612 python_version >= (3, 12), 2613 'mixin-format now uses member instead of member.value', 2614 ) 2615 def test_custom_strenum_with_warning(self): 2616 class CustomStrEnum(str, Enum): 2617 pass 2618 class OkayEnum(CustomStrEnum): 2619 one = '1' 2620 two = '2' 2621 three = b'3', 'ascii' 2622 four = b'4', 'latin1', 'strict' 2623 self.assertEqual(OkayEnum.one, '1') 2624 self.assertEqual(str(OkayEnum.one), 'one') 2625 with self.assertWarns(DeprecationWarning): 2626 self.assertEqual('{}'.format(OkayEnum.one), '1') 2627 self.assertEqual(OkayEnum.one, '{}'.format(OkayEnum.one)) 2628 self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one') 2629 # 2630 class DumbMixin: 2631 def __str__(self): 2632 return "don't do this" 2633 class DumbStrEnum(DumbMixin, CustomStrEnum): 2634 five = '5' 2635 six = '6' 2636 seven = '7' 2637 self.assertEqual(DumbStrEnum.seven, '7') 2638 self.assertEqual(str(DumbStrEnum.seven), "don't do this") 2639 # 2640 class EnumMixin(Enum): 2641 def hello(self): 2642 print('hello from %s' % (self, )) 2643 class HelloEnum(EnumMixin, CustomStrEnum): 2644 eight = '8' 2645 self.assertEqual(HelloEnum.eight, '8') 2646 self.assertEqual(str(HelloEnum.eight), 'eight') 2647 # 2648 class GoodbyeMixin: 2649 def goodbye(self): 2650 print('%s wishes you a fond farewell') 2651 class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum): 2652 nine = '9' 2653 self.assertEqual(GoodbyeEnum.nine, '9') 2654 self.assertEqual(str(GoodbyeEnum.nine), 'nine') 2655 # 2656 class FirstFailedStrEnum(CustomStrEnum): 2657 one = 1 # this will become '1' 2658 two = '2' 2659 class SecondFailedStrEnum(CustomStrEnum): 2660 one = '1' 2661 two = 2, # this will become '2' 2662 three = '3' 2663 class ThirdFailedStrEnum(CustomStrEnum): 2664 one = '1' 2665 two = 2 # this will become '2' 2666 with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '): 2667 class ThirdFailedStrEnum(CustomStrEnum): 2668 one = '1' 2669 two = b'2', sys.getdefaultencoding 2670 with self.assertRaisesRegex(TypeError, '.errors. must be str, not '): 2671 class ThirdFailedStrEnum(CustomStrEnum): 2672 one = '1' 2673 two = b'2', 'ascii', 9 2674 2675 @unittest.skipIf( 2676 python_version < (3, 12), 2677 'mixin-format currently uses member.value', 2678 ) 2679 def test_custom_strenum(self): 2680 class CustomStrEnum(str, Enum): 2681 pass 2682 class OkayEnum(CustomStrEnum): 2683 one = '1' 2684 two = '2' 2685 three = b'3', 'ascii' 2686 four = b'4', 'latin1', 'strict' 2687 self.assertEqual(OkayEnum.one, '1') 2688 self.assertEqual(str(OkayEnum.one), 'one') 2689 self.assertEqual('{}'.format(OkayEnum.one), 'one') 2690 self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one') 2691 # 2692 class DumbMixin: 2693 def __str__(self): 2694 return "don't do this" 2695 class DumbStrEnum(DumbMixin, CustomStrEnum): 2696 five = '5' 2697 six = '6' 2698 seven = '7' 2699 self.assertEqual(DumbStrEnum.seven, '7') 2700 self.assertEqual(str(DumbStrEnum.seven), "don't do this") 2701 # 2702 class EnumMixin(Enum): 2703 def hello(self): 2704 print('hello from %s' % (self, )) 2705 class HelloEnum(EnumMixin, CustomStrEnum): 2706 eight = '8' 2707 self.assertEqual(HelloEnum.eight, '8') 2708 self.assertEqual(str(HelloEnum.eight), 'eight') 2709 # 2710 class GoodbyeMixin: 2711 def goodbye(self): 2712 print('%s wishes you a fond farewell') 2713 class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum): 2714 nine = '9' 2715 self.assertEqual(GoodbyeEnum.nine, '9') 2716 self.assertEqual(str(GoodbyeEnum.nine), 'nine') 2717 # 2718 class FirstFailedStrEnum(CustomStrEnum): 2719 one = 1 # this will become '1' 2720 two = '2' 2721 class SecondFailedStrEnum(CustomStrEnum): 2722 one = '1' 2723 two = 2, # this will become '2' 2724 three = '3' 2725 class ThirdFailedStrEnum(CustomStrEnum): 2726 one = '1' 2727 two = 2 # this will become '2' 2728 with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '): 2729 class ThirdFailedStrEnum(CustomStrEnum): 2730 one = '1' 2731 two = b'2', sys.getdefaultencoding 2732 with self.assertRaisesRegex(TypeError, '.errors. must be str, not '): 2733 class ThirdFailedStrEnum(CustomStrEnum): 2734 one = '1' 2735 two = b'2', 'ascii', 9 2736 2737 def test_missing_value_error(self): 2738 with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"): 2739 class Combined(str, Enum): 2740 # 2741 def __new__(cls, value, sequence): 2742 enum = str.__new__(cls, value) 2743 if '(' in value: 2744 fis_name, segment = value.split('(', 1) 2745 segment = segment.strip(' )') 2746 else: 2747 fis_name = value 2748 segment = None 2749 enum.fis_name = fis_name 2750 enum.segment = segment 2751 enum.sequence = sequence 2752 return enum 2753 # 2754 def __repr__(self): 2755 return "<%s.%s>" % (self.__class__.__name__, self._name_) 2756 # 2757 key_type = 'An$(1,2)', 0 2758 company_id = 'An$(3,2)', 1 2759 code = 'An$(5,1)', 2 2760 description = 'Bn$', 3 2761 2762 @unittest.skipUnless( 2763 python_version == (3, 9), 2764 'private variables are now normal attributes', 2765 ) 2766 def test_warning_for_private_variables(self): 2767 with self.assertWarns(DeprecationWarning): 2768 class Private(Enum): 2769 __corporal = 'Radar' 2770 self.assertEqual(Private._Private__corporal.value, 'Radar') 2771 try: 2772 with self.assertWarns(DeprecationWarning): 2773 class Private(Enum): 2774 __major_ = 'Hoolihan' 2775 except ValueError: 2776 pass 2777 2778 def test_private_variable_is_normal_attribute(self): 2779 class Private(Enum): 2780 __corporal = 'Radar' 2781 __major_ = 'Hoolihan' 2782 self.assertEqual(Private._Private__corporal, 'Radar') 2783 self.assertEqual(Private._Private__major_, 'Hoolihan') 2784 2785 @unittest.skipUnless( 2786 python_version < (3, 12), 2787 'member-member access now raises an exception', 2788 ) 2789 def test_warning_for_member_from_member_access(self): 2790 with self.assertWarns(DeprecationWarning): 2791 class Di(Enum): 2792 YES = 1 2793 NO = 0 2794 nope = Di.YES.NO 2795 self.assertIs(Di.NO, nope) 2796 2797 @unittest.skipUnless( 2798 python_version >= (3, 12), 2799 'member-member access currently issues a warning', 2800 ) 2801 def test_exception_for_member_from_member_access(self): 2802 with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."): 2803 class Di(Enum): 2804 YES = 1 2805 NO = 0 2806 nope = Di.YES.NO 2807 2808 def test_strenum_auto(self): 2809 class Strings(StrEnum): 2810 ONE = auto() 2811 TWO = auto() 2812 self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two']) 2813 2814 2815 def test_dynamic_members_with_static_methods(self): 2816 # 2817 foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'} 2818 class Foo(Enum): 2819 vars().update({ 2820 k: v 2821 for k, v in foo_defines.items() 2822 if k.startswith('FOO_') 2823 }) 2824 def upper(self): 2825 return self.value.upper() 2826 self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE]) 2827 self.assertEqual(Foo.FOO_CAT.value, 'aloof') 2828 self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG') 2829 # 2830 with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"): 2831 class FooBar(Enum): 2832 vars().update({ 2833 k: v 2834 for k, v in foo_defines.items() 2835 if k.startswith('FOO_') 2836 }, 2837 **{'FOO_CAT': 'small'}, 2838 ) 2839 def upper(self): 2840 return self.value.upper() 2841 2842 2843class TestOrder(unittest.TestCase): 2844 2845 def test_same_members(self): 2846 class Color(Enum): 2847 _order_ = 'red green blue' 2848 red = 1 2849 green = 2 2850 blue = 3 2851 2852 def test_same_members_with_aliases(self): 2853 class Color(Enum): 2854 _order_ = 'red green blue' 2855 red = 1 2856 green = 2 2857 blue = 3 2858 verde = green 2859 2860 def test_same_members_wrong_order(self): 2861 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2862 class Color(Enum): 2863 _order_ = 'red green blue' 2864 red = 1 2865 blue = 3 2866 green = 2 2867 2868 def test_order_has_extra_members(self): 2869 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2870 class Color(Enum): 2871 _order_ = 'red green blue purple' 2872 red = 1 2873 green = 2 2874 blue = 3 2875 2876 def test_order_has_extra_members_with_aliases(self): 2877 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2878 class Color(Enum): 2879 _order_ = 'red green blue purple' 2880 red = 1 2881 green = 2 2882 blue = 3 2883 verde = green 2884 2885 def test_enum_has_extra_members(self): 2886 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2887 class Color(Enum): 2888 _order_ = 'red green blue' 2889 red = 1 2890 green = 2 2891 blue = 3 2892 purple = 4 2893 2894 def test_enum_has_extra_members_with_aliases(self): 2895 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2896 class Color(Enum): 2897 _order_ = 'red green blue' 2898 red = 1 2899 green = 2 2900 blue = 3 2901 purple = 4 2902 verde = green 2903 2904 2905class TestFlag(unittest.TestCase): 2906 """Tests of the Flags.""" 2907 2908 class Perm(Flag): 2909 R, W, X = 4, 2, 1 2910 2911 class Open(Flag): 2912 RO = 0 2913 WO = 1 2914 RW = 2 2915 AC = 3 2916 CE = 1<<19 2917 2918 class Color(Flag): 2919 BLACK = 0 2920 RED = 1 2921 ROJO = 1 2922 GREEN = 2 2923 BLUE = 4 2924 PURPLE = RED|BLUE 2925 WHITE = RED|GREEN|BLUE 2926 BLANCO = RED|GREEN|BLUE 2927 2928 def test_str(self): 2929 Perm = self.Perm 2930 self.assertEqual(str(Perm.R), 'R') 2931 self.assertEqual(str(Perm.W), 'W') 2932 self.assertEqual(str(Perm.X), 'X') 2933 self.assertEqual(str(Perm.R | Perm.W), 'R|W') 2934 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X') 2935 self.assertEqual(str(Perm(0)), 'Perm(0)') 2936 self.assertEqual(str(~Perm.R), 'W|X') 2937 self.assertEqual(str(~Perm.W), 'R|X') 2938 self.assertEqual(str(~Perm.X), 'R|W') 2939 self.assertEqual(str(~(Perm.R | Perm.W)), 'X') 2940 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)') 2941 self.assertEqual(str(Perm(~0)), 'R|W|X') 2942 2943 Open = self.Open 2944 self.assertEqual(str(Open.RO), 'RO') 2945 self.assertEqual(str(Open.WO), 'WO') 2946 self.assertEqual(str(Open.AC), 'AC') 2947 self.assertEqual(str(Open.RO | Open.CE), 'CE') 2948 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE') 2949 self.assertEqual(str(~Open.RO), 'WO|RW|CE') 2950 self.assertEqual(str(~Open.WO), 'RW|CE') 2951 self.assertEqual(str(~Open.AC), 'CE') 2952 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC') 2953 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW') 2954 2955 def test_repr(self): 2956 Perm = self.Perm 2957 self.assertEqual(repr(Perm.R), 'Perm.R') 2958 self.assertEqual(repr(Perm.W), 'Perm.W') 2959 self.assertEqual(repr(Perm.X), 'Perm.X') 2960 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W') 2961 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X') 2962 self.assertEqual(repr(Perm(0)), '0x0') 2963 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X') 2964 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X') 2965 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W') 2966 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X') 2967 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0') 2968 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X') 2969 2970 Open = self.Open 2971 self.assertEqual(repr(Open.RO), 'Open.RO') 2972 self.assertEqual(repr(Open.WO), 'Open.WO') 2973 self.assertEqual(repr(Open.AC), 'Open.AC') 2974 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE') 2975 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE') 2976 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE') 2977 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE') 2978 self.assertEqual(repr(~Open.AC), 'Open.CE') 2979 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC') 2980 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW') 2981 2982 def test_format(self): 2983 Perm = self.Perm 2984 self.assertEqual(format(Perm.R, ''), 'R') 2985 self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X') 2986 2987 def test_or(self): 2988 Perm = self.Perm 2989 for i in Perm: 2990 for j in Perm: 2991 self.assertEqual((i | j), Perm(i.value | j.value)) 2992 self.assertEqual((i | j).value, i.value | j.value) 2993 self.assertIs(type(i | j), Perm) 2994 for i in Perm: 2995 self.assertIs(i | i, i) 2996 Open = self.Open 2997 self.assertIs(Open.RO | Open.CE, Open.CE) 2998 2999 def test_and(self): 3000 Perm = self.Perm 3001 RW = Perm.R | Perm.W 3002 RX = Perm.R | Perm.X 3003 WX = Perm.W | Perm.X 3004 RWX = Perm.R | Perm.W | Perm.X 3005 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 3006 for i in values: 3007 for j in values: 3008 self.assertEqual((i & j).value, i.value & j.value) 3009 self.assertIs(type(i & j), Perm) 3010 for i in Perm: 3011 self.assertIs(i & i, i) 3012 self.assertIs(i & RWX, i) 3013 self.assertIs(RWX & i, i) 3014 Open = self.Open 3015 self.assertIs(Open.RO & Open.CE, Open.RO) 3016 3017 def test_xor(self): 3018 Perm = self.Perm 3019 for i in Perm: 3020 for j in Perm: 3021 self.assertEqual((i ^ j).value, i.value ^ j.value) 3022 self.assertIs(type(i ^ j), Perm) 3023 for i in Perm: 3024 self.assertIs(i ^ Perm(0), i) 3025 self.assertIs(Perm(0) ^ i, i) 3026 Open = self.Open 3027 self.assertIs(Open.RO ^ Open.CE, Open.CE) 3028 self.assertIs(Open.CE ^ Open.CE, Open.RO) 3029 3030 def test_invert(self): 3031 Perm = self.Perm 3032 RW = Perm.R | Perm.W 3033 RX = Perm.R | Perm.X 3034 WX = Perm.W | Perm.X 3035 RWX = Perm.R | Perm.W | Perm.X 3036 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 3037 for i in values: 3038 self.assertIs(type(~i), Perm) 3039 self.assertEqual(~~i, i) 3040 for i in Perm: 3041 self.assertIs(~~i, i) 3042 Open = self.Open 3043 self.assertIs(Open.WO & ~Open.WO, Open.RO) 3044 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE) 3045 3046 def test_bool(self): 3047 Perm = self.Perm 3048 for f in Perm: 3049 self.assertTrue(f) 3050 Open = self.Open 3051 for f in Open: 3052 self.assertEqual(bool(f.value), bool(f)) 3053 3054 def test_boundary(self): 3055 self.assertIs(enum.Flag._boundary_, STRICT) 3056 class Iron(Flag, boundary=STRICT): 3057 ONE = 1 3058 TWO = 2 3059 EIGHT = 8 3060 self.assertIs(Iron._boundary_, STRICT) 3061 # 3062 class Water(Flag, boundary=CONFORM): 3063 ONE = 1 3064 TWO = 2 3065 EIGHT = 8 3066 self.assertIs(Water._boundary_, CONFORM) 3067 # 3068 class Space(Flag, boundary=EJECT): 3069 ONE = 1 3070 TWO = 2 3071 EIGHT = 8 3072 self.assertIs(Space._boundary_, EJECT) 3073 # 3074 class Bizarre(Flag, boundary=KEEP): 3075 b = 3 3076 c = 4 3077 d = 6 3078 # 3079 self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7) 3080 # 3081 self.assertIs(Water(7), Water.ONE|Water.TWO) 3082 self.assertIs(Water(~9), Water.TWO) 3083 # 3084 self.assertEqual(Space(7), 7) 3085 self.assertTrue(type(Space(7)) is int) 3086 # 3087 self.assertEqual(list(Bizarre), [Bizarre.c]) 3088 self.assertIs(Bizarre(3), Bizarre.b) 3089 self.assertIs(Bizarre(6), Bizarre.d) 3090 3091 def test_iter(self): 3092 Color = self.Color 3093 Open = self.Open 3094 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE]) 3095 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE]) 3096 3097 def test_programatic_function_string(self): 3098 Perm = Flag('Perm', 'R W X') 3099 lst = list(Perm) 3100 self.assertEqual(len(lst), len(Perm)) 3101 self.assertEqual(len(Perm), 3, Perm) 3102 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3103 for i, n in enumerate('R W X'.split()): 3104 v = 1<<i 3105 e = Perm(v) 3106 self.assertEqual(e.value, v) 3107 self.assertEqual(type(e.value), int) 3108 self.assertEqual(e.name, n) 3109 self.assertIn(e, Perm) 3110 self.assertIs(type(e), Perm) 3111 3112 def test_programatic_function_string_with_start(self): 3113 Perm = Flag('Perm', 'R W X', start=8) 3114 lst = list(Perm) 3115 self.assertEqual(len(lst), len(Perm)) 3116 self.assertEqual(len(Perm), 3, Perm) 3117 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3118 for i, n in enumerate('R W X'.split()): 3119 v = 8<<i 3120 e = Perm(v) 3121 self.assertEqual(e.value, v) 3122 self.assertEqual(type(e.value), int) 3123 self.assertEqual(e.name, n) 3124 self.assertIn(e, Perm) 3125 self.assertIs(type(e), Perm) 3126 3127 def test_programatic_function_string_list(self): 3128 Perm = Flag('Perm', ['R', 'W', 'X']) 3129 lst = list(Perm) 3130 self.assertEqual(len(lst), len(Perm)) 3131 self.assertEqual(len(Perm), 3, Perm) 3132 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3133 for i, n in enumerate('R W X'.split()): 3134 v = 1<<i 3135 e = Perm(v) 3136 self.assertEqual(e.value, v) 3137 self.assertEqual(type(e.value), int) 3138 self.assertEqual(e.name, n) 3139 self.assertIn(e, Perm) 3140 self.assertIs(type(e), Perm) 3141 3142 def test_programatic_function_iterable(self): 3143 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32))) 3144 lst = list(Perm) 3145 self.assertEqual(len(lst), len(Perm)) 3146 self.assertEqual(len(Perm), 3, Perm) 3147 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3148 for i, n in enumerate('R W X'.split()): 3149 v = 1<<(2*i+1) 3150 e = Perm(v) 3151 self.assertEqual(e.value, v) 3152 self.assertEqual(type(e.value), int) 3153 self.assertEqual(e.name, n) 3154 self.assertIn(e, Perm) 3155 self.assertIs(type(e), Perm) 3156 3157 def test_programatic_function_from_dict(self): 3158 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32)))) 3159 lst = list(Perm) 3160 self.assertEqual(len(lst), len(Perm)) 3161 self.assertEqual(len(Perm), 3, Perm) 3162 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3163 for i, n in enumerate('R W X'.split()): 3164 v = 1<<(2*i+1) 3165 e = Perm(v) 3166 self.assertEqual(e.value, v) 3167 self.assertEqual(type(e.value), int) 3168 self.assertEqual(e.name, n) 3169 self.assertIn(e, Perm) 3170 self.assertIs(type(e), Perm) 3171 3172 def test_pickle(self): 3173 if isinstance(FlagStooges, Exception): 3174 raise FlagStooges 3175 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE) 3176 test_pickle_dump_load(self.assertIs, FlagStooges) 3177 3178 @unittest.skipIf( 3179 python_version >= (3, 12), 3180 '__contains__ now returns True/False for all inputs', 3181 ) 3182 def test_contains_er(self): 3183 Open = self.Open 3184 Color = self.Color 3185 self.assertFalse(Color.BLACK in Open) 3186 self.assertFalse(Open.RO in Color) 3187 with self.assertRaises(TypeError): 3188 with self.assertWarns(DeprecationWarning): 3189 'BLACK' in Color 3190 with self.assertRaises(TypeError): 3191 with self.assertWarns(DeprecationWarning): 3192 'RO' in Open 3193 with self.assertRaises(TypeError): 3194 with self.assertWarns(DeprecationWarning): 3195 1 in Color 3196 with self.assertRaises(TypeError): 3197 with self.assertWarns(DeprecationWarning): 3198 1 in Open 3199 3200 @unittest.skipIf( 3201 python_version < (3, 12), 3202 '__contains__ only works with enum memmbers before 3.12', 3203 ) 3204 def test_contains_tf(self): 3205 Open = self.Open 3206 Color = self.Color 3207 self.assertFalse(Color.BLACK in Open) 3208 self.assertFalse(Open.RO in Color) 3209 self.assertFalse('BLACK' in Color) 3210 self.assertFalse('RO' in Open) 3211 self.assertTrue(1 in Color) 3212 self.assertTrue(1 in Open) 3213 3214 def test_member_contains(self): 3215 Perm = self.Perm 3216 R, W, X = Perm 3217 RW = R | W 3218 RX = R | X 3219 WX = W | X 3220 RWX = R | W | X 3221 self.assertTrue(R in RW) 3222 self.assertTrue(R in RX) 3223 self.assertTrue(R in RWX) 3224 self.assertTrue(W in RW) 3225 self.assertTrue(W in WX) 3226 self.assertTrue(W in RWX) 3227 self.assertTrue(X in RX) 3228 self.assertTrue(X in WX) 3229 self.assertTrue(X in RWX) 3230 self.assertFalse(R in WX) 3231 self.assertFalse(W in RX) 3232 self.assertFalse(X in RW) 3233 3234 def test_member_iter(self): 3235 Color = self.Color 3236 self.assertEqual(list(Color.BLACK), []) 3237 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE]) 3238 self.assertEqual(list(Color.BLUE), [Color.BLUE]) 3239 self.assertEqual(list(Color.GREEN), [Color.GREEN]) 3240 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE]) 3241 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE]) 3242 3243 def test_member_length(self): 3244 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0) 3245 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1) 3246 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2) 3247 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3) 3248 3249 def test_number_reset_and_order_cleanup(self): 3250 class Confused(Flag): 3251 _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN' 3252 ONE = auto() 3253 TWO = auto() 3254 FOUR = auto() 3255 DOS = 2 3256 EIGHT = auto() 3257 SIXTEEN = auto() 3258 self.assertEqual( 3259 list(Confused), 3260 [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN]) 3261 self.assertIs(Confused.TWO, Confused.DOS) 3262 self.assertEqual(Confused.DOS._value_, 2) 3263 self.assertEqual(Confused.EIGHT._value_, 8) 3264 self.assertEqual(Confused.SIXTEEN._value_, 16) 3265 3266 def test_aliases(self): 3267 Color = self.Color 3268 self.assertEqual(Color(1).name, 'RED') 3269 self.assertEqual(Color['ROJO'].name, 'RED') 3270 self.assertEqual(Color(7).name, 'WHITE') 3271 self.assertEqual(Color['BLANCO'].name, 'WHITE') 3272 self.assertIs(Color.BLANCO, Color.WHITE) 3273 Open = self.Open 3274 self.assertIs(Open['AC'], Open.AC) 3275 3276 def test_auto_number(self): 3277 class Color(Flag): 3278 red = auto() 3279 blue = auto() 3280 green = auto() 3281 3282 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 3283 self.assertEqual(Color.red.value, 1) 3284 self.assertEqual(Color.blue.value, 2) 3285 self.assertEqual(Color.green.value, 4) 3286 3287 def test_auto_number_garbage(self): 3288 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'): 3289 class Color(Flag): 3290 red = 'not an int' 3291 blue = auto() 3292 3293 def test_duplicate_auto(self): 3294 class Dupes(Enum): 3295 first = primero = auto() 3296 second = auto() 3297 third = auto() 3298 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) 3299 3300 def test_multiple_mixin(self): 3301 class AllMixin: 3302 @classproperty 3303 def ALL(cls): 3304 members = list(cls) 3305 all_value = None 3306 if members: 3307 all_value = members[0] 3308 for member in members[1:]: 3309 all_value |= member 3310 cls.ALL = all_value 3311 return all_value 3312 class StrMixin: 3313 def __str__(self): 3314 return self._name_.lower() 3315 class Color(AllMixin, Flag): 3316 RED = auto() 3317 GREEN = auto() 3318 BLUE = auto() 3319 self.assertEqual(Color.RED.value, 1) 3320 self.assertEqual(Color.GREEN.value, 2) 3321 self.assertEqual(Color.BLUE.value, 4) 3322 self.assertEqual(Color.ALL.value, 7) 3323 self.assertEqual(str(Color.BLUE), 'BLUE') 3324 class Color(AllMixin, StrMixin, Flag): 3325 RED = auto() 3326 GREEN = auto() 3327 BLUE = auto() 3328 self.assertEqual(Color.RED.value, 1) 3329 self.assertEqual(Color.GREEN.value, 2) 3330 self.assertEqual(Color.BLUE.value, 4) 3331 self.assertEqual(Color.ALL.value, 7) 3332 self.assertEqual(str(Color.BLUE), 'blue') 3333 class Color(StrMixin, AllMixin, Flag): 3334 RED = auto() 3335 GREEN = auto() 3336 BLUE = auto() 3337 self.assertEqual(Color.RED.value, 1) 3338 self.assertEqual(Color.GREEN.value, 2) 3339 self.assertEqual(Color.BLUE.value, 4) 3340 self.assertEqual(Color.ALL.value, 7) 3341 self.assertEqual(str(Color.BLUE), 'blue') 3342 3343 @threading_helper.reap_threads 3344 def test_unique_composite(self): 3345 # override __eq__ to be identity only 3346 class TestFlag(Flag): 3347 one = auto() 3348 two = auto() 3349 three = auto() 3350 four = auto() 3351 five = auto() 3352 six = auto() 3353 seven = auto() 3354 eight = auto() 3355 def __eq__(self, other): 3356 return self is other 3357 def __hash__(self): 3358 return hash(self._value_) 3359 # have multiple threads competing to complete the composite members 3360 seen = set() 3361 failed = False 3362 def cycle_enum(): 3363 nonlocal failed 3364 try: 3365 for i in range(256): 3366 seen.add(TestFlag(i)) 3367 except Exception: 3368 failed = True 3369 threads = [ 3370 threading.Thread(target=cycle_enum) 3371 for _ in range(8) 3372 ] 3373 with threading_helper.start_threads(threads): 3374 pass 3375 # check that only 248 members were created 3376 self.assertFalse( 3377 failed, 3378 'at least one thread failed while creating composite members') 3379 self.assertEqual(256, len(seen), 'too many composite members created') 3380 3381 def test_init_subclass(self): 3382 class MyEnum(Flag): 3383 def __init_subclass__(cls, **kwds): 3384 super().__init_subclass__(**kwds) 3385 self.assertFalse(cls.__dict__.get('_test', False)) 3386 cls._test1 = 'MyEnum' 3387 # 3388 class TheirEnum(MyEnum): 3389 def __init_subclass__(cls, **kwds): 3390 super(TheirEnum, cls).__init_subclass__(**kwds) 3391 cls._test2 = 'TheirEnum' 3392 class WhoseEnum(TheirEnum): 3393 def __init_subclass__(cls, **kwds): 3394 pass 3395 class NoEnum(WhoseEnum): 3396 ONE = 1 3397 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') 3398 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') 3399 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') 3400 self.assertFalse(NoEnum.__dict__.get('_test1', False)) 3401 self.assertFalse(NoEnum.__dict__.get('_test2', False)) 3402 # 3403 class OurEnum(MyEnum): 3404 def __init_subclass__(cls, **kwds): 3405 cls._test2 = 'OurEnum' 3406 class WhereEnum(OurEnum): 3407 def __init_subclass__(cls, **kwds): 3408 pass 3409 class NeverEnum(WhereEnum): 3410 ONE = 1 3411 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') 3412 self.assertFalse(WhereEnum.__dict__.get('_test1', False)) 3413 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') 3414 self.assertFalse(NeverEnum.__dict__.get('_test1', False)) 3415 self.assertFalse(NeverEnum.__dict__.get('_test2', False)) 3416 3417 3418class TestIntFlag(unittest.TestCase): 3419 """Tests of the IntFlags.""" 3420 3421 class Perm(IntFlag): 3422 R = 1 << 2 3423 W = 1 << 1 3424 X = 1 << 0 3425 3426 class Open(IntFlag): 3427 RO = 0 3428 WO = 1 3429 RW = 2 3430 AC = 3 3431 CE = 1<<19 3432 3433 class Color(IntFlag): 3434 BLACK = 0 3435 RED = 1 3436 ROJO = 1 3437 GREEN = 2 3438 BLUE = 4 3439 PURPLE = RED|BLUE 3440 WHITE = RED|GREEN|BLUE 3441 BLANCO = RED|GREEN|BLUE 3442 3443 class Skip(IntFlag): 3444 FIRST = 1 3445 SECOND = 2 3446 EIGHTH = 8 3447 3448 def test_type(self): 3449 Perm = self.Perm 3450 self.assertTrue(Perm._member_type_ is int) 3451 Open = self.Open 3452 for f in Perm: 3453 self.assertTrue(isinstance(f, Perm)) 3454 self.assertEqual(f, f.value) 3455 self.assertTrue(isinstance(Perm.W | Perm.X, Perm)) 3456 self.assertEqual(Perm.W | Perm.X, 3) 3457 for f in Open: 3458 self.assertTrue(isinstance(f, Open)) 3459 self.assertEqual(f, f.value) 3460 self.assertTrue(isinstance(Open.WO | Open.RW, Open)) 3461 self.assertEqual(Open.WO | Open.RW, 3) 3462 3463 3464 def test_str(self): 3465 Perm = self.Perm 3466 self.assertEqual(str(Perm.R), 'R') 3467 self.assertEqual(str(Perm.W), 'W') 3468 self.assertEqual(str(Perm.X), 'X') 3469 self.assertEqual(str(Perm.R | Perm.W), 'R|W') 3470 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X') 3471 self.assertEqual(str(Perm.R | 8), '12') 3472 self.assertEqual(str(Perm(0)), 'Perm(0)') 3473 self.assertEqual(str(Perm(8)), '8') 3474 self.assertEqual(str(~Perm.R), 'W|X') 3475 self.assertEqual(str(~Perm.W), 'R|X') 3476 self.assertEqual(str(~Perm.X), 'R|W') 3477 self.assertEqual(str(~(Perm.R | Perm.W)), 'X') 3478 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)') 3479 self.assertEqual(str(~(Perm.R | 8)), '-13') 3480 self.assertEqual(str(Perm(~0)), 'R|W|X') 3481 self.assertEqual(str(Perm(~8)), '-9') 3482 3483 Open = self.Open 3484 self.assertEqual(str(Open.RO), 'RO') 3485 self.assertEqual(str(Open.WO), 'WO') 3486 self.assertEqual(str(Open.AC), 'AC') 3487 self.assertEqual(str(Open.RO | Open.CE), 'CE') 3488 self.assertEqual(str(Open.WO | Open.CE), 'WO|CE') 3489 self.assertEqual(str(Open(4)), '4') 3490 self.assertEqual(str(~Open.RO), 'WO|RW|CE') 3491 self.assertEqual(str(~Open.WO), 'RW|CE') 3492 self.assertEqual(str(~Open.AC), 'CE') 3493 self.assertEqual(str(~(Open.RO | Open.CE)), 'AC') 3494 self.assertEqual(str(~(Open.WO | Open.CE)), 'RW') 3495 self.assertEqual(str(Open(~4)), '-5') 3496 3497 def test_repr(self): 3498 Perm = self.Perm 3499 self.assertEqual(repr(Perm.R), 'Perm.R') 3500 self.assertEqual(repr(Perm.W), 'Perm.W') 3501 self.assertEqual(repr(Perm.X), 'Perm.X') 3502 self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W') 3503 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X') 3504 self.assertEqual(repr(Perm.R | 8), '12') 3505 self.assertEqual(repr(Perm(0)), '0x0') 3506 self.assertEqual(repr(Perm(8)), '8') 3507 self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X') 3508 self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X') 3509 self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W') 3510 self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X') 3511 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0') 3512 self.assertEqual(repr(~(Perm.R | 8)), '-13') 3513 self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X') 3514 self.assertEqual(repr(Perm(~8)), '-9') 3515 3516 Open = self.Open 3517 self.assertEqual(repr(Open.RO), 'Open.RO') 3518 self.assertEqual(repr(Open.WO), 'Open.WO') 3519 self.assertEqual(repr(Open.AC), 'Open.AC') 3520 self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE') 3521 self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE') 3522 self.assertEqual(repr(Open(4)), '4') 3523 self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE') 3524 self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE') 3525 self.assertEqual(repr(~Open.AC), 'Open.CE') 3526 self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC') 3527 self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW') 3528 self.assertEqual(repr(Open(~4)), '-5') 3529 3530 def test_global_repr_keep(self): 3531 self.assertEqual( 3532 repr(HeadlightsK(0)), 3533 '%s.OFF_K' % SHORT_MODULE, 3534 ) 3535 self.assertEqual( 3536 repr(HeadlightsK(2**0 + 2**2 + 2**3)), 3537 '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE}, 3538 ) 3539 self.assertEqual( 3540 repr(HeadlightsK(2**3)), 3541 '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE}, 3542 ) 3543 3544 def test_global_repr_conform1(self): 3545 self.assertEqual( 3546 repr(HeadlightsC(0)), 3547 '%s.OFF_C' % SHORT_MODULE, 3548 ) 3549 self.assertEqual( 3550 repr(HeadlightsC(2**0 + 2**2 + 2**3)), 3551 '%(m)s.LOW_BEAM_C|%(m)s.FOG_C' % {'m': SHORT_MODULE}, 3552 ) 3553 self.assertEqual( 3554 repr(HeadlightsC(2**3)), 3555 '%(m)s.OFF_C' % {'m': SHORT_MODULE}, 3556 ) 3557 3558 def test_format(self): 3559 Perm = self.Perm 3560 self.assertEqual(format(Perm.R, ''), '4') 3561 self.assertEqual(format(Perm.R | Perm.X, ''), '5') 3562 # 3563 class NewPerm(IntFlag): 3564 R = 1 << 2 3565 W = 1 << 1 3566 X = 1 << 0 3567 def __str__(self): 3568 return self._name_ 3569 self.assertEqual(format(NewPerm.R, ''), 'R') 3570 self.assertEqual(format(NewPerm.R | Perm.X, ''), 'R|X') 3571 3572 def test_or(self): 3573 Perm = self.Perm 3574 for i in Perm: 3575 for j in Perm: 3576 self.assertEqual(i | j, i.value | j.value) 3577 self.assertEqual((i | j).value, i.value | j.value) 3578 self.assertIs(type(i | j), Perm) 3579 for j in range(8): 3580 self.assertEqual(i | j, i.value | j) 3581 self.assertEqual((i | j).value, i.value | j) 3582 self.assertIs(type(i | j), Perm) 3583 self.assertEqual(j | i, j | i.value) 3584 self.assertEqual((j | i).value, j | i.value) 3585 self.assertIs(type(j | i), Perm) 3586 for i in Perm: 3587 self.assertIs(i | i, i) 3588 self.assertIs(i | 0, i) 3589 self.assertIs(0 | i, i) 3590 Open = self.Open 3591 self.assertIs(Open.RO | Open.CE, Open.CE) 3592 3593 def test_and(self): 3594 Perm = self.Perm 3595 RW = Perm.R | Perm.W 3596 RX = Perm.R | Perm.X 3597 WX = Perm.W | Perm.X 3598 RWX = Perm.R | Perm.W | Perm.X 3599 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 3600 for i in values: 3601 for j in values: 3602 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j)) 3603 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j)) 3604 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j)) 3605 for j in range(8): 3606 self.assertEqual(i & j, i.value & j) 3607 self.assertEqual((i & j).value, i.value & j) 3608 self.assertIs(type(i & j), Perm) 3609 self.assertEqual(j & i, j & i.value) 3610 self.assertEqual((j & i).value, j & i.value) 3611 self.assertIs(type(j & i), Perm) 3612 for i in Perm: 3613 self.assertIs(i & i, i) 3614 self.assertIs(i & 7, i) 3615 self.assertIs(7 & i, i) 3616 Open = self.Open 3617 self.assertIs(Open.RO & Open.CE, Open.RO) 3618 3619 def test_xor(self): 3620 Perm = self.Perm 3621 for i in Perm: 3622 for j in Perm: 3623 self.assertEqual(i ^ j, i.value ^ j.value) 3624 self.assertEqual((i ^ j).value, i.value ^ j.value) 3625 self.assertIs(type(i ^ j), Perm) 3626 for j in range(8): 3627 self.assertEqual(i ^ j, i.value ^ j) 3628 self.assertEqual((i ^ j).value, i.value ^ j) 3629 self.assertIs(type(i ^ j), Perm) 3630 self.assertEqual(j ^ i, j ^ i.value) 3631 self.assertEqual((j ^ i).value, j ^ i.value) 3632 self.assertIs(type(j ^ i), Perm) 3633 for i in Perm: 3634 self.assertIs(i ^ 0, i) 3635 self.assertIs(0 ^ i, i) 3636 Open = self.Open 3637 self.assertIs(Open.RO ^ Open.CE, Open.CE) 3638 self.assertIs(Open.CE ^ Open.CE, Open.RO) 3639 3640 def test_invert(self): 3641 Perm = self.Perm 3642 RW = Perm.R | Perm.W 3643 RX = Perm.R | Perm.X 3644 WX = Perm.W | Perm.X 3645 RWX = Perm.R | Perm.W | Perm.X 3646 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 3647 for i in values: 3648 self.assertEqual(~i, (~i).value) 3649 self.assertIs(type(~i), Perm) 3650 self.assertEqual(~~i, i) 3651 for i in Perm: 3652 self.assertIs(~~i, i) 3653 Open = self.Open 3654 self.assertIs(Open.WO & ~Open.WO, Open.RO) 3655 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE) 3656 3657 def test_boundary(self): 3658 self.assertIs(enum.IntFlag._boundary_, EJECT) 3659 class Iron(IntFlag, boundary=STRICT): 3660 ONE = 1 3661 TWO = 2 3662 EIGHT = 8 3663 self.assertIs(Iron._boundary_, STRICT) 3664 # 3665 class Water(IntFlag, boundary=CONFORM): 3666 ONE = 1 3667 TWO = 2 3668 EIGHT = 8 3669 self.assertIs(Water._boundary_, CONFORM) 3670 # 3671 class Space(IntFlag, boundary=EJECT): 3672 ONE = 1 3673 TWO = 2 3674 EIGHT = 8 3675 self.assertIs(Space._boundary_, EJECT) 3676 # 3677 # 3678 class Bizarre(IntFlag, boundary=KEEP): 3679 b = 3 3680 c = 4 3681 d = 6 3682 # 3683 self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5) 3684 # 3685 self.assertIs(Water(7), Water.ONE|Water.TWO) 3686 self.assertIs(Water(~9), Water.TWO) 3687 # 3688 self.assertEqual(Space(7), 7) 3689 self.assertTrue(type(Space(7)) is int) 3690 # 3691 self.assertEqual(list(Bizarre), [Bizarre.c]) 3692 self.assertIs(Bizarre(3), Bizarre.b) 3693 self.assertIs(Bizarre(6), Bizarre.d) 3694 3695 def test_iter(self): 3696 Color = self.Color 3697 Open = self.Open 3698 self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE]) 3699 self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE]) 3700 3701 def test_programatic_function_string(self): 3702 Perm = IntFlag('Perm', 'R W X') 3703 lst = list(Perm) 3704 self.assertEqual(len(lst), len(Perm)) 3705 self.assertEqual(len(Perm), 3, Perm) 3706 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3707 for i, n in enumerate('R W X'.split()): 3708 v = 1<<i 3709 e = Perm(v) 3710 self.assertEqual(e.value, v) 3711 self.assertEqual(type(e.value), int) 3712 self.assertEqual(e, v) 3713 self.assertEqual(e.name, n) 3714 self.assertIn(e, Perm) 3715 self.assertIs(type(e), Perm) 3716 3717 def test_programatic_function_string_with_start(self): 3718 Perm = IntFlag('Perm', 'R W X', start=8) 3719 lst = list(Perm) 3720 self.assertEqual(len(lst), len(Perm)) 3721 self.assertEqual(len(Perm), 3, Perm) 3722 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3723 for i, n in enumerate('R W X'.split()): 3724 v = 8<<i 3725 e = Perm(v) 3726 self.assertEqual(e.value, v) 3727 self.assertEqual(type(e.value), int) 3728 self.assertEqual(e, v) 3729 self.assertEqual(e.name, n) 3730 self.assertIn(e, Perm) 3731 self.assertIs(type(e), Perm) 3732 3733 def test_programatic_function_string_list(self): 3734 Perm = IntFlag('Perm', ['R', 'W', 'X']) 3735 lst = list(Perm) 3736 self.assertEqual(len(lst), len(Perm)) 3737 self.assertEqual(len(Perm), 3, Perm) 3738 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3739 for i, n in enumerate('R W X'.split()): 3740 v = 1<<i 3741 e = Perm(v) 3742 self.assertEqual(e.value, v) 3743 self.assertEqual(type(e.value), int) 3744 self.assertEqual(e, v) 3745 self.assertEqual(e.name, n) 3746 self.assertIn(e, Perm) 3747 self.assertIs(type(e), Perm) 3748 3749 def test_programatic_function_iterable(self): 3750 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32))) 3751 lst = list(Perm) 3752 self.assertEqual(len(lst), len(Perm)) 3753 self.assertEqual(len(Perm), 3, Perm) 3754 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3755 for i, n in enumerate('R W X'.split()): 3756 v = 1<<(2*i+1) 3757 e = Perm(v) 3758 self.assertEqual(e.value, v) 3759 self.assertEqual(type(e.value), int) 3760 self.assertEqual(e, v) 3761 self.assertEqual(e.name, n) 3762 self.assertIn(e, Perm) 3763 self.assertIs(type(e), Perm) 3764 3765 def test_programatic_function_from_dict(self): 3766 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32)))) 3767 lst = list(Perm) 3768 self.assertEqual(len(lst), len(Perm)) 3769 self.assertEqual(len(Perm), 3, Perm) 3770 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 3771 for i, n in enumerate('R W X'.split()): 3772 v = 1<<(2*i+1) 3773 e = Perm(v) 3774 self.assertEqual(e.value, v) 3775 self.assertEqual(type(e.value), int) 3776 self.assertEqual(e, v) 3777 self.assertEqual(e.name, n) 3778 self.assertIn(e, Perm) 3779 self.assertIs(type(e), Perm) 3780 3781 3782 def test_programatic_function_from_empty_list(self): 3783 Perm = enum.IntFlag('Perm', []) 3784 lst = list(Perm) 3785 self.assertEqual(len(lst), len(Perm)) 3786 self.assertEqual(len(Perm), 0, Perm) 3787 Thing = enum.Enum('Thing', []) 3788 lst = list(Thing) 3789 self.assertEqual(len(lst), len(Thing)) 3790 self.assertEqual(len(Thing), 0, Thing) 3791 3792 3793 def test_programatic_function_from_empty_tuple(self): 3794 Perm = enum.IntFlag('Perm', ()) 3795 lst = list(Perm) 3796 self.assertEqual(len(lst), len(Perm)) 3797 self.assertEqual(len(Perm), 0, Perm) 3798 Thing = enum.Enum('Thing', ()) 3799 self.assertEqual(len(lst), len(Thing)) 3800 self.assertEqual(len(Thing), 0, Thing) 3801 3802 @unittest.skipIf( 3803 python_version >= (3, 12), 3804 '__contains__ now returns True/False for all inputs', 3805 ) 3806 def test_contains_er(self): 3807 Open = self.Open 3808 Color = self.Color 3809 self.assertTrue(Color.GREEN in Color) 3810 self.assertTrue(Open.RW in Open) 3811 self.assertFalse(Color.GREEN in Open) 3812 self.assertFalse(Open.RW in Color) 3813 with self.assertRaises(TypeError): 3814 with self.assertWarns(DeprecationWarning): 3815 'GREEN' in Color 3816 with self.assertRaises(TypeError): 3817 with self.assertWarns(DeprecationWarning): 3818 'RW' in Open 3819 with self.assertRaises(TypeError): 3820 with self.assertWarns(DeprecationWarning): 3821 2 in Color 3822 with self.assertRaises(TypeError): 3823 with self.assertWarns(DeprecationWarning): 3824 2 in Open 3825 3826 @unittest.skipIf( 3827 python_version < (3, 12), 3828 '__contains__ only works with enum memmbers before 3.12', 3829 ) 3830 def test_contains_tf(self): 3831 Open = self.Open 3832 Color = self.Color 3833 self.assertTrue(Color.GREEN in Color) 3834 self.assertTrue(Open.RW in Open) 3835 self.assertTrue(Color.GREEN in Open) 3836 self.assertTrue(Open.RW in Color) 3837 self.assertFalse('GREEN' in Color) 3838 self.assertFalse('RW' in Open) 3839 self.assertTrue(2 in Color) 3840 self.assertTrue(2 in Open) 3841 3842 def test_member_contains(self): 3843 Perm = self.Perm 3844 R, W, X = Perm 3845 RW = R | W 3846 RX = R | X 3847 WX = W | X 3848 RWX = R | W | X 3849 self.assertTrue(R in RW) 3850 self.assertTrue(R in RX) 3851 self.assertTrue(R in RWX) 3852 self.assertTrue(W in RW) 3853 self.assertTrue(W in WX) 3854 self.assertTrue(W in RWX) 3855 self.assertTrue(X in RX) 3856 self.assertTrue(X in WX) 3857 self.assertTrue(X in RWX) 3858 self.assertFalse(R in WX) 3859 self.assertFalse(W in RX) 3860 self.assertFalse(X in RW) 3861 with self.assertRaises(TypeError): 3862 self.assertFalse('test' in RW) 3863 3864 def test_member_iter(self): 3865 Color = self.Color 3866 self.assertEqual(list(Color.BLACK), []) 3867 self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE]) 3868 self.assertEqual(list(Color.BLUE), [Color.BLUE]) 3869 self.assertEqual(list(Color.GREEN), [Color.GREEN]) 3870 self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE]) 3871 3872 def test_member_length(self): 3873 self.assertEqual(self.Color.__len__(self.Color.BLACK), 0) 3874 self.assertEqual(self.Color.__len__(self.Color.GREEN), 1) 3875 self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2) 3876 self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3) 3877 3878 def test_aliases(self): 3879 Color = self.Color 3880 self.assertEqual(Color(1).name, 'RED') 3881 self.assertEqual(Color['ROJO'].name, 'RED') 3882 self.assertEqual(Color(7).name, 'WHITE') 3883 self.assertEqual(Color['BLANCO'].name, 'WHITE') 3884 self.assertIs(Color.BLANCO, Color.WHITE) 3885 Open = self.Open 3886 self.assertIs(Open['AC'], Open.AC) 3887 3888 def test_bool(self): 3889 Perm = self.Perm 3890 for f in Perm: 3891 self.assertTrue(f) 3892 Open = self.Open 3893 for f in Open: 3894 self.assertEqual(bool(f.value), bool(f)) 3895 3896 3897 def test_multiple_mixin(self): 3898 class AllMixin: 3899 @classproperty 3900 def ALL(cls): 3901 members = list(cls) 3902 all_value = None 3903 if members: 3904 all_value = members[0] 3905 for member in members[1:]: 3906 all_value |= member 3907 cls.ALL = all_value 3908 return all_value 3909 class StrMixin: 3910 def __str__(self): 3911 return self._name_.lower() 3912 class Color(AllMixin, IntFlag): 3913 RED = auto() 3914 GREEN = auto() 3915 BLUE = auto() 3916 self.assertEqual(Color.RED.value, 1) 3917 self.assertEqual(Color.GREEN.value, 2) 3918 self.assertEqual(Color.BLUE.value, 4) 3919 self.assertEqual(Color.ALL.value, 7) 3920 self.assertEqual(str(Color.BLUE), 'BLUE') 3921 class Color(AllMixin, StrMixin, IntFlag): 3922 RED = auto() 3923 GREEN = auto() 3924 BLUE = auto() 3925 self.assertEqual(Color.RED.value, 1) 3926 self.assertEqual(Color.GREEN.value, 2) 3927 self.assertEqual(Color.BLUE.value, 4) 3928 self.assertEqual(Color.ALL.value, 7) 3929 self.assertEqual(str(Color.BLUE), 'blue') 3930 class Color(StrMixin, AllMixin, IntFlag): 3931 RED = auto() 3932 GREEN = auto() 3933 BLUE = auto() 3934 self.assertEqual(Color.RED.value, 1) 3935 self.assertEqual(Color.GREEN.value, 2) 3936 self.assertEqual(Color.BLUE.value, 4) 3937 self.assertEqual(Color.ALL.value, 7) 3938 self.assertEqual(str(Color.BLUE), 'blue') 3939 3940 @threading_helper.reap_threads 3941 def test_unique_composite(self): 3942 # override __eq__ to be identity only 3943 class TestFlag(IntFlag): 3944 one = auto() 3945 two = auto() 3946 three = auto() 3947 four = auto() 3948 five = auto() 3949 six = auto() 3950 seven = auto() 3951 eight = auto() 3952 def __eq__(self, other): 3953 return self is other 3954 def __hash__(self): 3955 return hash(self._value_) 3956 # have multiple threads competing to complete the composite members 3957 seen = set() 3958 failed = False 3959 def cycle_enum(): 3960 nonlocal failed 3961 try: 3962 for i in range(256): 3963 seen.add(TestFlag(i)) 3964 except Exception: 3965 failed = True 3966 threads = [ 3967 threading.Thread(target=cycle_enum) 3968 for _ in range(8) 3969 ] 3970 with threading_helper.start_threads(threads): 3971 pass 3972 # check that only 248 members were created 3973 self.assertFalse( 3974 failed, 3975 'at least one thread failed while creating composite members') 3976 self.assertEqual(256, len(seen), 'too many composite members created') 3977 3978 3979class TestEmptyAndNonLatinStrings(unittest.TestCase): 3980 3981 def test_empty_string(self): 3982 with self.assertRaises(ValueError): 3983 empty_abc = Enum('empty_abc', ('', 'B', 'C')) 3984 3985 def test_non_latin_character_string(self): 3986 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C')) 3987 item = getattr(greek_abc, '\u03B1') 3988 self.assertEqual(item.value, 1) 3989 3990 def test_non_latin_number_string(self): 3991 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3')) 3992 item = getattr(hebrew_123, '\u05D0') 3993 self.assertEqual(item.value, 1) 3994 3995 3996class TestUnique(unittest.TestCase): 3997 3998 def test_unique_clean(self): 3999 @unique 4000 class Clean(Enum): 4001 one = 1 4002 two = 'dos' 4003 tres = 4.0 4004 # 4005 @unique 4006 class Cleaner(IntEnum): 4007 single = 1 4008 double = 2 4009 triple = 3 4010 4011 def test_unique_dirty(self): 4012 with self.assertRaisesRegex(ValueError, 'tres.*one'): 4013 @unique 4014 class Dirty(Enum): 4015 one = 1 4016 two = 'dos' 4017 tres = 1 4018 with self.assertRaisesRegex( 4019 ValueError, 4020 'double.*single.*turkey.*triple', 4021 ): 4022 @unique 4023 class Dirtier(IntEnum): 4024 single = 1 4025 double = 1 4026 triple = 3 4027 turkey = 3 4028 4029 def test_unique_with_name(self): 4030 @verify(UNIQUE) 4031 class Silly(Enum): 4032 one = 1 4033 two = 'dos' 4034 name = 3 4035 # 4036 @verify(UNIQUE) 4037 class Sillier(IntEnum): 4038 single = 1 4039 name = 2 4040 triple = 3 4041 value = 4 4042 4043class TestVerify(unittest.TestCase): 4044 4045 def test_continuous(self): 4046 @verify(CONTINUOUS) 4047 class Auto(Enum): 4048 FIRST = auto() 4049 SECOND = auto() 4050 THIRD = auto() 4051 FORTH = auto() 4052 # 4053 @verify(CONTINUOUS) 4054 class Manual(Enum): 4055 FIRST = 3 4056 SECOND = 4 4057 THIRD = 5 4058 FORTH = 6 4059 # 4060 with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'): 4061 @verify(CONTINUOUS) 4062 class Missing(Enum): 4063 FIRST = 3 4064 SECOND = 4 4065 THIRD = 11 4066 FORTH = 13 4067 # 4068 with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'): 4069 @verify(CONTINUOUS) 4070 class Incomplete(Flag): 4071 FIRST = 4 4072 SECOND = 8 4073 THIRD = 16 4074 FORTH = 64 4075 # 4076 with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'): 4077 @verify(CONTINUOUS) 4078 class StillIncomplete(Flag): 4079 FIRST = 4 4080 SECOND = 8 4081 THIRD = 11 4082 FORTH = 32 4083 4084 4085 def test_composite(self): 4086 class Bizarre(Flag): 4087 b = 3 4088 c = 4 4089 d = 6 4090 self.assertEqual(list(Bizarre), [Bizarre.c]) 4091 self.assertEqual(Bizarre.b.value, 3) 4092 self.assertEqual(Bizarre.c.value, 4) 4093 self.assertEqual(Bizarre.d.value, 6) 4094 with self.assertRaisesRegex( 4095 ValueError, 4096 "invalid Flag 'Bizarre': aliases b and d are missing combined values of 0x3 .use enum.show_flag_values.value. for details.", 4097 ): 4098 @verify(NAMED_FLAGS) 4099 class Bizarre(Flag): 4100 b = 3 4101 c = 4 4102 d = 6 4103 # 4104 self.assertEqual(enum.show_flag_values(3), [1, 2]) 4105 class Bizarre(IntFlag): 4106 b = 3 4107 c = 4 4108 d = 6 4109 self.assertEqual(list(Bizarre), [Bizarre.c]) 4110 self.assertEqual(Bizarre.b.value, 3) 4111 self.assertEqual(Bizarre.c.value, 4) 4112 self.assertEqual(Bizarre.d.value, 6) 4113 with self.assertRaisesRegex( 4114 ValueError, 4115 "invalid Flag 'Bizarre': alias d is missing value 0x2 .use enum.show_flag_values.value. for details.", 4116 ): 4117 @verify(NAMED_FLAGS) 4118 class Bizarre(IntFlag): 4119 c = 4 4120 d = 6 4121 self.assertEqual(enum.show_flag_values(2), [2]) 4122 4123 def test_unique_clean(self): 4124 @verify(UNIQUE) 4125 class Clean(Enum): 4126 one = 1 4127 two = 'dos' 4128 tres = 4.0 4129 # 4130 @verify(UNIQUE) 4131 class Cleaner(IntEnum): 4132 single = 1 4133 double = 2 4134 triple = 3 4135 4136 def test_unique_dirty(self): 4137 with self.assertRaisesRegex(ValueError, 'tres.*one'): 4138 @verify(UNIQUE) 4139 class Dirty(Enum): 4140 one = 1 4141 two = 'dos' 4142 tres = 1 4143 with self.assertRaisesRegex( 4144 ValueError, 4145 'double.*single.*turkey.*triple', 4146 ): 4147 @verify(UNIQUE) 4148 class Dirtier(IntEnum): 4149 single = 1 4150 double = 1 4151 triple = 3 4152 turkey = 3 4153 4154 def test_unique_with_name(self): 4155 @verify(UNIQUE) 4156 class Silly(Enum): 4157 one = 1 4158 two = 'dos' 4159 name = 3 4160 # 4161 @verify(UNIQUE) 4162 class Sillier(IntEnum): 4163 single = 1 4164 name = 2 4165 triple = 3 4166 value = 4 4167 4168class TestHelpers(unittest.TestCase): 4169 4170 sunder_names = '_bad_', '_good_', '_what_ho_' 4171 dunder_names = '__mal__', '__bien__', '__que_que__' 4172 private_names = '_MyEnum__private', '_MyEnum__still_private' 4173 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_' 4174 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__' 4175 4176 def test_sunder(self): 4177 for name in self.sunder_names + self.private_and_sunder_names: 4178 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name) 4179 for name in self.dunder_names + self.private_names + self.random_names: 4180 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name) 4181 4182 def test_dunder(self): 4183 for name in self.dunder_names: 4184 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name) 4185 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names: 4186 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name) 4187 4188 def test_is_private(self): 4189 for name in self.private_names + self.private_and_sunder_names: 4190 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?') 4191 for name in self.sunder_names + self.dunder_names + self.random_names: 4192 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?') 4193 4194class TestEnumTypeSubclassing(unittest.TestCase): 4195 pass 4196 4197expected_help_output_with_docs = """\ 4198Help on class Color in module %s: 4199 4200class Color(enum.Enum) 4201 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None) 4202 |\x20\x20 4203 | An enumeration. 4204 |\x20\x20 4205 | Method resolution order: 4206 | Color 4207 | enum.Enum 4208 | builtins.object 4209 |\x20\x20 4210 | Data and other attributes defined here: 4211 |\x20\x20 4212 | blue = Color.blue 4213 |\x20\x20 4214 | green = Color.green 4215 |\x20\x20 4216 | red = Color.red 4217 |\x20\x20 4218 | ---------------------------------------------------------------------- 4219 | Data descriptors inherited from enum.Enum: 4220 |\x20\x20 4221 | name 4222 | The name of the Enum member. 4223 |\x20\x20 4224 | value 4225 | The value of the Enum member. 4226 |\x20\x20 4227 | ---------------------------------------------------------------------- 4228 | Readonly properties inherited from enum.EnumType: 4229 |\x20\x20 4230 | __members__ 4231 | Returns a mapping of member name->value. 4232 |\x20\x20\x20\x20\x20\x20 4233 | This mapping lists all enum members, including aliases. Note that this 4234 | is a read-only view of the internal mapping.""" 4235 4236expected_help_output_without_docs = """\ 4237Help on class Color in module %s: 4238 4239class Color(enum.Enum) 4240 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1) 4241 |\x20\x20 4242 | Method resolution order: 4243 | Color 4244 | enum.Enum 4245 | builtins.object 4246 |\x20\x20 4247 | Data and other attributes defined here: 4248 |\x20\x20 4249 | blue = Color.blue 4250 |\x20\x20 4251 | green = Color.green 4252 |\x20\x20 4253 | red = Color.red 4254 |\x20\x20 4255 | ---------------------------------------------------------------------- 4256 | Data descriptors inherited from enum.Enum: 4257 |\x20\x20 4258 | name 4259 |\x20\x20 4260 | value 4261 |\x20\x20 4262 | ---------------------------------------------------------------------- 4263 | Data descriptors inherited from enum.EnumType: 4264 |\x20\x20 4265 | __members__""" 4266 4267class TestStdLib(unittest.TestCase): 4268 4269 maxDiff = None 4270 4271 class Color(Enum): 4272 red = 1 4273 green = 2 4274 blue = 3 4275 4276 def test_pydoc(self): 4277 # indirectly test __objclass__ 4278 if StrEnum.__doc__ is None: 4279 expected_text = expected_help_output_without_docs % __name__ 4280 else: 4281 expected_text = expected_help_output_with_docs % __name__ 4282 output = StringIO() 4283 helper = pydoc.Helper(output=output) 4284 helper(self.Color) 4285 result = output.getvalue().strip() 4286 self.assertEqual(result, expected_text) 4287 4288 def test_inspect_getmembers(self): 4289 values = dict(( 4290 ('__class__', EnumType), 4291 ('__doc__', 'An enumeration.'), 4292 ('__members__', self.Color.__members__), 4293 ('__module__', __name__), 4294 ('blue', self.Color.blue), 4295 ('green', self.Color.green), 4296 ('name', Enum.__dict__['name']), 4297 ('red', self.Color.red), 4298 ('value', Enum.__dict__['value']), 4299 )) 4300 result = dict(inspect.getmembers(self.Color)) 4301 self.assertEqual(set(values.keys()), set(result.keys())) 4302 failed = False 4303 for k in values.keys(): 4304 if result[k] != values[k]: 4305 print() 4306 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' % 4307 ('=' * 75, k, result[k], values[k], '=' * 75), sep='') 4308 failed = True 4309 if failed: 4310 self.fail("result does not equal expected, see print above") 4311 4312 def test_inspect_classify_class_attrs(self): 4313 # indirectly test __objclass__ 4314 from inspect import Attribute 4315 values = [ 4316 Attribute(name='__class__', kind='data', 4317 defining_class=object, object=EnumType), 4318 Attribute(name='__doc__', kind='data', 4319 defining_class=self.Color, object='An enumeration.'), 4320 Attribute(name='__members__', kind='property', 4321 defining_class=EnumType, object=EnumType.__members__), 4322 Attribute(name='__module__', kind='data', 4323 defining_class=self.Color, object=__name__), 4324 Attribute(name='blue', kind='data', 4325 defining_class=self.Color, object=self.Color.blue), 4326 Attribute(name='green', kind='data', 4327 defining_class=self.Color, object=self.Color.green), 4328 Attribute(name='red', kind='data', 4329 defining_class=self.Color, object=self.Color.red), 4330 Attribute(name='name', kind='data', 4331 defining_class=Enum, object=Enum.__dict__['name']), 4332 Attribute(name='value', kind='data', 4333 defining_class=Enum, object=Enum.__dict__['value']), 4334 ] 4335 values.sort(key=lambda item: item.name) 4336 result = list(inspect.classify_class_attrs(self.Color)) 4337 result.sort(key=lambda item: item.name) 4338 self.assertEqual( 4339 len(values), len(result), 4340 "%s != %s" % ([a.name for a in values], [a.name for a in result]) 4341 ) 4342 failed = False 4343 for v, r in zip(values, result): 4344 if r != v: 4345 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='') 4346 failed = True 4347 if failed: 4348 self.fail("result does not equal expected, see print above") 4349 4350 def test_test_simple_enum(self): 4351 @_simple_enum(Enum) 4352 class SimpleColor: 4353 RED = 1 4354 GREEN = 2 4355 BLUE = 3 4356 class CheckedColor(Enum): 4357 RED = 1 4358 GREEN = 2 4359 BLUE = 3 4360 self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None) 4361 SimpleColor.GREEN._value_ = 9 4362 self.assertRaisesRegex( 4363 TypeError, "enum mismatch", 4364 _test_simple_enum, CheckedColor, SimpleColor, 4365 ) 4366 class CheckedMissing(IntFlag, boundary=KEEP): 4367 SIXTY_FOUR = 64 4368 ONE_TWENTY_EIGHT = 128 4369 TWENTY_FORTY_EIGHT = 2048 4370 ALL = 2048 + 128 + 64 + 12 4371 CM = CheckedMissing 4372 self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT]) 4373 # 4374 @_simple_enum(IntFlag, boundary=KEEP) 4375 class Missing: 4376 SIXTY_FOUR = 64 4377 ONE_TWENTY_EIGHT = 128 4378 TWENTY_FORTY_EIGHT = 2048 4379 ALL = 2048 + 128 + 64 + 12 4380 M = Missing 4381 self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT]) 4382 # 4383 _test_simple_enum(CheckedMissing, Missing) 4384 4385 4386class MiscTestCase(unittest.TestCase): 4387 def test__all__(self): 4388 support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'}) 4389 4390 4391# These are unordered here on purpose to ensure that declaration order 4392# makes no difference. 4393CONVERT_TEST_NAME_D = 5 4394CONVERT_TEST_NAME_C = 5 4395CONVERT_TEST_NAME_B = 5 4396CONVERT_TEST_NAME_A = 5 # This one should sort first. 4397CONVERT_TEST_NAME_E = 5 4398CONVERT_TEST_NAME_F = 5 4399 4400CONVERT_STRING_TEST_NAME_D = 5 4401CONVERT_STRING_TEST_NAME_C = 5 4402CONVERT_STRING_TEST_NAME_B = 5 4403CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first. 4404CONVERT_STRING_TEST_NAME_E = 5 4405CONVERT_STRING_TEST_NAME_F = 5 4406 4407class TestIntEnumConvert(unittest.TestCase): 4408 def setUp(self): 4409 # Reset the module-level test variables to their original integer 4410 # values, otherwise the already created enum values get converted 4411 # instead. 4412 for suffix in ['A', 'B', 'C', 'D', 'E', 'F']: 4413 globals()[f'CONVERT_TEST_NAME_{suffix}'] = 5 4414 globals()[f'CONVERT_STRING_TEST_NAME_{suffix}'] = 5 4415 4416 def test_convert_value_lookup_priority(self): 4417 test_type = enum.IntEnum._convert_( 4418 'UnittestConvert', 4419 MODULE, 4420 filter=lambda x: x.startswith('CONVERT_TEST_')) 4421 # We don't want the reverse lookup value to vary when there are 4422 # multiple possible names for a given value. It should always 4423 # report the first lexigraphical name in that case. 4424 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A') 4425 4426 def test_convert(self): 4427 test_type = enum.IntEnum._convert_( 4428 'UnittestConvert', 4429 MODULE, 4430 filter=lambda x: x.startswith('CONVERT_TEST_')) 4431 # Ensure that test_type has all of the desired names and values. 4432 self.assertEqual(test_type.CONVERT_TEST_NAME_F, 4433 test_type.CONVERT_TEST_NAME_A) 4434 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5) 4435 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5) 4436 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5) 4437 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5) 4438 # Ensure that test_type only picked up names matching the filter. 4439 self.assertEqual([name for name in dir(test_type) 4440 if name[0:2] not in ('CO', '__') 4441 and name not in dir(IntEnum)], 4442 [], msg='Names other than CONVERT_TEST_* found.') 4443 4444 @unittest.skipUnless(python_version == (3, 8), 4445 '_convert was deprecated in 3.8') 4446 def test_convert_warn(self): 4447 with self.assertWarns(DeprecationWarning): 4448 enum.IntEnum._convert( 4449 'UnittestConvert', 4450 MODULE, 4451 filter=lambda x: x.startswith('CONVERT_TEST_')) 4452 4453 @unittest.skipUnless(python_version >= (3, 9), 4454 '_convert was removed in 3.9') 4455 def test_convert_raise(self): 4456 with self.assertRaises(AttributeError): 4457 enum.IntEnum._convert( 4458 'UnittestConvert', 4459 MODULE, 4460 filter=lambda x: x.startswith('CONVERT_TEST_')) 4461 4462 def test_convert_repr_and_str(self): 4463 test_type = enum.IntEnum._convert_( 4464 'UnittestConvert', 4465 MODULE, 4466 filter=lambda x: x.startswith('CONVERT_STRING_TEST_')) 4467 self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE) 4468 self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A') 4469 self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5') 4470 4471# global names for StrEnum._convert_ test 4472CONVERT_STR_TEST_2 = 'goodbye' 4473CONVERT_STR_TEST_1 = 'hello' 4474 4475class TestStrEnumConvert(unittest.TestCase): 4476 def setUp(self): 4477 global CONVERT_STR_TEST_1 4478 global CONVERT_STR_TEST_2 4479 CONVERT_STR_TEST_2 = 'goodbye' 4480 CONVERT_STR_TEST_1 = 'hello' 4481 4482 def test_convert(self): 4483 test_type = enum.StrEnum._convert_( 4484 'UnittestConvert', 4485 MODULE, 4486 filter=lambda x: x.startswith('CONVERT_STR_')) 4487 # Ensure that test_type has all of the desired names and values. 4488 self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello') 4489 self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye') 4490 # Ensure that test_type only picked up names matching the filter. 4491 self.assertEqual([name for name in dir(test_type) 4492 if name[0:2] not in ('CO', '__') 4493 and name not in dir(StrEnum)], 4494 [], msg='Names other than CONVERT_STR_* found.') 4495 4496 def test_convert_repr_and_str(self): 4497 test_type = enum.StrEnum._convert_( 4498 'UnittestConvert', 4499 MODULE, 4500 filter=lambda x: x.startswith('CONVERT_STR_')) 4501 self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE) 4502 self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye') 4503 self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello') 4504 4505 4506if __name__ == '__main__': 4507 unittest.main() 4508