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