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