1import enum 2import inspect 3import pydoc 4import sys 5import unittest 6import threading 7from collections import OrderedDict 8from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto 9from io import StringIO 10from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL 11from test.support import ALWAYS_EQ, check__all__, threading_helper 12from datetime import timedelta 13 14python_version = sys.version_info[:2] 15 16# for pickle tests 17try: 18 class Stooges(Enum): 19 LARRY = 1 20 CURLY = 2 21 MOE = 3 22except Exception as exc: 23 Stooges = exc 24 25try: 26 class IntStooges(int, Enum): 27 LARRY = 1 28 CURLY = 2 29 MOE = 3 30except Exception as exc: 31 IntStooges = exc 32 33try: 34 class FloatStooges(float, Enum): 35 LARRY = 1.39 36 CURLY = 2.72 37 MOE = 3.142596 38except Exception as exc: 39 FloatStooges = exc 40 41try: 42 class FlagStooges(Flag): 43 LARRY = 1 44 CURLY = 2 45 MOE = 3 46except Exception as exc: 47 FlagStooges = exc 48 49# for pickle test and subclass tests 50try: 51 class StrEnum(str, Enum): 52 'accepts only string values' 53 class Name(StrEnum): 54 BDFL = 'Guido van Rossum' 55 FLUFL = 'Barry Warsaw' 56except Exception as exc: 57 Name = exc 58 59try: 60 Question = Enum('Question', 'who what when where why', module=__name__) 61except Exception as exc: 62 Question = exc 63 64try: 65 Answer = Enum('Answer', 'him this then there because') 66except Exception as exc: 67 Answer = exc 68 69try: 70 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition') 71except Exception as exc: 72 Theory = exc 73 74# for doctests 75try: 76 class Fruit(Enum): 77 TOMATO = 1 78 BANANA = 2 79 CHERRY = 3 80except Exception: 81 pass 82 83def test_pickle_dump_load(assertion, source, target=None): 84 if target is None: 85 target = source 86 for protocol in range(HIGHEST_PROTOCOL + 1): 87 assertion(loads(dumps(source, protocol=protocol)), target) 88 89def test_pickle_exception(assertion, exception, obj): 90 for protocol in range(HIGHEST_PROTOCOL + 1): 91 with assertion(exception): 92 dumps(obj, protocol=protocol) 93 94class TestHelpers(unittest.TestCase): 95 # _is_descriptor, _is_sunder, _is_dunder 96 97 def test_is_descriptor(self): 98 class foo: 99 pass 100 for attr in ('__get__','__set__','__delete__'): 101 obj = foo() 102 self.assertFalse(enum._is_descriptor(obj)) 103 setattr(obj, attr, 1) 104 self.assertTrue(enum._is_descriptor(obj)) 105 106 def test_is_sunder(self): 107 for s in ('_a_', '_aa_'): 108 self.assertTrue(enum._is_sunder(s)) 109 110 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_', 111 '__', '___', '____', '_____',): 112 self.assertFalse(enum._is_sunder(s)) 113 114 def test_is_dunder(self): 115 for s in ('__a__', '__aa__'): 116 self.assertTrue(enum._is_dunder(s)) 117 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_', 118 '__', '___', '____', '_____',): 119 self.assertFalse(enum._is_dunder(s)) 120 121# for subclassing tests 122 123class classproperty: 124 125 def __init__(self, fget=None, fset=None, fdel=None, doc=None): 126 self.fget = fget 127 self.fset = fset 128 self.fdel = fdel 129 if doc is None and fget is not None: 130 doc = fget.__doc__ 131 self.__doc__ = doc 132 133 def __get__(self, instance, ownerclass): 134 return self.fget(ownerclass) 135 136 137# tests 138 139class TestEnum(unittest.TestCase): 140 141 def setUp(self): 142 class Season(Enum): 143 SPRING = 1 144 SUMMER = 2 145 AUTUMN = 3 146 WINTER = 4 147 self.Season = Season 148 149 class Konstants(float, Enum): 150 E = 2.7182818 151 PI = 3.1415926 152 TAU = 2 * PI 153 self.Konstants = Konstants 154 155 class Grades(IntEnum): 156 A = 5 157 B = 4 158 C = 3 159 D = 2 160 F = 0 161 self.Grades = Grades 162 163 class Directional(str, Enum): 164 EAST = 'east' 165 WEST = 'west' 166 NORTH = 'north' 167 SOUTH = 'south' 168 self.Directional = Directional 169 170 from datetime import date 171 class Holiday(date, Enum): 172 NEW_YEAR = 2013, 1, 1 173 IDES_OF_MARCH = 2013, 3, 15 174 self.Holiday = Holiday 175 176 def test_dir_on_class(self): 177 Season = self.Season 178 self.assertEqual( 179 set(dir(Season)), 180 set(['__class__', '__doc__', '__members__', '__module__', 181 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']), 182 ) 183 184 def test_dir_on_item(self): 185 Season = self.Season 186 self.assertEqual( 187 set(dir(Season.WINTER)), 188 set(['__class__', '__doc__', '__module__', 'name', 'value']), 189 ) 190 191 def test_dir_with_added_behavior(self): 192 class Test(Enum): 193 this = 'that' 194 these = 'those' 195 def wowser(self): 196 return ("Wowser! I'm %s!" % self.name) 197 self.assertEqual( 198 set(dir(Test)), 199 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']), 200 ) 201 self.assertEqual( 202 set(dir(Test.this)), 203 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']), 204 ) 205 206 def test_dir_on_sub_with_behavior_on_super(self): 207 # see issue22506 208 class SuperEnum(Enum): 209 def invisible(self): 210 return "did you see me?" 211 class SubEnum(SuperEnum): 212 sample = 5 213 self.assertEqual( 214 set(dir(SubEnum.sample)), 215 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']), 216 ) 217 218 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self): 219 # see issue40084 220 class SuperEnum(IntEnum): 221 def __new__(cls, value, description=""): 222 obj = int.__new__(cls, value) 223 obj._value_ = value 224 obj.description = description 225 return obj 226 class SubEnum(SuperEnum): 227 sample = 5 228 self.assertTrue({'description'} <= set(dir(SubEnum.sample))) 229 230 def test_enum_in_enum_out(self): 231 Season = self.Season 232 self.assertIs(Season(Season.WINTER), Season.WINTER) 233 234 def test_enum_value(self): 235 Season = self.Season 236 self.assertEqual(Season.SPRING.value, 1) 237 238 def test_intenum_value(self): 239 self.assertEqual(IntStooges.CURLY.value, 2) 240 241 def test_enum(self): 242 Season = self.Season 243 lst = list(Season) 244 self.assertEqual(len(lst), len(Season)) 245 self.assertEqual(len(Season), 4, Season) 246 self.assertEqual( 247 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst) 248 249 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1): 250 e = Season(i) 251 self.assertEqual(e, getattr(Season, season)) 252 self.assertEqual(e.value, i) 253 self.assertNotEqual(e, i) 254 self.assertEqual(e.name, season) 255 self.assertIn(e, Season) 256 self.assertIs(type(e), Season) 257 self.assertIsInstance(e, Season) 258 self.assertEqual(str(e), 'Season.' + season) 259 self.assertEqual( 260 repr(e), 261 '<Season.{0}: {1}>'.format(season, i), 262 ) 263 264 def test_value_name(self): 265 Season = self.Season 266 self.assertEqual(Season.SPRING.name, 'SPRING') 267 self.assertEqual(Season.SPRING.value, 1) 268 with self.assertRaises(AttributeError): 269 Season.SPRING.name = 'invierno' 270 with self.assertRaises(AttributeError): 271 Season.SPRING.value = 2 272 273 def test_changing_member(self): 274 Season = self.Season 275 with self.assertRaises(AttributeError): 276 Season.WINTER = 'really cold' 277 278 def test_attribute_deletion(self): 279 class Season(Enum): 280 SPRING = 1 281 SUMMER = 2 282 AUTUMN = 3 283 WINTER = 4 284 285 def spam(cls): 286 pass 287 288 self.assertTrue(hasattr(Season, 'spam')) 289 del Season.spam 290 self.assertFalse(hasattr(Season, 'spam')) 291 292 with self.assertRaises(AttributeError): 293 del Season.SPRING 294 with self.assertRaises(AttributeError): 295 del Season.DRY 296 with self.assertRaises(AttributeError): 297 del Season.SPRING.name 298 299 def test_bool_of_class(self): 300 class Empty(Enum): 301 pass 302 self.assertTrue(bool(Empty)) 303 304 def test_bool_of_member(self): 305 class Count(Enum): 306 zero = 0 307 one = 1 308 two = 2 309 for member in Count: 310 self.assertTrue(bool(member)) 311 312 def test_invalid_names(self): 313 with self.assertRaises(ValueError): 314 class Wrong(Enum): 315 mro = 9 316 with self.assertRaises(ValueError): 317 class Wrong(Enum): 318 _create_= 11 319 with self.assertRaises(ValueError): 320 class Wrong(Enum): 321 _get_mixins_ = 9 322 with self.assertRaises(ValueError): 323 class Wrong(Enum): 324 _find_new_ = 1 325 with self.assertRaises(ValueError): 326 class Wrong(Enum): 327 _any_name_ = 9 328 329 def test_bool(self): 330 # plain Enum members are always True 331 class Logic(Enum): 332 true = True 333 false = False 334 self.assertTrue(Logic.true) 335 self.assertTrue(Logic.false) 336 # unless overridden 337 class RealLogic(Enum): 338 true = True 339 false = False 340 def __bool__(self): 341 return bool(self._value_) 342 self.assertTrue(RealLogic.true) 343 self.assertFalse(RealLogic.false) 344 # mixed Enums depend on mixed-in type 345 class IntLogic(int, Enum): 346 true = 1 347 false = 0 348 self.assertTrue(IntLogic.true) 349 self.assertFalse(IntLogic.false) 350 351 @unittest.skipIf( 352 python_version >= (3, 12), 353 '__contains__ now returns True/False for all inputs', 354 ) 355 def test_contains_er(self): 356 Season = self.Season 357 self.assertIn(Season.AUTUMN, Season) 358 with self.assertRaises(TypeError): 359 with self.assertWarns(DeprecationWarning): 360 3 in Season 361 with self.assertRaises(TypeError): 362 with self.assertWarns(DeprecationWarning): 363 'AUTUMN' in Season 364 val = Season(3) 365 self.assertIn(val, Season) 366 # 367 class OtherEnum(Enum): 368 one = 1; two = 2 369 self.assertNotIn(OtherEnum.two, Season) 370 371 @unittest.skipIf( 372 python_version < (3, 12), 373 '__contains__ only works with enum memmbers before 3.12', 374 ) 375 def test_contains_tf(self): 376 Season = self.Season 377 self.assertIn(Season.AUTUMN, Season) 378 self.assertTrue(3 in Season) 379 self.assertFalse('AUTUMN' in Season) 380 val = Season(3) 381 self.assertIn(val, Season) 382 # 383 class OtherEnum(Enum): 384 one = 1; two = 2 385 self.assertNotIn(OtherEnum.two, Season) 386 387 def test_comparisons(self): 388 Season = self.Season 389 with self.assertRaises(TypeError): 390 Season.SPRING < Season.WINTER 391 with self.assertRaises(TypeError): 392 Season.SPRING > 4 393 394 self.assertNotEqual(Season.SPRING, 1) 395 396 class Part(Enum): 397 SPRING = 1 398 CLIP = 2 399 BARREL = 3 400 401 self.assertNotEqual(Season.SPRING, Part.SPRING) 402 with self.assertRaises(TypeError): 403 Season.SPRING < Part.CLIP 404 405 def test_enum_duplicates(self): 406 class Season(Enum): 407 SPRING = 1 408 SUMMER = 2 409 AUTUMN = FALL = 3 410 WINTER = 4 411 ANOTHER_SPRING = 1 412 lst = list(Season) 413 self.assertEqual( 414 lst, 415 [Season.SPRING, Season.SUMMER, 416 Season.AUTUMN, Season.WINTER, 417 ]) 418 self.assertIs(Season.FALL, Season.AUTUMN) 419 self.assertEqual(Season.FALL.value, 3) 420 self.assertEqual(Season.AUTUMN.value, 3) 421 self.assertIs(Season(3), Season.AUTUMN) 422 self.assertIs(Season(1), Season.SPRING) 423 self.assertEqual(Season.FALL.name, 'AUTUMN') 424 self.assertEqual( 425 [k for k,v in Season.__members__.items() if v.name != k], 426 ['FALL', 'ANOTHER_SPRING'], 427 ) 428 429 def test_duplicate_name(self): 430 with self.assertRaises(TypeError): 431 class Color(Enum): 432 red = 1 433 green = 2 434 blue = 3 435 red = 4 436 437 with self.assertRaises(TypeError): 438 class Color(Enum): 439 red = 1 440 green = 2 441 blue = 3 442 def red(self): 443 return 'red' 444 445 with self.assertRaises(TypeError): 446 class Color(Enum): 447 @property 448 def red(self): 449 return 'redder' 450 red = 1 451 green = 2 452 blue = 3 453 454 455 def test_enum_with_value_name(self): 456 class Huh(Enum): 457 name = 1 458 value = 2 459 self.assertEqual( 460 list(Huh), 461 [Huh.name, Huh.value], 462 ) 463 self.assertIs(type(Huh.name), Huh) 464 self.assertEqual(Huh.name.name, 'name') 465 self.assertEqual(Huh.name.value, 1) 466 467 def test_format_enum(self): 468 Season = self.Season 469 self.assertEqual('{}'.format(Season.SPRING), 470 '{}'.format(str(Season.SPRING))) 471 self.assertEqual( '{:}'.format(Season.SPRING), 472 '{:}'.format(str(Season.SPRING))) 473 self.assertEqual('{:20}'.format(Season.SPRING), 474 '{:20}'.format(str(Season.SPRING))) 475 self.assertEqual('{:^20}'.format(Season.SPRING), 476 '{:^20}'.format(str(Season.SPRING))) 477 self.assertEqual('{:>20}'.format(Season.SPRING), 478 '{:>20}'.format(str(Season.SPRING))) 479 self.assertEqual('{:<20}'.format(Season.SPRING), 480 '{:<20}'.format(str(Season.SPRING))) 481 482 def test_str_override_enum(self): 483 class EnumWithStrOverrides(Enum): 484 one = auto() 485 two = auto() 486 487 def __str__(self): 488 return 'Str!' 489 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!') 490 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!') 491 492 def test_format_override_enum(self): 493 class EnumWithFormatOverride(Enum): 494 one = 1.0 495 two = 2.0 496 def __format__(self, spec): 497 return 'Format!!' 498 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one') 499 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!') 500 501 def test_str_and_format_override_enum(self): 502 class EnumWithStrFormatOverrides(Enum): 503 one = auto() 504 two = auto() 505 def __str__(self): 506 return 'Str!' 507 def __format__(self, spec): 508 return 'Format!' 509 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!') 510 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!') 511 512 def test_str_override_mixin(self): 513 class MixinEnumWithStrOverride(float, Enum): 514 one = 1.0 515 two = 2.0 516 def __str__(self): 517 return 'Overridden!' 518 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!') 519 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!') 520 521 def test_str_and_format_override_mixin(self): 522 class MixinWithStrFormatOverrides(float, Enum): 523 one = 1.0 524 two = 2.0 525 def __str__(self): 526 return 'Str!' 527 def __format__(self, spec): 528 return 'Format!' 529 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!') 530 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!') 531 532 def test_format_override_mixin(self): 533 class TestFloat(float, Enum): 534 one = 1.0 535 two = 2.0 536 def __format__(self, spec): 537 return 'TestFloat success!' 538 self.assertEqual(str(TestFloat.one), 'TestFloat.one') 539 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!') 540 541 def assertFormatIsValue(self, spec, member): 542 self.assertEqual(spec.format(member), spec.format(member.value)) 543 544 def test_format_enum_date(self): 545 Holiday = self.Holiday 546 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH) 547 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH) 548 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH) 549 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH) 550 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH) 551 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH) 552 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH) 553 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH) 554 555 def test_format_enum_float(self): 556 Konstants = self.Konstants 557 self.assertFormatIsValue('{}', Konstants.TAU) 558 self.assertFormatIsValue('{:}', Konstants.TAU) 559 self.assertFormatIsValue('{:20}', Konstants.TAU) 560 self.assertFormatIsValue('{:^20}', Konstants.TAU) 561 self.assertFormatIsValue('{:>20}', Konstants.TAU) 562 self.assertFormatIsValue('{:<20}', Konstants.TAU) 563 self.assertFormatIsValue('{:n}', Konstants.TAU) 564 self.assertFormatIsValue('{:5.2}', Konstants.TAU) 565 self.assertFormatIsValue('{:f}', Konstants.TAU) 566 567 def test_format_enum_int(self): 568 Grades = self.Grades 569 self.assertFormatIsValue('{}', Grades.C) 570 self.assertFormatIsValue('{:}', Grades.C) 571 self.assertFormatIsValue('{:20}', Grades.C) 572 self.assertFormatIsValue('{:^20}', Grades.C) 573 self.assertFormatIsValue('{:>20}', Grades.C) 574 self.assertFormatIsValue('{:<20}', Grades.C) 575 self.assertFormatIsValue('{:+}', Grades.C) 576 self.assertFormatIsValue('{:08X}', Grades.C) 577 self.assertFormatIsValue('{:b}', Grades.C) 578 579 def test_format_enum_str(self): 580 Directional = self.Directional 581 self.assertFormatIsValue('{}', Directional.WEST) 582 self.assertFormatIsValue('{:}', Directional.WEST) 583 self.assertFormatIsValue('{:20}', Directional.WEST) 584 self.assertFormatIsValue('{:^20}', Directional.WEST) 585 self.assertFormatIsValue('{:>20}', Directional.WEST) 586 self.assertFormatIsValue('{:<20}', Directional.WEST) 587 588 def test_object_str_override(self): 589 class Colors(Enum): 590 RED, GREEN, BLUE = 1, 2, 3 591 def __repr__(self): 592 return "test.%s" % (self._name_, ) 593 __str__ = object.__str__ 594 self.assertEqual(str(Colors.RED), 'test.RED') 595 596 def test_enum_str_override(self): 597 class MyStrEnum(Enum): 598 def __str__(self): 599 return 'MyStr' 600 class MyMethodEnum(Enum): 601 def hello(self): 602 return 'Hello! My name is %s' % self.name 603 class Test1Enum(MyMethodEnum, int, MyStrEnum): 604 One = 1 605 Two = 2 606 self.assertTrue(Test1Enum._member_type_ is int) 607 self.assertEqual(str(Test1Enum.One), 'MyStr') 608 self.assertEqual(format(Test1Enum.One, ''), 'MyStr') 609 # 610 class Test2Enum(MyStrEnum, MyMethodEnum): 611 One = 1 612 Two = 2 613 self.assertEqual(str(Test2Enum.One), 'MyStr') 614 self.assertEqual(format(Test1Enum.One, ''), 'MyStr') 615 616 def test_inherited_data_type(self): 617 class HexInt(int): 618 __qualname__ = 'HexInt' 619 def __repr__(self): 620 return hex(self) 621 class MyEnum(HexInt, enum.Enum): 622 __qualname__ = 'MyEnum' 623 A = 1 624 B = 2 625 C = 3 626 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>') 627 globals()['HexInt'] = HexInt 628 globals()['MyEnum'] = MyEnum 629 test_pickle_dump_load(self.assertIs, MyEnum.A) 630 test_pickle_dump_load(self.assertIs, MyEnum) 631 # 632 class SillyInt(HexInt): 633 __qualname__ = 'SillyInt' 634 pass 635 class MyOtherEnum(SillyInt, enum.Enum): 636 __qualname__ = 'MyOtherEnum' 637 D = 4 638 E = 5 639 F = 6 640 self.assertIs(MyOtherEnum._member_type_, SillyInt) 641 globals()['SillyInt'] = SillyInt 642 globals()['MyOtherEnum'] = MyOtherEnum 643 test_pickle_dump_load(self.assertIs, MyOtherEnum.E) 644 test_pickle_dump_load(self.assertIs, MyOtherEnum) 645 # 646 class BrokenInt(int): 647 __qualname__ = 'BrokenInt' 648 def __new__(cls, value): 649 return int.__new__(cls, value) 650 class MyBrokenEnum(BrokenInt, Enum): 651 __qualname__ = 'MyBrokenEnum' 652 G = 7 653 H = 8 654 I = 9 655 self.assertIs(MyBrokenEnum._member_type_, BrokenInt) 656 self.assertIs(MyBrokenEnum(7), MyBrokenEnum.G) 657 globals()['BrokenInt'] = BrokenInt 658 globals()['MyBrokenEnum'] = MyBrokenEnum 659 test_pickle_exception(self.assertRaises, TypeError, MyBrokenEnum.G) 660 test_pickle_exception(self.assertRaises, PicklingError, MyBrokenEnum) 661 662 def test_too_many_data_types(self): 663 with self.assertRaisesRegex(TypeError, 'too many data types'): 664 class Huh(str, int, Enum): 665 One = 1 666 667 class MyStr(str): 668 def hello(self): 669 return 'hello, %s' % self 670 class MyInt(int): 671 def repr(self): 672 return hex(self) 673 with self.assertRaisesRegex(TypeError, 'too many data types'): 674 class Huh(MyStr, MyInt, Enum): 675 One = 1 676 677 def test_hash(self): 678 Season = self.Season 679 dates = {} 680 dates[Season.WINTER] = '1225' 681 dates[Season.SPRING] = '0315' 682 dates[Season.SUMMER] = '0704' 683 dates[Season.AUTUMN] = '1031' 684 self.assertEqual(dates[Season.AUTUMN], '1031') 685 686 def test_intenum_from_scratch(self): 687 class phy(int, Enum): 688 pi = 3 689 tau = 2 * pi 690 self.assertTrue(phy.pi < phy.tau) 691 692 def test_intenum_inherited(self): 693 class IntEnum(int, Enum): 694 pass 695 class phy(IntEnum): 696 pi = 3 697 tau = 2 * pi 698 self.assertTrue(phy.pi < phy.tau) 699 700 def test_floatenum_from_scratch(self): 701 class phy(float, Enum): 702 pi = 3.1415926 703 tau = 2 * pi 704 self.assertTrue(phy.pi < phy.tau) 705 706 def test_floatenum_inherited(self): 707 class FloatEnum(float, Enum): 708 pass 709 class phy(FloatEnum): 710 pi = 3.1415926 711 tau = 2 * pi 712 self.assertTrue(phy.pi < phy.tau) 713 714 def test_strenum_from_scratch(self): 715 class phy(str, Enum): 716 pi = 'Pi' 717 tau = 'Tau' 718 self.assertTrue(phy.pi < phy.tau) 719 720 def test_strenum_inherited(self): 721 class StrEnum(str, Enum): 722 pass 723 class phy(StrEnum): 724 pi = 'Pi' 725 tau = 'Tau' 726 self.assertTrue(phy.pi < phy.tau) 727 728 729 def test_intenum(self): 730 class WeekDay(IntEnum): 731 SUNDAY = 1 732 MONDAY = 2 733 TUESDAY = 3 734 WEDNESDAY = 4 735 THURSDAY = 5 736 FRIDAY = 6 737 SATURDAY = 7 738 739 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c') 740 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2]) 741 742 lst = list(WeekDay) 743 self.assertEqual(len(lst), len(WeekDay)) 744 self.assertEqual(len(WeekDay), 7) 745 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY' 746 target = target.split() 747 for i, weekday in enumerate(target, 1): 748 e = WeekDay(i) 749 self.assertEqual(e, i) 750 self.assertEqual(int(e), i) 751 self.assertEqual(e.name, weekday) 752 self.assertIn(e, WeekDay) 753 self.assertEqual(lst.index(e)+1, i) 754 self.assertTrue(0 < e < 8) 755 self.assertIs(type(e), WeekDay) 756 self.assertIsInstance(e, int) 757 self.assertIsInstance(e, Enum) 758 759 def test_intenum_duplicates(self): 760 class WeekDay(IntEnum): 761 SUNDAY = 1 762 MONDAY = 2 763 TUESDAY = TEUSDAY = 3 764 WEDNESDAY = 4 765 THURSDAY = 5 766 FRIDAY = 6 767 SATURDAY = 7 768 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY) 769 self.assertEqual(WeekDay(3).name, 'TUESDAY') 770 self.assertEqual([k for k,v in WeekDay.__members__.items() 771 if v.name != k], ['TEUSDAY', ]) 772 773 def test_intenum_from_bytes(self): 774 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE) 775 with self.assertRaises(ValueError): 776 IntStooges.from_bytes(b'\x00\x05', 'big') 777 778 def test_floatenum_fromhex(self): 779 h = float.hex(FloatStooges.MOE.value) 780 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE) 781 h = float.hex(FloatStooges.MOE.value + 0.01) 782 with self.assertRaises(ValueError): 783 FloatStooges.fromhex(h) 784 785 def test_pickle_enum(self): 786 if isinstance(Stooges, Exception): 787 raise Stooges 788 test_pickle_dump_load(self.assertIs, Stooges.CURLY) 789 test_pickle_dump_load(self.assertIs, Stooges) 790 791 def test_pickle_int(self): 792 if isinstance(IntStooges, Exception): 793 raise IntStooges 794 test_pickle_dump_load(self.assertIs, IntStooges.CURLY) 795 test_pickle_dump_load(self.assertIs, IntStooges) 796 797 def test_pickle_float(self): 798 if isinstance(FloatStooges, Exception): 799 raise FloatStooges 800 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY) 801 test_pickle_dump_load(self.assertIs, FloatStooges) 802 803 def test_pickle_enum_function(self): 804 if isinstance(Answer, Exception): 805 raise Answer 806 test_pickle_dump_load(self.assertIs, Answer.him) 807 test_pickle_dump_load(self.assertIs, Answer) 808 809 def test_pickle_enum_function_with_module(self): 810 if isinstance(Question, Exception): 811 raise Question 812 test_pickle_dump_load(self.assertIs, Question.who) 813 test_pickle_dump_load(self.assertIs, Question) 814 815 def test_enum_function_with_qualname(self): 816 if isinstance(Theory, Exception): 817 raise Theory 818 self.assertEqual(Theory.__qualname__, 'spanish_inquisition') 819 820 def test_class_nested_enum_and_pickle_protocol_four(self): 821 # would normally just have this directly in the class namespace 822 class NestedEnum(Enum): 823 twigs = 'common' 824 shiny = 'rare' 825 826 self.__class__.NestedEnum = NestedEnum 827 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__ 828 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs) 829 830 def test_pickle_by_name(self): 831 class ReplaceGlobalInt(IntEnum): 832 ONE = 1 833 TWO = 2 834 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name 835 for proto in range(HIGHEST_PROTOCOL): 836 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO') 837 838 def test_exploding_pickle(self): 839 BadPickle = Enum( 840 'BadPickle', 'dill sweet bread-n-butter', module=__name__) 841 globals()['BadPickle'] = BadPickle 842 # now break BadPickle to test exception raising 843 enum._make_class_unpicklable(BadPickle) 844 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill) 845 test_pickle_exception(self.assertRaises, PicklingError, BadPickle) 846 847 def test_string_enum(self): 848 class SkillLevel(str, Enum): 849 master = 'what is the sound of one hand clapping?' 850 journeyman = 'why did the chicken cross the road?' 851 apprentice = 'knock, knock!' 852 self.assertEqual(SkillLevel.apprentice, 'knock, knock!') 853 854 def test_getattr_getitem(self): 855 class Period(Enum): 856 morning = 1 857 noon = 2 858 evening = 3 859 night = 4 860 self.assertIs(Period(2), Period.noon) 861 self.assertIs(getattr(Period, 'night'), Period.night) 862 self.assertIs(Period['morning'], Period.morning) 863 864 def test_getattr_dunder(self): 865 Season = self.Season 866 self.assertTrue(getattr(Season, '__eq__')) 867 868 def test_iteration_order(self): 869 class Season(Enum): 870 SUMMER = 2 871 WINTER = 4 872 AUTUMN = 3 873 SPRING = 1 874 self.assertEqual( 875 list(Season), 876 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING], 877 ) 878 879 def test_reversed_iteration_order(self): 880 self.assertEqual( 881 list(reversed(self.Season)), 882 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER, 883 self.Season.SPRING] 884 ) 885 886 def test_programmatic_function_string(self): 887 SummerMonth = Enum('SummerMonth', 'june july august') 888 lst = list(SummerMonth) 889 self.assertEqual(len(lst), len(SummerMonth)) 890 self.assertEqual(len(SummerMonth), 3, SummerMonth) 891 self.assertEqual( 892 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 893 lst, 894 ) 895 for i, month in enumerate('june july august'.split(), 1): 896 e = SummerMonth(i) 897 self.assertEqual(int(e.value), i) 898 self.assertNotEqual(e, i) 899 self.assertEqual(e.name, month) 900 self.assertIn(e, SummerMonth) 901 self.assertIs(type(e), SummerMonth) 902 903 def test_programmatic_function_string_with_start(self): 904 SummerMonth = Enum('SummerMonth', 'june july august', start=10) 905 lst = list(SummerMonth) 906 self.assertEqual(len(lst), len(SummerMonth)) 907 self.assertEqual(len(SummerMonth), 3, SummerMonth) 908 self.assertEqual( 909 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 910 lst, 911 ) 912 for i, month in enumerate('june july august'.split(), 10): 913 e = SummerMonth(i) 914 self.assertEqual(int(e.value), i) 915 self.assertNotEqual(e, i) 916 self.assertEqual(e.name, month) 917 self.assertIn(e, SummerMonth) 918 self.assertIs(type(e), SummerMonth) 919 920 def test_programmatic_function_string_list(self): 921 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august']) 922 lst = list(SummerMonth) 923 self.assertEqual(len(lst), len(SummerMonth)) 924 self.assertEqual(len(SummerMonth), 3, SummerMonth) 925 self.assertEqual( 926 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 927 lst, 928 ) 929 for i, month in enumerate('june july august'.split(), 1): 930 e = SummerMonth(i) 931 self.assertEqual(int(e.value), i) 932 self.assertNotEqual(e, i) 933 self.assertEqual(e.name, month) 934 self.assertIn(e, SummerMonth) 935 self.assertIs(type(e), SummerMonth) 936 937 def test_programmatic_function_string_list_with_start(self): 938 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20) 939 lst = list(SummerMonth) 940 self.assertEqual(len(lst), len(SummerMonth)) 941 self.assertEqual(len(SummerMonth), 3, SummerMonth) 942 self.assertEqual( 943 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 944 lst, 945 ) 946 for i, month in enumerate('june july august'.split(), 20): 947 e = SummerMonth(i) 948 self.assertEqual(int(e.value), i) 949 self.assertNotEqual(e, i) 950 self.assertEqual(e.name, month) 951 self.assertIn(e, SummerMonth) 952 self.assertIs(type(e), SummerMonth) 953 954 def test_programmatic_function_iterable(self): 955 SummerMonth = Enum( 956 'SummerMonth', 957 (('june', 1), ('july', 2), ('august', 3)) 958 ) 959 lst = list(SummerMonth) 960 self.assertEqual(len(lst), len(SummerMonth)) 961 self.assertEqual(len(SummerMonth), 3, SummerMonth) 962 self.assertEqual( 963 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 964 lst, 965 ) 966 for i, month in enumerate('june july august'.split(), 1): 967 e = SummerMonth(i) 968 self.assertEqual(int(e.value), i) 969 self.assertNotEqual(e, i) 970 self.assertEqual(e.name, month) 971 self.assertIn(e, SummerMonth) 972 self.assertIs(type(e), SummerMonth) 973 974 def test_programmatic_function_from_dict(self): 975 SummerMonth = Enum( 976 'SummerMonth', 977 OrderedDict((('june', 1), ('july', 2), ('august', 3))) 978 ) 979 lst = list(SummerMonth) 980 self.assertEqual(len(lst), len(SummerMonth)) 981 self.assertEqual(len(SummerMonth), 3, SummerMonth) 982 self.assertEqual( 983 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 984 lst, 985 ) 986 for i, month in enumerate('june july august'.split(), 1): 987 e = SummerMonth(i) 988 self.assertEqual(int(e.value), i) 989 self.assertNotEqual(e, i) 990 self.assertEqual(e.name, month) 991 self.assertIn(e, SummerMonth) 992 self.assertIs(type(e), SummerMonth) 993 994 def test_programmatic_function_type(self): 995 SummerMonth = Enum('SummerMonth', 'june july august', type=int) 996 lst = list(SummerMonth) 997 self.assertEqual(len(lst), len(SummerMonth)) 998 self.assertEqual(len(SummerMonth), 3, SummerMonth) 999 self.assertEqual( 1000 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1001 lst, 1002 ) 1003 for i, month in enumerate('june july august'.split(), 1): 1004 e = SummerMonth(i) 1005 self.assertEqual(e, i) 1006 self.assertEqual(e.name, month) 1007 self.assertIn(e, SummerMonth) 1008 self.assertIs(type(e), SummerMonth) 1009 1010 def test_programmatic_function_type_with_start(self): 1011 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30) 1012 lst = list(SummerMonth) 1013 self.assertEqual(len(lst), len(SummerMonth)) 1014 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1015 self.assertEqual( 1016 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1017 lst, 1018 ) 1019 for i, month in enumerate('june july august'.split(), 30): 1020 e = SummerMonth(i) 1021 self.assertEqual(e, i) 1022 self.assertEqual(e.name, month) 1023 self.assertIn(e, SummerMonth) 1024 self.assertIs(type(e), SummerMonth) 1025 1026 def test_programmatic_function_type_from_subclass(self): 1027 SummerMonth = IntEnum('SummerMonth', 'june july august') 1028 lst = list(SummerMonth) 1029 self.assertEqual(len(lst), len(SummerMonth)) 1030 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1031 self.assertEqual( 1032 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1033 lst, 1034 ) 1035 for i, month in enumerate('june july august'.split(), 1): 1036 e = SummerMonth(i) 1037 self.assertEqual(e, i) 1038 self.assertEqual(e.name, month) 1039 self.assertIn(e, SummerMonth) 1040 self.assertIs(type(e), SummerMonth) 1041 1042 def test_programmatic_function_type_from_subclass_with_start(self): 1043 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40) 1044 lst = list(SummerMonth) 1045 self.assertEqual(len(lst), len(SummerMonth)) 1046 self.assertEqual(len(SummerMonth), 3, SummerMonth) 1047 self.assertEqual( 1048 [SummerMonth.june, SummerMonth.july, SummerMonth.august], 1049 lst, 1050 ) 1051 for i, month in enumerate('june july august'.split(), 40): 1052 e = SummerMonth(i) 1053 self.assertEqual(e, i) 1054 self.assertEqual(e.name, month) 1055 self.assertIn(e, SummerMonth) 1056 self.assertIs(type(e), SummerMonth) 1057 1058 def test_subclassing(self): 1059 if isinstance(Name, Exception): 1060 raise Name 1061 self.assertEqual(Name.BDFL, 'Guido van Rossum') 1062 self.assertTrue(Name.BDFL, Name('Guido van Rossum')) 1063 self.assertIs(Name.BDFL, getattr(Name, 'BDFL')) 1064 test_pickle_dump_load(self.assertIs, Name.BDFL) 1065 1066 def test_extending(self): 1067 class Color(Enum): 1068 red = 1 1069 green = 2 1070 blue = 3 1071 with self.assertRaises(TypeError): 1072 class MoreColor(Color): 1073 cyan = 4 1074 magenta = 5 1075 yellow = 6 1076 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"): 1077 class EvenMoreColor(Color, IntEnum): 1078 chartruese = 7 1079 1080 def test_exclude_methods(self): 1081 class whatever(Enum): 1082 this = 'that' 1083 these = 'those' 1084 def really(self): 1085 return 'no, not %s' % self.value 1086 self.assertIsNot(type(whatever.really), whatever) 1087 self.assertEqual(whatever.this.really(), 'no, not that') 1088 1089 def test_wrong_inheritance_order(self): 1090 with self.assertRaises(TypeError): 1091 class Wrong(Enum, str): 1092 NotHere = 'error before this point' 1093 1094 def test_intenum_transitivity(self): 1095 class number(IntEnum): 1096 one = 1 1097 two = 2 1098 three = 3 1099 class numero(IntEnum): 1100 uno = 1 1101 dos = 2 1102 tres = 3 1103 self.assertEqual(number.one, numero.uno) 1104 self.assertEqual(number.two, numero.dos) 1105 self.assertEqual(number.three, numero.tres) 1106 1107 def test_wrong_enum_in_call(self): 1108 class Monochrome(Enum): 1109 black = 0 1110 white = 1 1111 class Gender(Enum): 1112 male = 0 1113 female = 1 1114 self.assertRaises(ValueError, Monochrome, Gender.male) 1115 1116 def test_wrong_enum_in_mixed_call(self): 1117 class Monochrome(IntEnum): 1118 black = 0 1119 white = 1 1120 class Gender(Enum): 1121 male = 0 1122 female = 1 1123 self.assertRaises(ValueError, Monochrome, Gender.male) 1124 1125 def test_mixed_enum_in_call_1(self): 1126 class Monochrome(IntEnum): 1127 black = 0 1128 white = 1 1129 class Gender(IntEnum): 1130 male = 0 1131 female = 1 1132 self.assertIs(Monochrome(Gender.female), Monochrome.white) 1133 1134 def test_mixed_enum_in_call_2(self): 1135 class Monochrome(Enum): 1136 black = 0 1137 white = 1 1138 class Gender(IntEnum): 1139 male = 0 1140 female = 1 1141 self.assertIs(Monochrome(Gender.male), Monochrome.black) 1142 1143 def test_flufl_enum(self): 1144 class Fluflnum(Enum): 1145 def __int__(self): 1146 return int(self.value) 1147 class MailManOptions(Fluflnum): 1148 option1 = 1 1149 option2 = 2 1150 option3 = 3 1151 self.assertEqual(int(MailManOptions.option1), 1) 1152 1153 def test_introspection(self): 1154 class Number(IntEnum): 1155 one = 100 1156 two = 200 1157 self.assertIs(Number.one._member_type_, int) 1158 self.assertIs(Number._member_type_, int) 1159 class String(str, Enum): 1160 yarn = 'soft' 1161 rope = 'rough' 1162 wire = 'hard' 1163 self.assertIs(String.yarn._member_type_, str) 1164 self.assertIs(String._member_type_, str) 1165 class Plain(Enum): 1166 vanilla = 'white' 1167 one = 1 1168 self.assertIs(Plain.vanilla._member_type_, object) 1169 self.assertIs(Plain._member_type_, object) 1170 1171 def test_no_such_enum_member(self): 1172 class Color(Enum): 1173 red = 1 1174 green = 2 1175 blue = 3 1176 with self.assertRaises(ValueError): 1177 Color(4) 1178 with self.assertRaises(KeyError): 1179 Color['chartreuse'] 1180 1181 def test_new_repr(self): 1182 class Color(Enum): 1183 red = 1 1184 green = 2 1185 blue = 3 1186 def __repr__(self): 1187 return "don't you just love shades of %s?" % self.name 1188 self.assertEqual( 1189 repr(Color.blue), 1190 "don't you just love shades of blue?", 1191 ) 1192 1193 def test_inherited_repr(self): 1194 class MyEnum(Enum): 1195 def __repr__(self): 1196 return "My name is %s." % self.name 1197 class MyIntEnum(int, MyEnum): 1198 this = 1 1199 that = 2 1200 theother = 3 1201 self.assertEqual(repr(MyIntEnum.that), "My name is that.") 1202 1203 def test_multiple_mixin_mro(self): 1204 class auto_enum(type(Enum)): 1205 def __new__(metacls, cls, bases, classdict): 1206 temp = type(classdict)() 1207 temp._cls_name = cls 1208 names = set(classdict._member_names) 1209 i = 0 1210 for k in classdict._member_names: 1211 v = classdict[k] 1212 if v is Ellipsis: 1213 v = i 1214 else: 1215 i = v 1216 i += 1 1217 temp[k] = v 1218 for k, v in classdict.items(): 1219 if k not in names: 1220 temp[k] = v 1221 return super(auto_enum, metacls).__new__( 1222 metacls, cls, bases, temp) 1223 1224 class AutoNumberedEnum(Enum, metaclass=auto_enum): 1225 pass 1226 1227 class AutoIntEnum(IntEnum, metaclass=auto_enum): 1228 pass 1229 1230 class TestAutoNumber(AutoNumberedEnum): 1231 a = ... 1232 b = 3 1233 c = ... 1234 1235 class TestAutoInt(AutoIntEnum): 1236 a = ... 1237 b = 3 1238 c = ... 1239 1240 def test_subclasses_with_getnewargs(self): 1241 class NamedInt(int): 1242 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1243 def __new__(cls, *args): 1244 _args = args 1245 name, *args = args 1246 if len(args) == 0: 1247 raise TypeError("name and value must be specified") 1248 self = int.__new__(cls, *args) 1249 self._intname = name 1250 self._args = _args 1251 return self 1252 def __getnewargs__(self): 1253 return self._args 1254 @property 1255 def __name__(self): 1256 return self._intname 1257 def __repr__(self): 1258 # repr() is updated to include the name and type info 1259 return "{}({!r}, {})".format(type(self).__name__, 1260 self.__name__, 1261 int.__repr__(self)) 1262 def __str__(self): 1263 # str() is unchanged, even if it relies on the repr() fallback 1264 base = int 1265 base_str = base.__str__ 1266 if base_str.__objclass__ is object: 1267 return base.__repr__(self) 1268 return base_str(self) 1269 # for simplicity, we only define one operator that 1270 # propagates expressions 1271 def __add__(self, other): 1272 temp = int(self) + int( other) 1273 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1274 return NamedInt( 1275 '({0} + {1})'.format(self.__name__, other.__name__), 1276 temp ) 1277 else: 1278 return temp 1279 1280 class NEI(NamedInt, Enum): 1281 __qualname__ = 'NEI' # needed for pickle protocol 4 1282 x = ('the-x', 1) 1283 y = ('the-y', 2) 1284 1285 1286 self.assertIs(NEI.__new__, Enum.__new__) 1287 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1288 globals()['NamedInt'] = NamedInt 1289 globals()['NEI'] = NEI 1290 NI5 = NamedInt('test', 5) 1291 self.assertEqual(NI5, 5) 1292 test_pickle_dump_load(self.assertEqual, NI5, 5) 1293 self.assertEqual(NEI.y.value, 2) 1294 test_pickle_dump_load(self.assertIs, NEI.y) 1295 test_pickle_dump_load(self.assertIs, NEI) 1296 1297 def test_subclasses_with_getnewargs_ex(self): 1298 class NamedInt(int): 1299 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1300 def __new__(cls, *args): 1301 _args = args 1302 name, *args = args 1303 if len(args) == 0: 1304 raise TypeError("name and value must be specified") 1305 self = int.__new__(cls, *args) 1306 self._intname = name 1307 self._args = _args 1308 return self 1309 def __getnewargs_ex__(self): 1310 return self._args, {} 1311 @property 1312 def __name__(self): 1313 return self._intname 1314 def __repr__(self): 1315 # repr() is updated to include the name and type info 1316 return "{}({!r}, {})".format(type(self).__name__, 1317 self.__name__, 1318 int.__repr__(self)) 1319 def __str__(self): 1320 # str() is unchanged, even if it relies on the repr() fallback 1321 base = int 1322 base_str = base.__str__ 1323 if base_str.__objclass__ is object: 1324 return base.__repr__(self) 1325 return base_str(self) 1326 # for simplicity, we only define one operator that 1327 # propagates expressions 1328 def __add__(self, other): 1329 temp = int(self) + int( other) 1330 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1331 return NamedInt( 1332 '({0} + {1})'.format(self.__name__, other.__name__), 1333 temp ) 1334 else: 1335 return temp 1336 1337 class NEI(NamedInt, Enum): 1338 __qualname__ = 'NEI' # needed for pickle protocol 4 1339 x = ('the-x', 1) 1340 y = ('the-y', 2) 1341 1342 1343 self.assertIs(NEI.__new__, Enum.__new__) 1344 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1345 globals()['NamedInt'] = NamedInt 1346 globals()['NEI'] = NEI 1347 NI5 = NamedInt('test', 5) 1348 self.assertEqual(NI5, 5) 1349 test_pickle_dump_load(self.assertEqual, NI5, 5) 1350 self.assertEqual(NEI.y.value, 2) 1351 test_pickle_dump_load(self.assertIs, NEI.y) 1352 test_pickle_dump_load(self.assertIs, NEI) 1353 1354 def test_subclasses_with_reduce(self): 1355 class NamedInt(int): 1356 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1357 def __new__(cls, *args): 1358 _args = args 1359 name, *args = args 1360 if len(args) == 0: 1361 raise TypeError("name and value must be specified") 1362 self = int.__new__(cls, *args) 1363 self._intname = name 1364 self._args = _args 1365 return self 1366 def __reduce__(self): 1367 return self.__class__, self._args 1368 @property 1369 def __name__(self): 1370 return self._intname 1371 def __repr__(self): 1372 # repr() is updated to include the name and type info 1373 return "{}({!r}, {})".format(type(self).__name__, 1374 self.__name__, 1375 int.__repr__(self)) 1376 def __str__(self): 1377 # str() is unchanged, even if it relies on the repr() fallback 1378 base = int 1379 base_str = base.__str__ 1380 if base_str.__objclass__ is object: 1381 return base.__repr__(self) 1382 return base_str(self) 1383 # for simplicity, we only define one operator that 1384 # propagates expressions 1385 def __add__(self, other): 1386 temp = int(self) + int( other) 1387 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1388 return NamedInt( 1389 '({0} + {1})'.format(self.__name__, other.__name__), 1390 temp ) 1391 else: 1392 return temp 1393 1394 class NEI(NamedInt, Enum): 1395 __qualname__ = 'NEI' # needed for pickle protocol 4 1396 x = ('the-x', 1) 1397 y = ('the-y', 2) 1398 1399 1400 self.assertIs(NEI.__new__, Enum.__new__) 1401 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1402 globals()['NamedInt'] = NamedInt 1403 globals()['NEI'] = NEI 1404 NI5 = NamedInt('test', 5) 1405 self.assertEqual(NI5, 5) 1406 test_pickle_dump_load(self.assertEqual, NI5, 5) 1407 self.assertEqual(NEI.y.value, 2) 1408 test_pickle_dump_load(self.assertIs, NEI.y) 1409 test_pickle_dump_load(self.assertIs, NEI) 1410 1411 def test_subclasses_with_reduce_ex(self): 1412 class NamedInt(int): 1413 __qualname__ = 'NamedInt' # needed for pickle protocol 4 1414 def __new__(cls, *args): 1415 _args = args 1416 name, *args = args 1417 if len(args) == 0: 1418 raise TypeError("name and value must be specified") 1419 self = int.__new__(cls, *args) 1420 self._intname = name 1421 self._args = _args 1422 return self 1423 def __reduce_ex__(self, proto): 1424 return self.__class__, self._args 1425 @property 1426 def __name__(self): 1427 return self._intname 1428 def __repr__(self): 1429 # repr() is updated to include the name and type info 1430 return "{}({!r}, {})".format(type(self).__name__, 1431 self.__name__, 1432 int.__repr__(self)) 1433 def __str__(self): 1434 # str() is unchanged, even if it relies on the repr() fallback 1435 base = int 1436 base_str = base.__str__ 1437 if base_str.__objclass__ is object: 1438 return base.__repr__(self) 1439 return base_str(self) 1440 # for simplicity, we only define one operator that 1441 # propagates expressions 1442 def __add__(self, other): 1443 temp = int(self) + int( other) 1444 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1445 return NamedInt( 1446 '({0} + {1})'.format(self.__name__, other.__name__), 1447 temp ) 1448 else: 1449 return temp 1450 1451 class NEI(NamedInt, Enum): 1452 __qualname__ = 'NEI' # needed for pickle protocol 4 1453 x = ('the-x', 1) 1454 y = ('the-y', 2) 1455 1456 1457 self.assertIs(NEI.__new__, Enum.__new__) 1458 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1459 globals()['NamedInt'] = NamedInt 1460 globals()['NEI'] = NEI 1461 NI5 = NamedInt('test', 5) 1462 self.assertEqual(NI5, 5) 1463 test_pickle_dump_load(self.assertEqual, NI5, 5) 1464 self.assertEqual(NEI.y.value, 2) 1465 test_pickle_dump_load(self.assertIs, NEI.y) 1466 test_pickle_dump_load(self.assertIs, NEI) 1467 1468 def test_subclasses_without_direct_pickle_support(self): 1469 class NamedInt(int): 1470 __qualname__ = 'NamedInt' 1471 def __new__(cls, *args): 1472 _args = args 1473 name, *args = args 1474 if len(args) == 0: 1475 raise TypeError("name and value must be specified") 1476 self = int.__new__(cls, *args) 1477 self._intname = name 1478 self._args = _args 1479 return self 1480 @property 1481 def __name__(self): 1482 return self._intname 1483 def __repr__(self): 1484 # repr() is updated to include the name and type info 1485 return "{}({!r}, {})".format(type(self).__name__, 1486 self.__name__, 1487 int.__repr__(self)) 1488 def __str__(self): 1489 # str() is unchanged, even if it relies on the repr() fallback 1490 base = int 1491 base_str = base.__str__ 1492 if base_str.__objclass__ is object: 1493 return base.__repr__(self) 1494 return base_str(self) 1495 # for simplicity, we only define one operator that 1496 # propagates expressions 1497 def __add__(self, other): 1498 temp = int(self) + int( other) 1499 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1500 return NamedInt( 1501 '({0} + {1})'.format(self.__name__, other.__name__), 1502 temp ) 1503 else: 1504 return temp 1505 1506 class NEI(NamedInt, Enum): 1507 __qualname__ = 'NEI' 1508 x = ('the-x', 1) 1509 y = ('the-y', 2) 1510 1511 self.assertIs(NEI.__new__, Enum.__new__) 1512 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1513 globals()['NamedInt'] = NamedInt 1514 globals()['NEI'] = NEI 1515 NI5 = NamedInt('test', 5) 1516 self.assertEqual(NI5, 5) 1517 self.assertEqual(NEI.y.value, 2) 1518 test_pickle_exception(self.assertRaises, TypeError, NEI.x) 1519 test_pickle_exception(self.assertRaises, PicklingError, NEI) 1520 1521 def test_subclasses_without_direct_pickle_support_using_name(self): 1522 class NamedInt(int): 1523 __qualname__ = 'NamedInt' 1524 def __new__(cls, *args): 1525 _args = args 1526 name, *args = args 1527 if len(args) == 0: 1528 raise TypeError("name and value must be specified") 1529 self = int.__new__(cls, *args) 1530 self._intname = name 1531 self._args = _args 1532 return self 1533 @property 1534 def __name__(self): 1535 return self._intname 1536 def __repr__(self): 1537 # repr() is updated to include the name and type info 1538 return "{}({!r}, {})".format(type(self).__name__, 1539 self.__name__, 1540 int.__repr__(self)) 1541 def __str__(self): 1542 # str() is unchanged, even if it relies on the repr() fallback 1543 base = int 1544 base_str = base.__str__ 1545 if base_str.__objclass__ is object: 1546 return base.__repr__(self) 1547 return base_str(self) 1548 # for simplicity, we only define one operator that 1549 # propagates expressions 1550 def __add__(self, other): 1551 temp = int(self) + int( other) 1552 if isinstance(self, NamedInt) and isinstance(other, NamedInt): 1553 return NamedInt( 1554 '({0} + {1})'.format(self.__name__, other.__name__), 1555 temp ) 1556 else: 1557 return temp 1558 1559 class NEI(NamedInt, Enum): 1560 __qualname__ = 'NEI' 1561 x = ('the-x', 1) 1562 y = ('the-y', 2) 1563 def __reduce_ex__(self, proto): 1564 return getattr, (self.__class__, self._name_) 1565 1566 self.assertIs(NEI.__new__, Enum.__new__) 1567 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") 1568 globals()['NamedInt'] = NamedInt 1569 globals()['NEI'] = NEI 1570 NI5 = NamedInt('test', 5) 1571 self.assertEqual(NI5, 5) 1572 self.assertEqual(NEI.y.value, 2) 1573 test_pickle_dump_load(self.assertIs, NEI.y) 1574 test_pickle_dump_load(self.assertIs, NEI) 1575 1576 def test_tuple_subclass(self): 1577 class SomeTuple(tuple, Enum): 1578 __qualname__ = 'SomeTuple' # needed for pickle protocol 4 1579 first = (1, 'for the money') 1580 second = (2, 'for the show') 1581 third = (3, 'for the music') 1582 self.assertIs(type(SomeTuple.first), SomeTuple) 1583 self.assertIsInstance(SomeTuple.second, tuple) 1584 self.assertEqual(SomeTuple.third, (3, 'for the music')) 1585 globals()['SomeTuple'] = SomeTuple 1586 test_pickle_dump_load(self.assertIs, SomeTuple.first) 1587 1588 def test_duplicate_values_give_unique_enum_items(self): 1589 class AutoNumber(Enum): 1590 first = () 1591 second = () 1592 third = () 1593 def __new__(cls): 1594 value = len(cls.__members__) + 1 1595 obj = object.__new__(cls) 1596 obj._value_ = value 1597 return obj 1598 def __int__(self): 1599 return int(self._value_) 1600 self.assertEqual( 1601 list(AutoNumber), 1602 [AutoNumber.first, AutoNumber.second, AutoNumber.third], 1603 ) 1604 self.assertEqual(int(AutoNumber.second), 2) 1605 self.assertEqual(AutoNumber.third.value, 3) 1606 self.assertIs(AutoNumber(1), AutoNumber.first) 1607 1608 def test_inherited_new_from_enhanced_enum(self): 1609 class AutoNumber(Enum): 1610 def __new__(cls): 1611 value = len(cls.__members__) + 1 1612 obj = object.__new__(cls) 1613 obj._value_ = value 1614 return obj 1615 def __int__(self): 1616 return int(self._value_) 1617 class Color(AutoNumber): 1618 red = () 1619 green = () 1620 blue = () 1621 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) 1622 self.assertEqual(list(map(int, Color)), [1, 2, 3]) 1623 1624 def test_inherited_new_from_mixed_enum(self): 1625 class AutoNumber(IntEnum): 1626 def __new__(cls): 1627 value = len(cls.__members__) + 1 1628 obj = int.__new__(cls, value) 1629 obj._value_ = value 1630 return obj 1631 class Color(AutoNumber): 1632 red = () 1633 green = () 1634 blue = () 1635 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) 1636 self.assertEqual(list(map(int, Color)), [1, 2, 3]) 1637 1638 def test_equality(self): 1639 class OrdinaryEnum(Enum): 1640 a = 1 1641 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a) 1642 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ) 1643 1644 def test_ordered_mixin(self): 1645 class OrderedEnum(Enum): 1646 def __ge__(self, other): 1647 if self.__class__ is other.__class__: 1648 return self._value_ >= other._value_ 1649 return NotImplemented 1650 def __gt__(self, other): 1651 if self.__class__ is other.__class__: 1652 return self._value_ > other._value_ 1653 return NotImplemented 1654 def __le__(self, other): 1655 if self.__class__ is other.__class__: 1656 return self._value_ <= other._value_ 1657 return NotImplemented 1658 def __lt__(self, other): 1659 if self.__class__ is other.__class__: 1660 return self._value_ < other._value_ 1661 return NotImplemented 1662 class Grade(OrderedEnum): 1663 A = 5 1664 B = 4 1665 C = 3 1666 D = 2 1667 F = 1 1668 self.assertGreater(Grade.A, Grade.B) 1669 self.assertLessEqual(Grade.F, Grade.C) 1670 self.assertLess(Grade.D, Grade.A) 1671 self.assertGreaterEqual(Grade.B, Grade.B) 1672 self.assertEqual(Grade.B, Grade.B) 1673 self.assertNotEqual(Grade.C, Grade.D) 1674 1675 def test_extending2(self): 1676 class Shade(Enum): 1677 def shade(self): 1678 print(self.name) 1679 class Color(Shade): 1680 red = 1 1681 green = 2 1682 blue = 3 1683 with self.assertRaises(TypeError): 1684 class MoreColor(Color): 1685 cyan = 4 1686 magenta = 5 1687 yellow = 6 1688 1689 def test_extending3(self): 1690 class Shade(Enum): 1691 def shade(self): 1692 return self.name 1693 class Color(Shade): 1694 def hex(self): 1695 return '%s hexlified!' % self.value 1696 class MoreColor(Color): 1697 cyan = 4 1698 magenta = 5 1699 yellow = 6 1700 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!') 1701 1702 def test_subclass_duplicate_name(self): 1703 class Base(Enum): 1704 def test(self): 1705 pass 1706 class Test(Base): 1707 test = 1 1708 self.assertIs(type(Test.test), Test) 1709 1710 def test_subclass_duplicate_name_dynamic(self): 1711 from types import DynamicClassAttribute 1712 class Base(Enum): 1713 @DynamicClassAttribute 1714 def test(self): 1715 return 'dynamic' 1716 class Test(Base): 1717 test = 1 1718 self.assertEqual(Test.test.test, 'dynamic') 1719 1720 def test_no_duplicates(self): 1721 class UniqueEnum(Enum): 1722 def __init__(self, *args): 1723 cls = self.__class__ 1724 if any(self.value == e.value for e in cls): 1725 a = self.name 1726 e = cls(self.value).name 1727 raise ValueError( 1728 "aliases not allowed in UniqueEnum: %r --> %r" 1729 % (a, e) 1730 ) 1731 class Color(UniqueEnum): 1732 red = 1 1733 green = 2 1734 blue = 3 1735 with self.assertRaises(ValueError): 1736 class Color(UniqueEnum): 1737 red = 1 1738 green = 2 1739 blue = 3 1740 grene = 2 1741 1742 def test_init(self): 1743 class Planet(Enum): 1744 MERCURY = (3.303e+23, 2.4397e6) 1745 VENUS = (4.869e+24, 6.0518e6) 1746 EARTH = (5.976e+24, 6.37814e6) 1747 MARS = (6.421e+23, 3.3972e6) 1748 JUPITER = (1.9e+27, 7.1492e7) 1749 SATURN = (5.688e+26, 6.0268e7) 1750 URANUS = (8.686e+25, 2.5559e7) 1751 NEPTUNE = (1.024e+26, 2.4746e7) 1752 def __init__(self, mass, radius): 1753 self.mass = mass # in kilograms 1754 self.radius = radius # in meters 1755 @property 1756 def surface_gravity(self): 1757 # universal gravitational constant (m3 kg-1 s-2) 1758 G = 6.67300E-11 1759 return G * self.mass / (self.radius * self.radius) 1760 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80) 1761 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6)) 1762 1763 def test_ignore(self): 1764 class Period(timedelta, Enum): 1765 ''' 1766 different lengths of time 1767 ''' 1768 def __new__(cls, value, period): 1769 obj = timedelta.__new__(cls, value) 1770 obj._value_ = value 1771 obj.period = period 1772 return obj 1773 _ignore_ = 'Period i' 1774 Period = vars() 1775 for i in range(13): 1776 Period['month_%d' % i] = i*30, 'month' 1777 for i in range(53): 1778 Period['week_%d' % i] = i*7, 'week' 1779 for i in range(32): 1780 Period['day_%d' % i] = i, 'day' 1781 OneDay = day_1 1782 OneWeek = week_1 1783 OneMonth = month_1 1784 self.assertFalse(hasattr(Period, '_ignore_')) 1785 self.assertFalse(hasattr(Period, 'Period')) 1786 self.assertFalse(hasattr(Period, 'i')) 1787 self.assertTrue(isinstance(Period.day_1, timedelta)) 1788 self.assertTrue(Period.month_1 is Period.day_30) 1789 self.assertTrue(Period.week_4 is Period.day_28) 1790 1791 def test_nonhash_value(self): 1792 class AutoNumberInAList(Enum): 1793 def __new__(cls): 1794 value = [len(cls.__members__) + 1] 1795 obj = object.__new__(cls) 1796 obj._value_ = value 1797 return obj 1798 class ColorInAList(AutoNumberInAList): 1799 red = () 1800 green = () 1801 blue = () 1802 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue]) 1803 for enum, value in zip(ColorInAList, range(3)): 1804 value += 1 1805 self.assertEqual(enum.value, [value]) 1806 self.assertIs(ColorInAList([value]), enum) 1807 1808 def test_conflicting_types_resolved_in_new(self): 1809 class LabelledIntEnum(int, Enum): 1810 def __new__(cls, *args): 1811 value, label = args 1812 obj = int.__new__(cls, value) 1813 obj.label = label 1814 obj._value_ = value 1815 return obj 1816 1817 class LabelledList(LabelledIntEnum): 1818 unprocessed = (1, "Unprocessed") 1819 payment_complete = (2, "Payment Complete") 1820 1821 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete]) 1822 self.assertEqual(LabelledList.unprocessed, 1) 1823 self.assertEqual(LabelledList(1), LabelledList.unprocessed) 1824 1825 def test_auto_number(self): 1826 class Color(Enum): 1827 red = auto() 1828 blue = auto() 1829 green = auto() 1830 1831 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 1832 self.assertEqual(Color.red.value, 1) 1833 self.assertEqual(Color.blue.value, 2) 1834 self.assertEqual(Color.green.value, 3) 1835 1836 def test_auto_name(self): 1837 class Color(Enum): 1838 def _generate_next_value_(name, start, count, last): 1839 return name 1840 red = auto() 1841 blue = auto() 1842 green = auto() 1843 1844 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 1845 self.assertEqual(Color.red.value, 'red') 1846 self.assertEqual(Color.blue.value, 'blue') 1847 self.assertEqual(Color.green.value, 'green') 1848 1849 def test_auto_name_inherit(self): 1850 class AutoNameEnum(Enum): 1851 def _generate_next_value_(name, start, count, last): 1852 return name 1853 class Color(AutoNameEnum): 1854 red = auto() 1855 blue = auto() 1856 green = auto() 1857 1858 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 1859 self.assertEqual(Color.red.value, 'red') 1860 self.assertEqual(Color.blue.value, 'blue') 1861 self.assertEqual(Color.green.value, 'green') 1862 1863 def test_auto_garbage(self): 1864 class Color(Enum): 1865 red = 'red' 1866 blue = auto() 1867 self.assertEqual(Color.blue.value, 1) 1868 1869 def test_auto_garbage_corrected(self): 1870 class Color(Enum): 1871 red = 'red' 1872 blue = 2 1873 green = auto() 1874 1875 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 1876 self.assertEqual(Color.red.value, 'red') 1877 self.assertEqual(Color.blue.value, 2) 1878 self.assertEqual(Color.green.value, 3) 1879 1880 def test_auto_order(self): 1881 with self.assertRaises(TypeError): 1882 class Color(Enum): 1883 red = auto() 1884 green = auto() 1885 blue = auto() 1886 def _generate_next_value_(name, start, count, last): 1887 return name 1888 1889 def test_auto_order_wierd(self): 1890 weird_auto = auto() 1891 weird_auto.value = 'pathological case' 1892 class Color(Enum): 1893 red = weird_auto 1894 def _generate_next_value_(name, start, count, last): 1895 return name 1896 blue = auto() 1897 self.assertEqual(list(Color), [Color.red, Color.blue]) 1898 self.assertEqual(Color.red.value, 'pathological case') 1899 self.assertEqual(Color.blue.value, 'blue') 1900 1901 def test_duplicate_auto(self): 1902 class Dupes(Enum): 1903 first = primero = auto() 1904 second = auto() 1905 third = auto() 1906 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) 1907 1908 def test_default_missing(self): 1909 class Color(Enum): 1910 RED = 1 1911 GREEN = 2 1912 BLUE = 3 1913 try: 1914 Color(7) 1915 except ValueError as exc: 1916 self.assertTrue(exc.__context__ is None) 1917 else: 1918 raise Exception('Exception not raised.') 1919 1920 def test_missing(self): 1921 class Color(Enum): 1922 red = 1 1923 green = 2 1924 blue = 3 1925 @classmethod 1926 def _missing_(cls, item): 1927 if item == 'three': 1928 return cls.blue 1929 elif item == 'bad return': 1930 # trigger internal error 1931 return 5 1932 elif item == 'error out': 1933 raise ZeroDivisionError 1934 else: 1935 # trigger not found 1936 return None 1937 self.assertIs(Color('three'), Color.blue) 1938 try: 1939 Color(7) 1940 except ValueError as exc: 1941 self.assertTrue(exc.__context__ is None) 1942 else: 1943 raise Exception('Exception not raised.') 1944 try: 1945 Color('bad return') 1946 except TypeError as exc: 1947 self.assertTrue(isinstance(exc.__context__, ValueError)) 1948 else: 1949 raise Exception('Exception not raised.') 1950 try: 1951 Color('error out') 1952 except ZeroDivisionError as exc: 1953 self.assertTrue(isinstance(exc.__context__, ValueError)) 1954 else: 1955 raise Exception('Exception not raised.') 1956 1957 def test_missing_exceptions_reset(self): 1958 import weakref 1959 # 1960 class TestEnum(enum.Enum): 1961 VAL1 = 'val1' 1962 VAL2 = 'val2' 1963 # 1964 class Class1: 1965 def __init__(self): 1966 # Gracefully handle an exception of our own making 1967 try: 1968 raise ValueError() 1969 except ValueError: 1970 pass 1971 # 1972 class Class2: 1973 def __init__(self): 1974 # Gracefully handle an exception of Enum's making 1975 try: 1976 TestEnum('invalid_value') 1977 except ValueError: 1978 pass 1979 # No strong refs here so these are free to die. 1980 class_1_ref = weakref.ref(Class1()) 1981 class_2_ref = weakref.ref(Class2()) 1982 # 1983 # The exception raised by Enum creates a reference loop and thus 1984 # Class2 instances will stick around until the next gargage collection 1985 # cycle, unlike Class1. 1986 self.assertIs(class_1_ref(), None) 1987 self.assertIs(class_2_ref(), None) 1988 1989 def test_multiple_mixin(self): 1990 class MaxMixin: 1991 @classproperty 1992 def MAX(cls): 1993 max = len(cls) 1994 cls.MAX = max 1995 return max 1996 class StrMixin: 1997 def __str__(self): 1998 return self._name_.lower() 1999 class SomeEnum(Enum): 2000 def behavior(self): 2001 return 'booyah' 2002 class AnotherEnum(Enum): 2003 def behavior(self): 2004 return 'nuhuh!' 2005 def social(self): 2006 return "what's up?" 2007 class Color(MaxMixin, Enum): 2008 RED = auto() 2009 GREEN = auto() 2010 BLUE = auto() 2011 self.assertEqual(Color.RED.value, 1) 2012 self.assertEqual(Color.GREEN.value, 2) 2013 self.assertEqual(Color.BLUE.value, 3) 2014 self.assertEqual(Color.MAX, 3) 2015 self.assertEqual(str(Color.BLUE), 'Color.BLUE') 2016 class Color(MaxMixin, StrMixin, Enum): 2017 RED = auto() 2018 GREEN = auto() 2019 BLUE = auto() 2020 self.assertEqual(Color.RED.value, 1) 2021 self.assertEqual(Color.GREEN.value, 2) 2022 self.assertEqual(Color.BLUE.value, 3) 2023 self.assertEqual(Color.MAX, 3) 2024 self.assertEqual(str(Color.BLUE), 'blue') 2025 class Color(StrMixin, MaxMixin, Enum): 2026 RED = auto() 2027 GREEN = auto() 2028 BLUE = auto() 2029 self.assertEqual(Color.RED.value, 1) 2030 self.assertEqual(Color.GREEN.value, 2) 2031 self.assertEqual(Color.BLUE.value, 3) 2032 self.assertEqual(Color.MAX, 3) 2033 self.assertEqual(str(Color.BLUE), 'blue') 2034 class CoolColor(StrMixin, SomeEnum, Enum): 2035 RED = auto() 2036 GREEN = auto() 2037 BLUE = auto() 2038 self.assertEqual(CoolColor.RED.value, 1) 2039 self.assertEqual(CoolColor.GREEN.value, 2) 2040 self.assertEqual(CoolColor.BLUE.value, 3) 2041 self.assertEqual(str(CoolColor.BLUE), 'blue') 2042 self.assertEqual(CoolColor.RED.behavior(), 'booyah') 2043 class CoolerColor(StrMixin, AnotherEnum, Enum): 2044 RED = auto() 2045 GREEN = auto() 2046 BLUE = auto() 2047 self.assertEqual(CoolerColor.RED.value, 1) 2048 self.assertEqual(CoolerColor.GREEN.value, 2) 2049 self.assertEqual(CoolerColor.BLUE.value, 3) 2050 self.assertEqual(str(CoolerColor.BLUE), 'blue') 2051 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!') 2052 self.assertEqual(CoolerColor.RED.social(), "what's up?") 2053 class CoolestColor(StrMixin, SomeEnum, AnotherEnum): 2054 RED = auto() 2055 GREEN = auto() 2056 BLUE = auto() 2057 self.assertEqual(CoolestColor.RED.value, 1) 2058 self.assertEqual(CoolestColor.GREEN.value, 2) 2059 self.assertEqual(CoolestColor.BLUE.value, 3) 2060 self.assertEqual(str(CoolestColor.BLUE), 'blue') 2061 self.assertEqual(CoolestColor.RED.behavior(), 'booyah') 2062 self.assertEqual(CoolestColor.RED.social(), "what's up?") 2063 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum): 2064 RED = auto() 2065 GREEN = auto() 2066 BLUE = auto() 2067 self.assertEqual(ConfusedColor.RED.value, 1) 2068 self.assertEqual(ConfusedColor.GREEN.value, 2) 2069 self.assertEqual(ConfusedColor.BLUE.value, 3) 2070 self.assertEqual(str(ConfusedColor.BLUE), 'blue') 2071 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!') 2072 self.assertEqual(ConfusedColor.RED.social(), "what's up?") 2073 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum): 2074 RED = auto() 2075 GREEN = auto() 2076 BLUE = auto() 2077 self.assertEqual(ReformedColor.RED.value, 1) 2078 self.assertEqual(ReformedColor.GREEN.value, 2) 2079 self.assertEqual(ReformedColor.BLUE.value, 3) 2080 self.assertEqual(str(ReformedColor.BLUE), 'blue') 2081 self.assertEqual(ReformedColor.RED.behavior(), 'booyah') 2082 self.assertEqual(ConfusedColor.RED.social(), "what's up?") 2083 self.assertTrue(issubclass(ReformedColor, int)) 2084 2085 def test_multiple_inherited_mixin(self): 2086 class StrEnum(str, Enum): 2087 def __new__(cls, *args, **kwargs): 2088 for a in args: 2089 if not isinstance(a, str): 2090 raise TypeError("Enumeration '%s' (%s) is not" 2091 " a string" % (a, type(a).__name__)) 2092 return str.__new__(cls, *args, **kwargs) 2093 @unique 2094 class Decision1(StrEnum): 2095 REVERT = "REVERT" 2096 REVERT_ALL = "REVERT_ALL" 2097 RETRY = "RETRY" 2098 class MyEnum(StrEnum): 2099 pass 2100 @unique 2101 class Decision2(MyEnum): 2102 REVERT = "REVERT" 2103 REVERT_ALL = "REVERT_ALL" 2104 RETRY = "RETRY" 2105 2106 def test_multiple_mixin_inherited(self): 2107 class MyInt(int): 2108 def __new__(cls, value): 2109 return super().__new__(cls, value) 2110 2111 class HexMixin: 2112 def __repr__(self): 2113 return hex(self) 2114 2115 class MyIntEnum(HexMixin, MyInt, enum.Enum): 2116 pass 2117 2118 class Foo(MyIntEnum): 2119 TEST = 1 2120 self.assertTrue(isinstance(Foo.TEST, MyInt)) 2121 self.assertEqual(repr(Foo.TEST), "0x1") 2122 2123 class Fee(MyIntEnum): 2124 TEST = 1 2125 def __new__(cls, value): 2126 value += 1 2127 member = int.__new__(cls, value) 2128 member._value_ = value 2129 return member 2130 self.assertEqual(Fee.TEST, 2) 2131 2132 def test_empty_globals(self): 2133 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError 2134 # when using compile and exec because f_globals is empty 2135 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')" 2136 code = compile(code, "<string>", "exec") 2137 global_ns = {} 2138 local_ls = {} 2139 exec(code, global_ns, local_ls) 2140 2141 @unittest.skipUnless( 2142 python_version == (3, 9), 2143 'private variables are now normal attributes', 2144 ) 2145 def test_warning_for_private_variables(self): 2146 with self.assertWarns(DeprecationWarning): 2147 class Private(Enum): 2148 __corporal = 'Radar' 2149 self.assertEqual(Private._Private__corporal.value, 'Radar') 2150 try: 2151 with self.assertWarns(DeprecationWarning): 2152 class Private(Enum): 2153 __major_ = 'Hoolihan' 2154 except ValueError: 2155 pass 2156 2157 2158class TestOrder(unittest.TestCase): 2159 2160 def test_same_members(self): 2161 class Color(Enum): 2162 _order_ = 'red green blue' 2163 red = 1 2164 green = 2 2165 blue = 3 2166 2167 def test_same_members_with_aliases(self): 2168 class Color(Enum): 2169 _order_ = 'red green blue' 2170 red = 1 2171 green = 2 2172 blue = 3 2173 verde = green 2174 2175 def test_same_members_wrong_order(self): 2176 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2177 class Color(Enum): 2178 _order_ = 'red green blue' 2179 red = 1 2180 blue = 3 2181 green = 2 2182 2183 def test_order_has_extra_members(self): 2184 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2185 class Color(Enum): 2186 _order_ = 'red green blue purple' 2187 red = 1 2188 green = 2 2189 blue = 3 2190 2191 def test_order_has_extra_members_with_aliases(self): 2192 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2193 class Color(Enum): 2194 _order_ = 'red green blue purple' 2195 red = 1 2196 green = 2 2197 blue = 3 2198 verde = green 2199 2200 def test_enum_has_extra_members(self): 2201 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2202 class Color(Enum): 2203 _order_ = 'red green blue' 2204 red = 1 2205 green = 2 2206 blue = 3 2207 purple = 4 2208 2209 def test_enum_has_extra_members_with_aliases(self): 2210 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): 2211 class Color(Enum): 2212 _order_ = 'red green blue' 2213 red = 1 2214 green = 2 2215 blue = 3 2216 purple = 4 2217 verde = green 2218 2219 2220class TestFlag(unittest.TestCase): 2221 """Tests of the Flags.""" 2222 2223 class Perm(Flag): 2224 R, W, X = 4, 2, 1 2225 2226 class Open(Flag): 2227 RO = 0 2228 WO = 1 2229 RW = 2 2230 AC = 3 2231 CE = 1<<19 2232 2233 class Color(Flag): 2234 BLACK = 0 2235 RED = 1 2236 GREEN = 2 2237 BLUE = 4 2238 PURPLE = RED|BLUE 2239 2240 def test_str(self): 2241 Perm = self.Perm 2242 self.assertEqual(str(Perm.R), 'Perm.R') 2243 self.assertEqual(str(Perm.W), 'Perm.W') 2244 self.assertEqual(str(Perm.X), 'Perm.X') 2245 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W') 2246 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X') 2247 self.assertEqual(str(Perm(0)), 'Perm.0') 2248 self.assertEqual(str(~Perm.R), 'Perm.W|X') 2249 self.assertEqual(str(~Perm.W), 'Perm.R|X') 2250 self.assertEqual(str(~Perm.X), 'Perm.R|W') 2251 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X') 2252 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0') 2253 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X') 2254 2255 Open = self.Open 2256 self.assertEqual(str(Open.RO), 'Open.RO') 2257 self.assertEqual(str(Open.WO), 'Open.WO') 2258 self.assertEqual(str(Open.AC), 'Open.AC') 2259 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE') 2260 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO') 2261 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO') 2262 self.assertEqual(str(~Open.WO), 'Open.CE|RW') 2263 self.assertEqual(str(~Open.AC), 'Open.CE') 2264 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC') 2265 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW') 2266 2267 def test_repr(self): 2268 Perm = self.Perm 2269 self.assertEqual(repr(Perm.R), '<Perm.R: 4>') 2270 self.assertEqual(repr(Perm.W), '<Perm.W: 2>') 2271 self.assertEqual(repr(Perm.X), '<Perm.X: 1>') 2272 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>') 2273 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>') 2274 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>') 2275 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>') 2276 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>') 2277 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>') 2278 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>') 2279 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>') 2280 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>') 2281 2282 Open = self.Open 2283 self.assertEqual(repr(Open.RO), '<Open.RO: 0>') 2284 self.assertEqual(repr(Open.WO), '<Open.WO: 1>') 2285 self.assertEqual(repr(Open.AC), '<Open.AC: 3>') 2286 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>') 2287 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>') 2288 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>') 2289 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>') 2290 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>') 2291 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>') 2292 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>') 2293 2294 def test_format(self): 2295 Perm = self.Perm 2296 self.assertEqual(format(Perm.R, ''), 'Perm.R') 2297 self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X') 2298 2299 def test_or(self): 2300 Perm = self.Perm 2301 for i in Perm: 2302 for j in Perm: 2303 self.assertEqual((i | j), Perm(i.value | j.value)) 2304 self.assertEqual((i | j).value, i.value | j.value) 2305 self.assertIs(type(i | j), Perm) 2306 for i in Perm: 2307 self.assertIs(i | i, i) 2308 Open = self.Open 2309 self.assertIs(Open.RO | Open.CE, Open.CE) 2310 2311 def test_and(self): 2312 Perm = self.Perm 2313 RW = Perm.R | Perm.W 2314 RX = Perm.R | Perm.X 2315 WX = Perm.W | Perm.X 2316 RWX = Perm.R | Perm.W | Perm.X 2317 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 2318 for i in values: 2319 for j in values: 2320 self.assertEqual((i & j).value, i.value & j.value) 2321 self.assertIs(type(i & j), Perm) 2322 for i in Perm: 2323 self.assertIs(i & i, i) 2324 self.assertIs(i & RWX, i) 2325 self.assertIs(RWX & i, i) 2326 Open = self.Open 2327 self.assertIs(Open.RO & Open.CE, Open.RO) 2328 2329 def test_xor(self): 2330 Perm = self.Perm 2331 for i in Perm: 2332 for j in Perm: 2333 self.assertEqual((i ^ j).value, i.value ^ j.value) 2334 self.assertIs(type(i ^ j), Perm) 2335 for i in Perm: 2336 self.assertIs(i ^ Perm(0), i) 2337 self.assertIs(Perm(0) ^ i, i) 2338 Open = self.Open 2339 self.assertIs(Open.RO ^ Open.CE, Open.CE) 2340 self.assertIs(Open.CE ^ Open.CE, Open.RO) 2341 2342 def test_invert(self): 2343 Perm = self.Perm 2344 RW = Perm.R | Perm.W 2345 RX = Perm.R | Perm.X 2346 WX = Perm.W | Perm.X 2347 RWX = Perm.R | Perm.W | Perm.X 2348 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 2349 for i in values: 2350 self.assertIs(type(~i), Perm) 2351 self.assertEqual(~~i, i) 2352 for i in Perm: 2353 self.assertIs(~~i, i) 2354 Open = self.Open 2355 self.assertIs(Open.WO & ~Open.WO, Open.RO) 2356 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE) 2357 2358 def test_bool(self): 2359 Perm = self.Perm 2360 for f in Perm: 2361 self.assertTrue(f) 2362 Open = self.Open 2363 for f in Open: 2364 self.assertEqual(bool(f.value), bool(f)) 2365 2366 def test_programatic_function_string(self): 2367 Perm = Flag('Perm', 'R W X') 2368 lst = list(Perm) 2369 self.assertEqual(len(lst), len(Perm)) 2370 self.assertEqual(len(Perm), 3, Perm) 2371 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2372 for i, n in enumerate('R W X'.split()): 2373 v = 1<<i 2374 e = Perm(v) 2375 self.assertEqual(e.value, v) 2376 self.assertEqual(type(e.value), int) 2377 self.assertEqual(e.name, n) 2378 self.assertIn(e, Perm) 2379 self.assertIs(type(e), Perm) 2380 2381 def test_programatic_function_string_with_start(self): 2382 Perm = Flag('Perm', 'R W X', start=8) 2383 lst = list(Perm) 2384 self.assertEqual(len(lst), len(Perm)) 2385 self.assertEqual(len(Perm), 3, Perm) 2386 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2387 for i, n in enumerate('R W X'.split()): 2388 v = 8<<i 2389 e = Perm(v) 2390 self.assertEqual(e.value, v) 2391 self.assertEqual(type(e.value), int) 2392 self.assertEqual(e.name, n) 2393 self.assertIn(e, Perm) 2394 self.assertIs(type(e), Perm) 2395 2396 def test_programatic_function_string_list(self): 2397 Perm = Flag('Perm', ['R', 'W', 'X']) 2398 lst = list(Perm) 2399 self.assertEqual(len(lst), len(Perm)) 2400 self.assertEqual(len(Perm), 3, Perm) 2401 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2402 for i, n in enumerate('R W X'.split()): 2403 v = 1<<i 2404 e = Perm(v) 2405 self.assertEqual(e.value, v) 2406 self.assertEqual(type(e.value), int) 2407 self.assertEqual(e.name, n) 2408 self.assertIn(e, Perm) 2409 self.assertIs(type(e), Perm) 2410 2411 def test_programatic_function_iterable(self): 2412 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32))) 2413 lst = list(Perm) 2414 self.assertEqual(len(lst), len(Perm)) 2415 self.assertEqual(len(Perm), 3, Perm) 2416 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2417 for i, n in enumerate('R W X'.split()): 2418 v = 1<<(2*i+1) 2419 e = Perm(v) 2420 self.assertEqual(e.value, v) 2421 self.assertEqual(type(e.value), int) 2422 self.assertEqual(e.name, n) 2423 self.assertIn(e, Perm) 2424 self.assertIs(type(e), Perm) 2425 2426 def test_programatic_function_from_dict(self): 2427 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32)))) 2428 lst = list(Perm) 2429 self.assertEqual(len(lst), len(Perm)) 2430 self.assertEqual(len(Perm), 3, Perm) 2431 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2432 for i, n in enumerate('R W X'.split()): 2433 v = 1<<(2*i+1) 2434 e = Perm(v) 2435 self.assertEqual(e.value, v) 2436 self.assertEqual(type(e.value), int) 2437 self.assertEqual(e.name, n) 2438 self.assertIn(e, Perm) 2439 self.assertIs(type(e), Perm) 2440 2441 def test_pickle(self): 2442 if isinstance(FlagStooges, Exception): 2443 raise FlagStooges 2444 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE) 2445 test_pickle_dump_load(self.assertIs, FlagStooges) 2446 2447 @unittest.skipIf( 2448 python_version >= (3, 12), 2449 '__contains__ now returns True/False for all inputs', 2450 ) 2451 def test_contains_er(self): 2452 Open = self.Open 2453 Color = self.Color 2454 self.assertFalse(Color.BLACK in Open) 2455 self.assertFalse(Open.RO in Color) 2456 with self.assertRaises(TypeError): 2457 with self.assertWarns(DeprecationWarning): 2458 'BLACK' in Color 2459 with self.assertRaises(TypeError): 2460 with self.assertWarns(DeprecationWarning): 2461 'RO' in Open 2462 with self.assertRaises(TypeError): 2463 with self.assertWarns(DeprecationWarning): 2464 1 in Color 2465 with self.assertRaises(TypeError): 2466 with self.assertWarns(DeprecationWarning): 2467 1 in Open 2468 2469 @unittest.skipIf( 2470 python_version < (3, 12), 2471 '__contains__ only works with enum memmbers before 3.12', 2472 ) 2473 def test_contains_tf(self): 2474 Open = self.Open 2475 Color = self.Color 2476 self.assertFalse(Color.BLACK in Open) 2477 self.assertFalse(Open.RO in Color) 2478 self.assertFalse('BLACK' in Color) 2479 self.assertFalse('RO' in Open) 2480 self.assertTrue(1 in Color) 2481 self.assertTrue(1 in Open) 2482 2483 2484 def test_member_contains(self): 2485 Perm = self.Perm 2486 R, W, X = Perm 2487 RW = R | W 2488 RX = R | X 2489 WX = W | X 2490 RWX = R | W | X 2491 self.assertTrue(R in RW) 2492 self.assertTrue(R in RX) 2493 self.assertTrue(R in RWX) 2494 self.assertTrue(W in RW) 2495 self.assertTrue(W in WX) 2496 self.assertTrue(W in RWX) 2497 self.assertTrue(X in RX) 2498 self.assertTrue(X in WX) 2499 self.assertTrue(X in RWX) 2500 self.assertFalse(R in WX) 2501 self.assertFalse(W in RX) 2502 self.assertFalse(X in RW) 2503 2504 def test_auto_number(self): 2505 class Color(Flag): 2506 red = auto() 2507 blue = auto() 2508 green = auto() 2509 2510 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) 2511 self.assertEqual(Color.red.value, 1) 2512 self.assertEqual(Color.blue.value, 2) 2513 self.assertEqual(Color.green.value, 4) 2514 2515 def test_auto_number_garbage(self): 2516 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'): 2517 class Color(Flag): 2518 red = 'not an int' 2519 blue = auto() 2520 2521 def test_cascading_failure(self): 2522 class Bizarre(Flag): 2523 c = 3 2524 d = 4 2525 f = 6 2526 # Bizarre.c | Bizarre.d 2527 name = "TestFlag.test_cascading_failure.<locals>.Bizarre" 2528 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5) 2529 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5) 2530 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2) 2531 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2) 2532 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1) 2533 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1) 2534 2535 def test_duplicate_auto(self): 2536 class Dupes(Enum): 2537 first = primero = auto() 2538 second = auto() 2539 third = auto() 2540 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) 2541 2542 def test_bizarre(self): 2543 class Bizarre(Flag): 2544 b = 3 2545 c = 4 2546 d = 6 2547 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>') 2548 2549 def test_multiple_mixin(self): 2550 class AllMixin: 2551 @classproperty 2552 def ALL(cls): 2553 members = list(cls) 2554 all_value = None 2555 if members: 2556 all_value = members[0] 2557 for member in members[1:]: 2558 all_value |= member 2559 cls.ALL = all_value 2560 return all_value 2561 class StrMixin: 2562 def __str__(self): 2563 return self._name_.lower() 2564 class Color(AllMixin, Flag): 2565 RED = auto() 2566 GREEN = auto() 2567 BLUE = auto() 2568 self.assertEqual(Color.RED.value, 1) 2569 self.assertEqual(Color.GREEN.value, 2) 2570 self.assertEqual(Color.BLUE.value, 4) 2571 self.assertEqual(Color.ALL.value, 7) 2572 self.assertEqual(str(Color.BLUE), 'Color.BLUE') 2573 class Color(AllMixin, StrMixin, Flag): 2574 RED = auto() 2575 GREEN = auto() 2576 BLUE = auto() 2577 self.assertEqual(Color.RED.value, 1) 2578 self.assertEqual(Color.GREEN.value, 2) 2579 self.assertEqual(Color.BLUE.value, 4) 2580 self.assertEqual(Color.ALL.value, 7) 2581 self.assertEqual(str(Color.BLUE), 'blue') 2582 class Color(StrMixin, AllMixin, Flag): 2583 RED = auto() 2584 GREEN = auto() 2585 BLUE = auto() 2586 self.assertEqual(Color.RED.value, 1) 2587 self.assertEqual(Color.GREEN.value, 2) 2588 self.assertEqual(Color.BLUE.value, 4) 2589 self.assertEqual(Color.ALL.value, 7) 2590 self.assertEqual(str(Color.BLUE), 'blue') 2591 2592 @threading_helper.reap_threads 2593 def test_unique_composite(self): 2594 # override __eq__ to be identity only 2595 class TestFlag(Flag): 2596 one = auto() 2597 two = auto() 2598 three = auto() 2599 four = auto() 2600 five = auto() 2601 six = auto() 2602 seven = auto() 2603 eight = auto() 2604 def __eq__(self, other): 2605 return self is other 2606 def __hash__(self): 2607 return hash(self._value_) 2608 # have multiple threads competing to complete the composite members 2609 seen = set() 2610 failed = False 2611 def cycle_enum(): 2612 nonlocal failed 2613 try: 2614 for i in range(256): 2615 seen.add(TestFlag(i)) 2616 except Exception: 2617 failed = True 2618 threads = [ 2619 threading.Thread(target=cycle_enum) 2620 for _ in range(8) 2621 ] 2622 with threading_helper.start_threads(threads): 2623 pass 2624 # check that only 248 members were created 2625 self.assertFalse( 2626 failed, 2627 'at least one thread failed while creating composite members') 2628 self.assertEqual(256, len(seen), 'too many composite members created') 2629 2630 def test_init_subclass(self): 2631 class MyEnum(Flag): 2632 def __init_subclass__(cls, **kwds): 2633 super().__init_subclass__(**kwds) 2634 self.assertFalse(cls.__dict__.get('_test', False)) 2635 cls._test1 = 'MyEnum' 2636 # 2637 class TheirEnum(MyEnum): 2638 def __init_subclass__(cls, **kwds): 2639 super(TheirEnum, cls).__init_subclass__(**kwds) 2640 cls._test2 = 'TheirEnum' 2641 class WhoseEnum(TheirEnum): 2642 def __init_subclass__(cls, **kwds): 2643 pass 2644 class NoEnum(WhoseEnum): 2645 ONE = 1 2646 self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') 2647 self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') 2648 self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') 2649 self.assertFalse(NoEnum.__dict__.get('_test1', False)) 2650 self.assertFalse(NoEnum.__dict__.get('_test2', False)) 2651 # 2652 class OurEnum(MyEnum): 2653 def __init_subclass__(cls, **kwds): 2654 cls._test2 = 'OurEnum' 2655 class WhereEnum(OurEnum): 2656 def __init_subclass__(cls, **kwds): 2657 pass 2658 class NeverEnum(WhereEnum): 2659 ONE = 1 2660 self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') 2661 self.assertFalse(WhereEnum.__dict__.get('_test1', False)) 2662 self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') 2663 self.assertFalse(NeverEnum.__dict__.get('_test1', False)) 2664 self.assertFalse(NeverEnum.__dict__.get('_test2', False)) 2665 2666 2667class TestIntFlag(unittest.TestCase): 2668 """Tests of the IntFlags.""" 2669 2670 class Perm(IntFlag): 2671 X = 1 << 0 2672 W = 1 << 1 2673 R = 1 << 2 2674 2675 class Open(IntFlag): 2676 RO = 0 2677 WO = 1 2678 RW = 2 2679 AC = 3 2680 CE = 1<<19 2681 2682 class Color(IntFlag): 2683 BLACK = 0 2684 RED = 1 2685 GREEN = 2 2686 BLUE = 4 2687 PURPLE = RED|BLUE 2688 2689 def test_type(self): 2690 Perm = self.Perm 2691 self.assertTrue(Perm._member_type_ is int) 2692 Open = self.Open 2693 for f in Perm: 2694 self.assertTrue(isinstance(f, Perm)) 2695 self.assertEqual(f, f.value) 2696 self.assertTrue(isinstance(Perm.W | Perm.X, Perm)) 2697 self.assertEqual(Perm.W | Perm.X, 3) 2698 for f in Open: 2699 self.assertTrue(isinstance(f, Open)) 2700 self.assertEqual(f, f.value) 2701 self.assertTrue(isinstance(Open.WO | Open.RW, Open)) 2702 self.assertEqual(Open.WO | Open.RW, 3) 2703 2704 2705 def test_str(self): 2706 Perm = self.Perm 2707 self.assertEqual(str(Perm.R), 'Perm.R') 2708 self.assertEqual(str(Perm.W), 'Perm.W') 2709 self.assertEqual(str(Perm.X), 'Perm.X') 2710 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W') 2711 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X') 2712 self.assertEqual(str(Perm.R | 8), 'Perm.8|R') 2713 self.assertEqual(str(Perm(0)), 'Perm.0') 2714 self.assertEqual(str(Perm(8)), 'Perm.8') 2715 self.assertEqual(str(~Perm.R), 'Perm.W|X') 2716 self.assertEqual(str(~Perm.W), 'Perm.R|X') 2717 self.assertEqual(str(~Perm.X), 'Perm.R|W') 2718 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X') 2719 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8') 2720 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X') 2721 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X') 2722 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X') 2723 2724 Open = self.Open 2725 self.assertEqual(str(Open.RO), 'Open.RO') 2726 self.assertEqual(str(Open.WO), 'Open.WO') 2727 self.assertEqual(str(Open.AC), 'Open.AC') 2728 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE') 2729 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO') 2730 self.assertEqual(str(Open(4)), 'Open.4') 2731 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO') 2732 self.assertEqual(str(~Open.WO), 'Open.CE|RW') 2733 self.assertEqual(str(~Open.AC), 'Open.CE') 2734 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO') 2735 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW') 2736 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO') 2737 2738 def test_repr(self): 2739 Perm = self.Perm 2740 self.assertEqual(repr(Perm.R), '<Perm.R: 4>') 2741 self.assertEqual(repr(Perm.W), '<Perm.W: 2>') 2742 self.assertEqual(repr(Perm.X), '<Perm.X: 1>') 2743 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>') 2744 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>') 2745 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>') 2746 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>') 2747 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>') 2748 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>') 2749 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>') 2750 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>') 2751 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>') 2752 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>') 2753 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>') 2754 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>') 2755 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>') 2756 2757 Open = self.Open 2758 self.assertEqual(repr(Open.RO), '<Open.RO: 0>') 2759 self.assertEqual(repr(Open.WO), '<Open.WO: 1>') 2760 self.assertEqual(repr(Open.AC), '<Open.AC: 3>') 2761 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>') 2762 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>') 2763 self.assertEqual(repr(Open(4)), '<Open.4: 4>') 2764 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>') 2765 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>') 2766 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>') 2767 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>') 2768 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>') 2769 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>') 2770 2771 def test_format(self): 2772 Perm = self.Perm 2773 self.assertEqual(format(Perm.R, ''), '4') 2774 self.assertEqual(format(Perm.R | Perm.X, ''), '5') 2775 2776 def test_or(self): 2777 Perm = self.Perm 2778 for i in Perm: 2779 for j in Perm: 2780 self.assertEqual(i | j, i.value | j.value) 2781 self.assertEqual((i | j).value, i.value | j.value) 2782 self.assertIs(type(i | j), Perm) 2783 for j in range(8): 2784 self.assertEqual(i | j, i.value | j) 2785 self.assertEqual((i | j).value, i.value | j) 2786 self.assertIs(type(i | j), Perm) 2787 self.assertEqual(j | i, j | i.value) 2788 self.assertEqual((j | i).value, j | i.value) 2789 self.assertIs(type(j | i), Perm) 2790 for i in Perm: 2791 self.assertIs(i | i, i) 2792 self.assertIs(i | 0, i) 2793 self.assertIs(0 | i, i) 2794 Open = self.Open 2795 self.assertIs(Open.RO | Open.CE, Open.CE) 2796 2797 def test_and(self): 2798 Perm = self.Perm 2799 RW = Perm.R | Perm.W 2800 RX = Perm.R | Perm.X 2801 WX = Perm.W | Perm.X 2802 RWX = Perm.R | Perm.W | Perm.X 2803 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 2804 for i in values: 2805 for j in values: 2806 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j)) 2807 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j)) 2808 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j)) 2809 for j in range(8): 2810 self.assertEqual(i & j, i.value & j) 2811 self.assertEqual((i & j).value, i.value & j) 2812 self.assertIs(type(i & j), Perm) 2813 self.assertEqual(j & i, j & i.value) 2814 self.assertEqual((j & i).value, j & i.value) 2815 self.assertIs(type(j & i), Perm) 2816 for i in Perm: 2817 self.assertIs(i & i, i) 2818 self.assertIs(i & 7, i) 2819 self.assertIs(7 & i, i) 2820 Open = self.Open 2821 self.assertIs(Open.RO & Open.CE, Open.RO) 2822 2823 def test_xor(self): 2824 Perm = self.Perm 2825 for i in Perm: 2826 for j in Perm: 2827 self.assertEqual(i ^ j, i.value ^ j.value) 2828 self.assertEqual((i ^ j).value, i.value ^ j.value) 2829 self.assertIs(type(i ^ j), Perm) 2830 for j in range(8): 2831 self.assertEqual(i ^ j, i.value ^ j) 2832 self.assertEqual((i ^ j).value, i.value ^ j) 2833 self.assertIs(type(i ^ j), Perm) 2834 self.assertEqual(j ^ i, j ^ i.value) 2835 self.assertEqual((j ^ i).value, j ^ i.value) 2836 self.assertIs(type(j ^ i), Perm) 2837 for i in Perm: 2838 self.assertIs(i ^ 0, i) 2839 self.assertIs(0 ^ i, i) 2840 Open = self.Open 2841 self.assertIs(Open.RO ^ Open.CE, Open.CE) 2842 self.assertIs(Open.CE ^ Open.CE, Open.RO) 2843 2844 def test_invert(self): 2845 Perm = self.Perm 2846 RW = Perm.R | Perm.W 2847 RX = Perm.R | Perm.X 2848 WX = Perm.W | Perm.X 2849 RWX = Perm.R | Perm.W | Perm.X 2850 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] 2851 for i in values: 2852 self.assertEqual(~i, ~i.value) 2853 self.assertEqual((~i).value, ~i.value) 2854 self.assertIs(type(~i), Perm) 2855 self.assertEqual(~~i, i) 2856 for i in Perm: 2857 self.assertIs(~~i, i) 2858 Open = self.Open 2859 self.assertIs(Open.WO & ~Open.WO, Open.RO) 2860 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE) 2861 2862 def test_programatic_function_string(self): 2863 Perm = IntFlag('Perm', 'R W X') 2864 lst = list(Perm) 2865 self.assertEqual(len(lst), len(Perm)) 2866 self.assertEqual(len(Perm), 3, Perm) 2867 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2868 for i, n in enumerate('R W X'.split()): 2869 v = 1<<i 2870 e = Perm(v) 2871 self.assertEqual(e.value, v) 2872 self.assertEqual(type(e.value), int) 2873 self.assertEqual(e, v) 2874 self.assertEqual(e.name, n) 2875 self.assertIn(e, Perm) 2876 self.assertIs(type(e), Perm) 2877 2878 def test_programatic_function_string_with_start(self): 2879 Perm = IntFlag('Perm', 'R W X', start=8) 2880 lst = list(Perm) 2881 self.assertEqual(len(lst), len(Perm)) 2882 self.assertEqual(len(Perm), 3, Perm) 2883 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2884 for i, n in enumerate('R W X'.split()): 2885 v = 8<<i 2886 e = Perm(v) 2887 self.assertEqual(e.value, v) 2888 self.assertEqual(type(e.value), int) 2889 self.assertEqual(e, v) 2890 self.assertEqual(e.name, n) 2891 self.assertIn(e, Perm) 2892 self.assertIs(type(e), Perm) 2893 2894 def test_programatic_function_string_list(self): 2895 Perm = IntFlag('Perm', ['R', 'W', 'X']) 2896 lst = list(Perm) 2897 self.assertEqual(len(lst), len(Perm)) 2898 self.assertEqual(len(Perm), 3, Perm) 2899 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2900 for i, n in enumerate('R W X'.split()): 2901 v = 1<<i 2902 e = Perm(v) 2903 self.assertEqual(e.value, v) 2904 self.assertEqual(type(e.value), int) 2905 self.assertEqual(e, v) 2906 self.assertEqual(e.name, n) 2907 self.assertIn(e, Perm) 2908 self.assertIs(type(e), Perm) 2909 2910 def test_programatic_function_iterable(self): 2911 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32))) 2912 lst = list(Perm) 2913 self.assertEqual(len(lst), len(Perm)) 2914 self.assertEqual(len(Perm), 3, Perm) 2915 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2916 for i, n in enumerate('R W X'.split()): 2917 v = 1<<(2*i+1) 2918 e = Perm(v) 2919 self.assertEqual(e.value, v) 2920 self.assertEqual(type(e.value), int) 2921 self.assertEqual(e, v) 2922 self.assertEqual(e.name, n) 2923 self.assertIn(e, Perm) 2924 self.assertIs(type(e), Perm) 2925 2926 def test_programatic_function_from_dict(self): 2927 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32)))) 2928 lst = list(Perm) 2929 self.assertEqual(len(lst), len(Perm)) 2930 self.assertEqual(len(Perm), 3, Perm) 2931 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X]) 2932 for i, n in enumerate('R W X'.split()): 2933 v = 1<<(2*i+1) 2934 e = Perm(v) 2935 self.assertEqual(e.value, v) 2936 self.assertEqual(type(e.value), int) 2937 self.assertEqual(e, v) 2938 self.assertEqual(e.name, n) 2939 self.assertIn(e, Perm) 2940 self.assertIs(type(e), Perm) 2941 2942 2943 def test_programatic_function_from_empty_list(self): 2944 Perm = enum.IntFlag('Perm', []) 2945 lst = list(Perm) 2946 self.assertEqual(len(lst), len(Perm)) 2947 self.assertEqual(len(Perm), 0, Perm) 2948 Thing = enum.Enum('Thing', []) 2949 lst = list(Thing) 2950 self.assertEqual(len(lst), len(Thing)) 2951 self.assertEqual(len(Thing), 0, Thing) 2952 2953 2954 def test_programatic_function_from_empty_tuple(self): 2955 Perm = enum.IntFlag('Perm', ()) 2956 lst = list(Perm) 2957 self.assertEqual(len(lst), len(Perm)) 2958 self.assertEqual(len(Perm), 0, Perm) 2959 Thing = enum.Enum('Thing', ()) 2960 self.assertEqual(len(lst), len(Thing)) 2961 self.assertEqual(len(Thing), 0, Thing) 2962 2963 @unittest.skipIf( 2964 python_version >= (3, 12), 2965 '__contains__ now returns True/False for all inputs', 2966 ) 2967 def test_contains_er(self): 2968 Open = self.Open 2969 Color = self.Color 2970 self.assertTrue(Color.GREEN in Color) 2971 self.assertTrue(Open.RW in Open) 2972 self.assertFalse(Color.GREEN in Open) 2973 self.assertFalse(Open.RW in Color) 2974 with self.assertRaises(TypeError): 2975 with self.assertWarns(DeprecationWarning): 2976 'GREEN' in Color 2977 with self.assertRaises(TypeError): 2978 with self.assertWarns(DeprecationWarning): 2979 'RW' in Open 2980 with self.assertRaises(TypeError): 2981 with self.assertWarns(DeprecationWarning): 2982 2 in Color 2983 with self.assertRaises(TypeError): 2984 with self.assertWarns(DeprecationWarning): 2985 2 in Open 2986 2987 @unittest.skipIf( 2988 python_version < (3, 12), 2989 '__contains__ only works with enum memmbers before 3.12', 2990 ) 2991 def test_contains_tf(self): 2992 Open = self.Open 2993 Color = self.Color 2994 self.assertTrue(Color.GREEN in Color) 2995 self.assertTrue(Open.RW in Open) 2996 self.assertTrue(Color.GREEN in Open) 2997 self.assertTrue(Open.RW in Color) 2998 self.assertFalse('GREEN' in Color) 2999 self.assertFalse('RW' in Open) 3000 self.assertTrue(2 in Color) 3001 self.assertTrue(2 in Open) 3002 3003 def test_member_contains(self): 3004 Perm = self.Perm 3005 R, W, X = Perm 3006 RW = R | W 3007 RX = R | X 3008 WX = W | X 3009 RWX = R | W | X 3010 self.assertTrue(R in RW) 3011 self.assertTrue(R in RX) 3012 self.assertTrue(R in RWX) 3013 self.assertTrue(W in RW) 3014 self.assertTrue(W in WX) 3015 self.assertTrue(W in RWX) 3016 self.assertTrue(X in RX) 3017 self.assertTrue(X in WX) 3018 self.assertTrue(X in RWX) 3019 self.assertFalse(R in WX) 3020 self.assertFalse(W in RX) 3021 self.assertFalse(X in RW) 3022 with self.assertRaises(TypeError): 3023 self.assertFalse('test' in RW) 3024 3025 def test_bool(self): 3026 Perm = self.Perm 3027 for f in Perm: 3028 self.assertTrue(f) 3029 Open = self.Open 3030 for f in Open: 3031 self.assertEqual(bool(f.value), bool(f)) 3032 3033 def test_multiple_mixin(self): 3034 class AllMixin: 3035 @classproperty 3036 def ALL(cls): 3037 members = list(cls) 3038 all_value = None 3039 if members: 3040 all_value = members[0] 3041 for member in members[1:]: 3042 all_value |= member 3043 cls.ALL = all_value 3044 return all_value 3045 class StrMixin: 3046 def __str__(self): 3047 return self._name_.lower() 3048 class Color(AllMixin, IntFlag): 3049 RED = auto() 3050 GREEN = auto() 3051 BLUE = auto() 3052 self.assertEqual(Color.RED.value, 1) 3053 self.assertEqual(Color.GREEN.value, 2) 3054 self.assertEqual(Color.BLUE.value, 4) 3055 self.assertEqual(Color.ALL.value, 7) 3056 self.assertEqual(str(Color.BLUE), 'Color.BLUE') 3057 class Color(AllMixin, StrMixin, IntFlag): 3058 RED = auto() 3059 GREEN = auto() 3060 BLUE = auto() 3061 self.assertEqual(Color.RED.value, 1) 3062 self.assertEqual(Color.GREEN.value, 2) 3063 self.assertEqual(Color.BLUE.value, 4) 3064 self.assertEqual(Color.ALL.value, 7) 3065 self.assertEqual(str(Color.BLUE), 'blue') 3066 class Color(StrMixin, AllMixin, IntFlag): 3067 RED = auto() 3068 GREEN = auto() 3069 BLUE = auto() 3070 self.assertEqual(Color.RED.value, 1) 3071 self.assertEqual(Color.GREEN.value, 2) 3072 self.assertEqual(Color.BLUE.value, 4) 3073 self.assertEqual(Color.ALL.value, 7) 3074 self.assertEqual(str(Color.BLUE), 'blue') 3075 3076 @threading_helper.reap_threads 3077 def test_unique_composite(self): 3078 # override __eq__ to be identity only 3079 class TestFlag(IntFlag): 3080 one = auto() 3081 two = auto() 3082 three = auto() 3083 four = auto() 3084 five = auto() 3085 six = auto() 3086 seven = auto() 3087 eight = auto() 3088 def __eq__(self, other): 3089 return self is other 3090 def __hash__(self): 3091 return hash(self._value_) 3092 # have multiple threads competing to complete the composite members 3093 seen = set() 3094 failed = False 3095 def cycle_enum(): 3096 nonlocal failed 3097 try: 3098 for i in range(256): 3099 seen.add(TestFlag(i)) 3100 except Exception: 3101 failed = True 3102 threads = [ 3103 threading.Thread(target=cycle_enum) 3104 for _ in range(8) 3105 ] 3106 with threading_helper.start_threads(threads): 3107 pass 3108 # check that only 248 members were created 3109 self.assertFalse( 3110 failed, 3111 'at least one thread failed while creating composite members') 3112 self.assertEqual(256, len(seen), 'too many composite members created') 3113 3114 3115class TestEmptyAndNonLatinStrings(unittest.TestCase): 3116 3117 def test_empty_string(self): 3118 with self.assertRaises(ValueError): 3119 empty_abc = Enum('empty_abc', ('', 'B', 'C')) 3120 3121 def test_non_latin_character_string(self): 3122 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C')) 3123 item = getattr(greek_abc, '\u03B1') 3124 self.assertEqual(item.value, 1) 3125 3126 def test_non_latin_number_string(self): 3127 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3')) 3128 item = getattr(hebrew_123, '\u05D0') 3129 self.assertEqual(item.value, 1) 3130 3131 3132class TestUnique(unittest.TestCase): 3133 3134 def test_unique_clean(self): 3135 @unique 3136 class Clean(Enum): 3137 one = 1 3138 two = 'dos' 3139 tres = 4.0 3140 @unique 3141 class Cleaner(IntEnum): 3142 single = 1 3143 double = 2 3144 triple = 3 3145 3146 def test_unique_dirty(self): 3147 with self.assertRaisesRegex(ValueError, 'tres.*one'): 3148 @unique 3149 class Dirty(Enum): 3150 one = 1 3151 two = 'dos' 3152 tres = 1 3153 with self.assertRaisesRegex( 3154 ValueError, 3155 'double.*single.*turkey.*triple', 3156 ): 3157 @unique 3158 class Dirtier(IntEnum): 3159 single = 1 3160 double = 1 3161 triple = 3 3162 turkey = 3 3163 3164 def test_unique_with_name(self): 3165 @unique 3166 class Silly(Enum): 3167 one = 1 3168 two = 'dos' 3169 name = 3 3170 @unique 3171 class Sillier(IntEnum): 3172 single = 1 3173 name = 2 3174 triple = 3 3175 value = 4 3176 3177 3178 3179expected_help_output_with_docs = """\ 3180Help on class Color in module %s: 3181 3182class Color(enum.Enum) 3183 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1) 3184 |\x20\x20 3185 | An enumeration. 3186 |\x20\x20 3187 | Method resolution order: 3188 | Color 3189 | enum.Enum 3190 | builtins.object 3191 |\x20\x20 3192 | Data and other attributes defined here: 3193 |\x20\x20 3194 | blue = <Color.blue: 3> 3195 |\x20\x20 3196 | green = <Color.green: 2> 3197 |\x20\x20 3198 | red = <Color.red: 1> 3199 |\x20\x20 3200 | ---------------------------------------------------------------------- 3201 | Data descriptors inherited from enum.Enum: 3202 |\x20\x20 3203 | name 3204 | The name of the Enum member. 3205 |\x20\x20 3206 | value 3207 | The value of the Enum member. 3208 |\x20\x20 3209 | ---------------------------------------------------------------------- 3210 | Readonly properties inherited from enum.EnumMeta: 3211 |\x20\x20 3212 | __members__ 3213 | Returns a mapping of member name->value. 3214 |\x20\x20\x20\x20\x20\x20 3215 | This mapping lists all enum members, including aliases. Note that this 3216 | is a read-only view of the internal mapping.""" 3217 3218expected_help_output_without_docs = """\ 3219Help on class Color in module %s: 3220 3221class Color(enum.Enum) 3222 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1) 3223 |\x20\x20 3224 | Method resolution order: 3225 | Color 3226 | enum.Enum 3227 | builtins.object 3228 |\x20\x20 3229 | Data and other attributes defined here: 3230 |\x20\x20 3231 | blue = <Color.blue: 3> 3232 |\x20\x20 3233 | green = <Color.green: 2> 3234 |\x20\x20 3235 | red = <Color.red: 1> 3236 |\x20\x20 3237 | ---------------------------------------------------------------------- 3238 | Data descriptors inherited from enum.Enum: 3239 |\x20\x20 3240 | name 3241 |\x20\x20 3242 | value 3243 |\x20\x20 3244 | ---------------------------------------------------------------------- 3245 | Data descriptors inherited from enum.EnumMeta: 3246 |\x20\x20 3247 | __members__""" 3248 3249class TestStdLib(unittest.TestCase): 3250 3251 maxDiff = None 3252 3253 class Color(Enum): 3254 red = 1 3255 green = 2 3256 blue = 3 3257 3258 def test_pydoc(self): 3259 # indirectly test __objclass__ 3260 if StrEnum.__doc__ is None: 3261 expected_text = expected_help_output_without_docs % __name__ 3262 else: 3263 expected_text = expected_help_output_with_docs % __name__ 3264 output = StringIO() 3265 helper = pydoc.Helper(output=output) 3266 helper(self.Color) 3267 result = output.getvalue().strip() 3268 self.assertEqual(result, expected_text) 3269 3270 def test_inspect_getmembers(self): 3271 values = dict(( 3272 ('__class__', EnumMeta), 3273 ('__doc__', 'An enumeration.'), 3274 ('__members__', self.Color.__members__), 3275 ('__module__', __name__), 3276 ('blue', self.Color.blue), 3277 ('green', self.Color.green), 3278 ('name', Enum.__dict__['name']), 3279 ('red', self.Color.red), 3280 ('value', Enum.__dict__['value']), 3281 )) 3282 result = dict(inspect.getmembers(self.Color)) 3283 self.assertEqual(values.keys(), result.keys()) 3284 failed = False 3285 for k in values.keys(): 3286 if result[k] != values[k]: 3287 print() 3288 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' % 3289 ('=' * 75, k, result[k], values[k], '=' * 75), sep='') 3290 failed = True 3291 if failed: 3292 self.fail("result does not equal expected, see print above") 3293 3294 def test_inspect_classify_class_attrs(self): 3295 # indirectly test __objclass__ 3296 from inspect import Attribute 3297 values = [ 3298 Attribute(name='__class__', kind='data', 3299 defining_class=object, object=EnumMeta), 3300 Attribute(name='__doc__', kind='data', 3301 defining_class=self.Color, object='An enumeration.'), 3302 Attribute(name='__members__', kind='property', 3303 defining_class=EnumMeta, object=EnumMeta.__members__), 3304 Attribute(name='__module__', kind='data', 3305 defining_class=self.Color, object=__name__), 3306 Attribute(name='blue', kind='data', 3307 defining_class=self.Color, object=self.Color.blue), 3308 Attribute(name='green', kind='data', 3309 defining_class=self.Color, object=self.Color.green), 3310 Attribute(name='red', kind='data', 3311 defining_class=self.Color, object=self.Color.red), 3312 Attribute(name='name', kind='data', 3313 defining_class=Enum, object=Enum.__dict__['name']), 3314 Attribute(name='value', kind='data', 3315 defining_class=Enum, object=Enum.__dict__['value']), 3316 ] 3317 values.sort(key=lambda item: item.name) 3318 result = list(inspect.classify_class_attrs(self.Color)) 3319 result.sort(key=lambda item: item.name) 3320 failed = False 3321 for v, r in zip(values, result): 3322 if r != v: 3323 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='') 3324 failed = True 3325 if failed: 3326 self.fail("result does not equal expected, see print above") 3327 3328 3329class MiscTestCase(unittest.TestCase): 3330 def test__all__(self): 3331 check__all__(self, enum) 3332 3333 3334# These are unordered here on purpose to ensure that declaration order 3335# makes no difference. 3336CONVERT_TEST_NAME_D = 5 3337CONVERT_TEST_NAME_C = 5 3338CONVERT_TEST_NAME_B = 5 3339CONVERT_TEST_NAME_A = 5 # This one should sort first. 3340CONVERT_TEST_NAME_E = 5 3341CONVERT_TEST_NAME_F = 5 3342 3343class TestIntEnumConvert(unittest.TestCase): 3344 def test_convert_value_lookup_priority(self): 3345 test_type = enum.IntEnum._convert_( 3346 'UnittestConvert', 3347 ('test.test_enum', '__main__')[__name__=='__main__'], 3348 filter=lambda x: x.startswith('CONVERT_TEST_')) 3349 # We don't want the reverse lookup value to vary when there are 3350 # multiple possible names for a given value. It should always 3351 # report the first lexigraphical name in that case. 3352 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A') 3353 3354 def test_convert(self): 3355 test_type = enum.IntEnum._convert_( 3356 'UnittestConvert', 3357 ('test.test_enum', '__main__')[__name__=='__main__'], 3358 filter=lambda x: x.startswith('CONVERT_TEST_')) 3359 # Ensure that test_type has all of the desired names and values. 3360 self.assertEqual(test_type.CONVERT_TEST_NAME_F, 3361 test_type.CONVERT_TEST_NAME_A) 3362 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5) 3363 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5) 3364 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5) 3365 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5) 3366 # Ensure that test_type only picked up names matching the filter. 3367 self.assertEqual([name for name in dir(test_type) 3368 if name[0:2] not in ('CO', '__')], 3369 [], msg='Names other than CONVERT_TEST_* found.') 3370 3371 @unittest.skipUnless(python_version == (3, 8), 3372 '_convert was deprecated in 3.8') 3373 def test_convert_warn(self): 3374 with self.assertWarns(DeprecationWarning): 3375 enum.IntEnum._convert( 3376 'UnittestConvert', 3377 ('test.test_enum', '__main__')[__name__=='__main__'], 3378 filter=lambda x: x.startswith('CONVERT_TEST_')) 3379 3380 @unittest.skipUnless(python_version >= (3, 9), 3381 '_convert was removed in 3.9') 3382 def test_convert_raise(self): 3383 with self.assertRaises(AttributeError): 3384 enum.IntEnum._convert( 3385 'UnittestConvert', 3386 ('test.test_enum', '__main__')[__name__=='__main__'], 3387 filter=lambda x: x.startswith('CONVERT_TEST_')) 3388 3389class TestHelpers(unittest.TestCase): 3390 3391 sunder_names = '_bad_', '_good_', '_what_ho_' 3392 dunder_names = '__mal__', '__bien__', '__que_que__' 3393 private_names = '_MyEnum__private', '_MyEnum__still_private' 3394 private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_' 3395 random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__' 3396 3397 def test_sunder(self): 3398 for name in self.sunder_names + self.private_and_sunder_names: 3399 self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name) 3400 for name in self.dunder_names + self.private_names + self.random_names: 3401 self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name) 3402 3403 def test_dunder(self): 3404 for name in self.dunder_names: 3405 self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name) 3406 for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names: 3407 self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name) 3408 3409 def test_is_private(self): 3410 for name in self.private_names + self.private_and_sunder_names: 3411 self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?') 3412 for name in self.sunder_names + self.dunder_names + self.random_names: 3413 self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?') 3414 3415 3416if __name__ == '__main__': 3417 unittest.main() 3418 3419