blob: d1dd2e78d455f0957226bc11a1980067aefecdae [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
orlnub1230fb9fad2018-09-12 20:28:53 +03004import sys
Ethan Furman6b3d64a2013-06-14 16:55:46 -07005import unittest
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02006import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07007from collections import OrderedDict
Ethan Furman0063ff42020-09-21 17:23:13 -07008from enum import Enum, IntEnum, StrEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07009from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -080010from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000011from test import support
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +030012from test.support import ALWAYS_EQ
Hai Shie80697d2020-05-28 06:10:27 +080013from test.support import threading_helper
Ethan Furmana4b1bb42018-01-22 07:56:37 -080014from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080015
Ethan Furman6b3d64a2013-06-14 16:55:46 -070016
17# for pickle tests
18try:
19 class Stooges(Enum):
20 LARRY = 1
21 CURLY = 2
22 MOE = 3
23except Exception as exc:
24 Stooges = exc
25
26try:
27 class IntStooges(int, Enum):
28 LARRY = 1
29 CURLY = 2
30 MOE = 3
31except Exception as exc:
32 IntStooges = exc
33
34try:
35 class FloatStooges(float, Enum):
36 LARRY = 1.39
37 CURLY = 2.72
38 MOE = 3.142596
39except Exception as exc:
40 FloatStooges = exc
41
Ethan Furman65a5a472016-09-01 23:55:19 -070042try:
43 class FlagStooges(Flag):
44 LARRY = 1
45 CURLY = 2
46 MOE = 3
47except Exception as exc:
48 FlagStooges = exc
49
Ethan Furman6b3d64a2013-06-14 16:55:46 -070050# for pickle test and subclass tests
Ethan Furman0063ff42020-09-21 17:23:13 -070051class Name(StrEnum):
52 BDFL = 'Guido van Rossum'
53 FLUFL = 'Barry Warsaw'
Ethan Furman6b3d64a2013-06-14 16:55:46 -070054
55try:
56 Question = Enum('Question', 'who what when where why', module=__name__)
57except Exception as exc:
58 Question = exc
59
60try:
61 Answer = Enum('Answer', 'him this then there because')
62except Exception as exc:
63 Answer = exc
64
Ethan Furmanca1b7942014-02-08 11:36:27 -080065try:
66 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
67except Exception as exc:
68 Theory = exc
69
Ethan Furman6b3d64a2013-06-14 16:55:46 -070070# for doctests
71try:
72 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080073 TOMATO = 1
74 BANANA = 2
75 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070076except Exception:
77 pass
78
Serhiy Storchakae50e7802015-03-31 16:56:49 +030079def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080080 if target is None:
81 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030082 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080083 assertion(loads(dumps(source, protocol=protocol)), target)
84
Serhiy Storchakae50e7802015-03-31 16:56:49 +030085def test_pickle_exception(assertion, exception, obj):
86 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080087 with assertion(exception):
88 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070089
90class TestHelpers(unittest.TestCase):
91 # _is_descriptor, _is_sunder, _is_dunder
92
93 def test_is_descriptor(self):
94 class foo:
95 pass
96 for attr in ('__get__','__set__','__delete__'):
97 obj = foo()
98 self.assertFalse(enum._is_descriptor(obj))
99 setattr(obj, attr, 1)
100 self.assertTrue(enum._is_descriptor(obj))
101
102 def test_is_sunder(self):
103 for s in ('_a_', '_aa_'):
104 self.assertTrue(enum._is_sunder(s))
105
106 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
107 '__', '___', '____', '_____',):
108 self.assertFalse(enum._is_sunder(s))
109
110 def test_is_dunder(self):
111 for s in ('__a__', '__aa__'):
112 self.assertTrue(enum._is_dunder(s))
113 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
114 '__', '___', '____', '_____',):
115 self.assertFalse(enum._is_dunder(s))
116
Ethan Furman5bdab642018-09-21 19:03:09 -0700117# for subclassing tests
118
119class classproperty:
120
121 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
122 self.fget = fget
123 self.fset = fset
124 self.fdel = fdel
125 if doc is None and fget is not None:
126 doc = fget.__doc__
127 self.__doc__ = doc
128
129 def __get__(self, instance, ownerclass):
130 return self.fget(ownerclass)
131
132
Ethan Furmanc16595e2016-09-10 23:36:59 -0700133# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700134
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700135class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800136
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700137 def setUp(self):
138 class Season(Enum):
139 SPRING = 1
140 SUMMER = 2
141 AUTUMN = 3
142 WINTER = 4
143 self.Season = Season
144
Ethan Furmanec15a822013-08-31 19:17:41 -0700145 class Konstants(float, Enum):
146 E = 2.7182818
147 PI = 3.1415926
148 TAU = 2 * PI
149 self.Konstants = Konstants
150
151 class Grades(IntEnum):
152 A = 5
153 B = 4
154 C = 3
155 D = 2
156 F = 0
157 self.Grades = Grades
158
159 class Directional(str, Enum):
160 EAST = 'east'
161 WEST = 'west'
162 NORTH = 'north'
163 SOUTH = 'south'
164 self.Directional = Directional
165
166 from datetime import date
167 class Holiday(date, Enum):
168 NEW_YEAR = 2013, 1, 1
169 IDES_OF_MARCH = 2013, 3, 15
170 self.Holiday = Holiday
171
Ethan Furman388a3922013-08-12 06:51:41 -0700172 def test_dir_on_class(self):
173 Season = self.Season
174 self.assertEqual(
175 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700176 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700177 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
178 )
179
180 def test_dir_on_item(self):
181 Season = self.Season
182 self.assertEqual(
183 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700184 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700185 )
186
Ethan Furmanc850f342013-09-15 16:59:35 -0700187 def test_dir_with_added_behavior(self):
188 class Test(Enum):
189 this = 'that'
190 these = 'those'
191 def wowser(self):
192 return ("Wowser! I'm %s!" % self.name)
193 self.assertEqual(
194 set(dir(Test)),
195 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
196 )
197 self.assertEqual(
198 set(dir(Test.this)),
199 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
200 )
201
Ethan Furman0ae550b2014-10-14 08:58:32 -0700202 def test_dir_on_sub_with_behavior_on_super(self):
203 # see issue22506
204 class SuperEnum(Enum):
205 def invisible(self):
206 return "did you see me?"
207 class SubEnum(SuperEnum):
208 sample = 5
209 self.assertEqual(
210 set(dir(SubEnum.sample)),
211 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
212 )
213
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200214 def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
215 # see issue40084
216 class SuperEnum(IntEnum):
217 def __new__(cls, value, description=""):
218 obj = int.__new__(cls, value)
219 obj._value_ = value
220 obj.description = description
221 return obj
222 class SubEnum(SuperEnum):
223 sample = 5
224 self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
225
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700226 def test_enum_in_enum_out(self):
227 Season = self.Season
228 self.assertIs(Season(Season.WINTER), Season.WINTER)
229
230 def test_enum_value(self):
231 Season = self.Season
232 self.assertEqual(Season.SPRING.value, 1)
233
234 def test_intenum_value(self):
235 self.assertEqual(IntStooges.CURLY.value, 2)
236
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700237 def test_enum(self):
238 Season = self.Season
239 lst = list(Season)
240 self.assertEqual(len(lst), len(Season))
241 self.assertEqual(len(Season), 4, Season)
242 self.assertEqual(
243 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
244
245 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
246 e = Season(i)
247 self.assertEqual(e, getattr(Season, season))
248 self.assertEqual(e.value, i)
249 self.assertNotEqual(e, i)
250 self.assertEqual(e.name, season)
251 self.assertIn(e, Season)
252 self.assertIs(type(e), Season)
253 self.assertIsInstance(e, Season)
254 self.assertEqual(str(e), 'Season.' + season)
255 self.assertEqual(
256 repr(e),
257 '<Season.{0}: {1}>'.format(season, i),
258 )
259
260 def test_value_name(self):
261 Season = self.Season
262 self.assertEqual(Season.SPRING.name, 'SPRING')
263 self.assertEqual(Season.SPRING.value, 1)
264 with self.assertRaises(AttributeError):
265 Season.SPRING.name = 'invierno'
266 with self.assertRaises(AttributeError):
267 Season.SPRING.value = 2
268
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700269 def test_changing_member(self):
270 Season = self.Season
271 with self.assertRaises(AttributeError):
272 Season.WINTER = 'really cold'
273
Ethan Furman64a99722013-09-22 16:18:19 -0700274 def test_attribute_deletion(self):
275 class Season(Enum):
276 SPRING = 1
277 SUMMER = 2
278 AUTUMN = 3
279 WINTER = 4
280
281 def spam(cls):
282 pass
283
284 self.assertTrue(hasattr(Season, 'spam'))
285 del Season.spam
286 self.assertFalse(hasattr(Season, 'spam'))
287
288 with self.assertRaises(AttributeError):
289 del Season.SPRING
290 with self.assertRaises(AttributeError):
291 del Season.DRY
292 with self.assertRaises(AttributeError):
293 del Season.SPRING.name
294
Ethan Furman5de67b12016-04-13 23:52:09 -0700295 def test_bool_of_class(self):
296 class Empty(Enum):
297 pass
298 self.assertTrue(bool(Empty))
299
300 def test_bool_of_member(self):
301 class Count(Enum):
302 zero = 0
303 one = 1
304 two = 2
305 for member in Count:
306 self.assertTrue(bool(member))
307
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700308 def test_invalid_names(self):
309 with self.assertRaises(ValueError):
310 class Wrong(Enum):
311 mro = 9
312 with self.assertRaises(ValueError):
313 class Wrong(Enum):
314 _create_= 11
315 with self.assertRaises(ValueError):
316 class Wrong(Enum):
317 _get_mixins_ = 9
318 with self.assertRaises(ValueError):
319 class Wrong(Enum):
320 _find_new_ = 1
321 with self.assertRaises(ValueError):
322 class Wrong(Enum):
323 _any_name_ = 9
324
Ethan Furman6db1fd52015-09-17 21:49:12 -0700325 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800326 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700327 class Logic(Enum):
328 true = True
329 false = False
330 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800331 self.assertTrue(Logic.false)
332 # unless overridden
333 class RealLogic(Enum):
334 true = True
335 false = False
336 def __bool__(self):
337 return bool(self._value_)
338 self.assertTrue(RealLogic.true)
339 self.assertFalse(RealLogic.false)
340 # mixed Enums depend on mixed-in type
341 class IntLogic(int, Enum):
342 true = 1
343 false = 0
344 self.assertTrue(IntLogic.true)
345 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700346
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700347 def test_contains(self):
348 Season = self.Season
349 self.assertIn(Season.AUTUMN, Season)
Rahul Jha94306522018-09-10 23:51:04 +0530350 with self.assertRaises(TypeError):
351 3 in Season
352 with self.assertRaises(TypeError):
353 'AUTUMN' in Season
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700354
355 val = Season(3)
356 self.assertIn(val, Season)
357
358 class OtherEnum(Enum):
359 one = 1; two = 2
360 self.assertNotIn(OtherEnum.two, Season)
361
362 def test_comparisons(self):
363 Season = self.Season
364 with self.assertRaises(TypeError):
365 Season.SPRING < Season.WINTER
366 with self.assertRaises(TypeError):
367 Season.SPRING > 4
368
369 self.assertNotEqual(Season.SPRING, 1)
370
371 class Part(Enum):
372 SPRING = 1
373 CLIP = 2
374 BARREL = 3
375
376 self.assertNotEqual(Season.SPRING, Part.SPRING)
377 with self.assertRaises(TypeError):
378 Season.SPRING < Part.CLIP
379
380 def test_enum_duplicates(self):
381 class Season(Enum):
382 SPRING = 1
383 SUMMER = 2
384 AUTUMN = FALL = 3
385 WINTER = 4
386 ANOTHER_SPRING = 1
387 lst = list(Season)
388 self.assertEqual(
389 lst,
390 [Season.SPRING, Season.SUMMER,
391 Season.AUTUMN, Season.WINTER,
392 ])
393 self.assertIs(Season.FALL, Season.AUTUMN)
394 self.assertEqual(Season.FALL.value, 3)
395 self.assertEqual(Season.AUTUMN.value, 3)
396 self.assertIs(Season(3), Season.AUTUMN)
397 self.assertIs(Season(1), Season.SPRING)
398 self.assertEqual(Season.FALL.name, 'AUTUMN')
399 self.assertEqual(
400 [k for k,v in Season.__members__.items() if v.name != k],
401 ['FALL', 'ANOTHER_SPRING'],
402 )
403
Ethan Furman101e0742013-09-15 12:34:36 -0700404 def test_duplicate_name(self):
405 with self.assertRaises(TypeError):
406 class Color(Enum):
407 red = 1
408 green = 2
409 blue = 3
410 red = 4
411
412 with self.assertRaises(TypeError):
413 class Color(Enum):
414 red = 1
415 green = 2
416 blue = 3
417 def red(self):
418 return 'red'
419
420 with self.assertRaises(TypeError):
421 class Color(Enum):
422 @property
423 def red(self):
424 return 'redder'
425 red = 1
426 green = 2
427 blue = 3
428
Zackery Spytz2ec67522020-09-13 14:27:51 -0600429 def test_reserved__sunder_(self):
Ethan Furman5a565b32020-09-15 12:27:06 -0700430 with self.assertRaisesRegex(
431 ValueError,
432 '_sunder_ names, such as "_bad_", are reserved',
433 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -0600434 class Bad(Enum):
435 _bad_ = 1
Ethan Furman101e0742013-09-15 12:34:36 -0700436
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700437 def test_enum_with_value_name(self):
438 class Huh(Enum):
439 name = 1
440 value = 2
441 self.assertEqual(
442 list(Huh),
443 [Huh.name, Huh.value],
444 )
445 self.assertIs(type(Huh.name), Huh)
446 self.assertEqual(Huh.name.name, 'name')
447 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700448
449 def test_format_enum(self):
450 Season = self.Season
451 self.assertEqual('{}'.format(Season.SPRING),
452 '{}'.format(str(Season.SPRING)))
453 self.assertEqual( '{:}'.format(Season.SPRING),
454 '{:}'.format(str(Season.SPRING)))
455 self.assertEqual('{:20}'.format(Season.SPRING),
456 '{:20}'.format(str(Season.SPRING)))
457 self.assertEqual('{:^20}'.format(Season.SPRING),
458 '{:^20}'.format(str(Season.SPRING)))
459 self.assertEqual('{:>20}'.format(Season.SPRING),
460 '{:>20}'.format(str(Season.SPRING)))
461 self.assertEqual('{:<20}'.format(Season.SPRING),
462 '{:<20}'.format(str(Season.SPRING)))
463
thatneat2f19e822019-07-04 11:28:37 -0700464 def test_str_override_enum(self):
465 class EnumWithStrOverrides(Enum):
466 one = auto()
467 two = auto()
468
469 def __str__(self):
470 return 'Str!'
471 self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
472 self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
473
474 def test_format_override_enum(self):
475 class EnumWithFormatOverride(Enum):
476 one = 1.0
477 two = 2.0
478 def __format__(self, spec):
479 return 'Format!!'
480 self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
481 self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
482
483 def test_str_and_format_override_enum(self):
484 class EnumWithStrFormatOverrides(Enum):
485 one = auto()
486 two = auto()
487 def __str__(self):
488 return 'Str!'
489 def __format__(self, spec):
490 return 'Format!'
491 self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
492 self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
493
494 def test_str_override_mixin(self):
495 class MixinEnumWithStrOverride(float, Enum):
496 one = 1.0
497 two = 2.0
498 def __str__(self):
499 return 'Overridden!'
500 self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
501 self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
502
503 def test_str_and_format_override_mixin(self):
504 class MixinWithStrFormatOverrides(float, Enum):
505 one = 1.0
506 two = 2.0
507 def __str__(self):
508 return 'Str!'
509 def __format__(self, spec):
510 return 'Format!'
511 self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
512 self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
513
514 def test_format_override_mixin(self):
Ethan Furmanec15a822013-08-31 19:17:41 -0700515 class TestFloat(float, Enum):
516 one = 1.0
517 two = 2.0
518 def __format__(self, spec):
519 return 'TestFloat success!'
thatneat2f19e822019-07-04 11:28:37 -0700520 self.assertEqual(str(TestFloat.one), 'TestFloat.one')
Ethan Furmanec15a822013-08-31 19:17:41 -0700521 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
522
523 def assertFormatIsValue(self, spec, member):
524 self.assertEqual(spec.format(member), spec.format(member.value))
525
526 def test_format_enum_date(self):
527 Holiday = self.Holiday
528 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
529 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
530 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
531 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
532 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
533 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
534 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
535 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
536
537 def test_format_enum_float(self):
538 Konstants = self.Konstants
539 self.assertFormatIsValue('{}', Konstants.TAU)
540 self.assertFormatIsValue('{:}', Konstants.TAU)
541 self.assertFormatIsValue('{:20}', Konstants.TAU)
542 self.assertFormatIsValue('{:^20}', Konstants.TAU)
543 self.assertFormatIsValue('{:>20}', Konstants.TAU)
544 self.assertFormatIsValue('{:<20}', Konstants.TAU)
545 self.assertFormatIsValue('{:n}', Konstants.TAU)
546 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
547 self.assertFormatIsValue('{:f}', Konstants.TAU)
548
549 def test_format_enum_int(self):
550 Grades = self.Grades
551 self.assertFormatIsValue('{}', Grades.C)
552 self.assertFormatIsValue('{:}', Grades.C)
553 self.assertFormatIsValue('{:20}', Grades.C)
554 self.assertFormatIsValue('{:^20}', Grades.C)
555 self.assertFormatIsValue('{:>20}', Grades.C)
556 self.assertFormatIsValue('{:<20}', Grades.C)
557 self.assertFormatIsValue('{:+}', Grades.C)
558 self.assertFormatIsValue('{:08X}', Grades.C)
559 self.assertFormatIsValue('{:b}', Grades.C)
560
561 def test_format_enum_str(self):
562 Directional = self.Directional
563 self.assertFormatIsValue('{}', Directional.WEST)
564 self.assertFormatIsValue('{:}', Directional.WEST)
565 self.assertFormatIsValue('{:20}', Directional.WEST)
566 self.assertFormatIsValue('{:^20}', Directional.WEST)
567 self.assertFormatIsValue('{:>20}', Directional.WEST)
568 self.assertFormatIsValue('{:<20}', Directional.WEST)
569
Ethan Furman22415ad2020-09-15 16:28:25 -0700570 def test_object_str_override(self):
571 class Colors(Enum):
572 RED, GREEN, BLUE = 1, 2, 3
573 def __repr__(self):
574 return "test.%s" % (self._name_, )
575 __str__ = object.__str__
576 self.assertEqual(str(Colors.RED), 'test.RED')
577
Ethan Furmanbff01f32020-09-15 15:56:26 -0700578 def test_enum_str_override(self):
579 class MyStrEnum(Enum):
580 def __str__(self):
581 return 'MyStr'
582 class MyMethodEnum(Enum):
583 def hello(self):
584 return 'Hello! My name is %s' % self.name
585 class Test1Enum(MyMethodEnum, int, MyStrEnum):
586 One = 1
587 Two = 2
588 self.assertEqual(str(Test1Enum.One), 'MyStr')
589 #
590 class Test2Enum(MyStrEnum, MyMethodEnum):
591 One = 1
592 Two = 2
593 self.assertEqual(str(Test2Enum.One), 'MyStr')
594
595 def test_inherited_data_type(self):
596 class HexInt(int):
597 def __repr__(self):
598 return hex(self)
599 class MyEnum(HexInt, enum.Enum):
600 A = 1
601 B = 2
602 C = 3
603 self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
604
605 def test_too_many_data_types(self):
606 with self.assertRaisesRegex(TypeError, 'too many data types'):
607 class Huh(str, int, Enum):
608 One = 1
609
610 class MyStr(str):
611 def hello(self):
612 return 'hello, %s' % self
613 class MyInt(int):
614 def repr(self):
615 return hex(self)
616 with self.assertRaisesRegex(TypeError, 'too many data types'):
617 class Huh(MyStr, MyInt, Enum):
618 One = 1
619
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700620 def test_hash(self):
621 Season = self.Season
622 dates = {}
623 dates[Season.WINTER] = '1225'
624 dates[Season.SPRING] = '0315'
625 dates[Season.SUMMER] = '0704'
626 dates[Season.AUTUMN] = '1031'
627 self.assertEqual(dates[Season.AUTUMN], '1031')
628
629 def test_intenum_from_scratch(self):
630 class phy(int, Enum):
631 pi = 3
632 tau = 2 * pi
633 self.assertTrue(phy.pi < phy.tau)
634
635 def test_intenum_inherited(self):
636 class IntEnum(int, Enum):
637 pass
638 class phy(IntEnum):
639 pi = 3
640 tau = 2 * pi
641 self.assertTrue(phy.pi < phy.tau)
642
643 def test_floatenum_from_scratch(self):
644 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700645 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700646 tau = 2 * pi
647 self.assertTrue(phy.pi < phy.tau)
648
649 def test_floatenum_inherited(self):
650 class FloatEnum(float, Enum):
651 pass
652 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700653 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700654 tau = 2 * pi
655 self.assertTrue(phy.pi < phy.tau)
656
657 def test_strenum_from_scratch(self):
658 class phy(str, Enum):
659 pi = 'Pi'
660 tau = 'Tau'
661 self.assertTrue(phy.pi < phy.tau)
662
Ethan Furman0063ff42020-09-21 17:23:13 -0700663 def test_strenum_inherited_methods(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700664 class phy(StrEnum):
665 pi = 'Pi'
666 tau = 'Tau'
667 self.assertTrue(phy.pi < phy.tau)
Ethan Furman0063ff42020-09-21 17:23:13 -0700668 self.assertEqual(phy.pi.upper(), 'PI')
669 self.assertEqual(phy.tau.count('a'), 1)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700670
671 def test_intenum(self):
672 class WeekDay(IntEnum):
673 SUNDAY = 1
674 MONDAY = 2
675 TUESDAY = 3
676 WEDNESDAY = 4
677 THURSDAY = 5
678 FRIDAY = 6
679 SATURDAY = 7
680
681 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
682 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
683
684 lst = list(WeekDay)
685 self.assertEqual(len(lst), len(WeekDay))
686 self.assertEqual(len(WeekDay), 7)
687 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
688 target = target.split()
689 for i, weekday in enumerate(target, 1):
690 e = WeekDay(i)
691 self.assertEqual(e, i)
692 self.assertEqual(int(e), i)
693 self.assertEqual(e.name, weekday)
694 self.assertIn(e, WeekDay)
695 self.assertEqual(lst.index(e)+1, i)
696 self.assertTrue(0 < e < 8)
697 self.assertIs(type(e), WeekDay)
698 self.assertIsInstance(e, int)
699 self.assertIsInstance(e, Enum)
700
701 def test_intenum_duplicates(self):
702 class WeekDay(IntEnum):
703 SUNDAY = 1
704 MONDAY = 2
705 TUESDAY = TEUSDAY = 3
706 WEDNESDAY = 4
707 THURSDAY = 5
708 FRIDAY = 6
709 SATURDAY = 7
710 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
711 self.assertEqual(WeekDay(3).name, 'TUESDAY')
712 self.assertEqual([k for k,v in WeekDay.__members__.items()
713 if v.name != k], ['TEUSDAY', ])
714
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300715 def test_intenum_from_bytes(self):
716 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
717 with self.assertRaises(ValueError):
718 IntStooges.from_bytes(b'\x00\x05', 'big')
719
720 def test_floatenum_fromhex(self):
721 h = float.hex(FloatStooges.MOE.value)
722 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
723 h = float.hex(FloatStooges.MOE.value + 0.01)
724 with self.assertRaises(ValueError):
725 FloatStooges.fromhex(h)
726
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700727 def test_pickle_enum(self):
728 if isinstance(Stooges, Exception):
729 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800730 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
731 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700732
733 def test_pickle_int(self):
734 if isinstance(IntStooges, Exception):
735 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800736 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
737 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700738
739 def test_pickle_float(self):
740 if isinstance(FloatStooges, Exception):
741 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800742 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
743 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700744
745 def test_pickle_enum_function(self):
746 if isinstance(Answer, Exception):
747 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800748 test_pickle_dump_load(self.assertIs, Answer.him)
749 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700750
751 def test_pickle_enum_function_with_module(self):
752 if isinstance(Question, Exception):
753 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800754 test_pickle_dump_load(self.assertIs, Question.who)
755 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700756
Ethan Furmanca1b7942014-02-08 11:36:27 -0800757 def test_enum_function_with_qualname(self):
758 if isinstance(Theory, Exception):
759 raise Theory
760 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
761
762 def test_class_nested_enum_and_pickle_protocol_four(self):
763 # would normally just have this directly in the class namespace
764 class NestedEnum(Enum):
765 twigs = 'common'
766 shiny = 'rare'
767
768 self.__class__.NestedEnum = NestedEnum
769 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300770 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800771
Ethan Furman24e837f2015-03-18 17:27:57 -0700772 def test_pickle_by_name(self):
773 class ReplaceGlobalInt(IntEnum):
774 ONE = 1
775 TWO = 2
776 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
777 for proto in range(HIGHEST_PROTOCOL):
778 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
779
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700780 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800781 BadPickle = Enum(
782 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700783 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800784 # now break BadPickle to test exception raising
785 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800786 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
787 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700788
789 def test_string_enum(self):
790 class SkillLevel(str, Enum):
791 master = 'what is the sound of one hand clapping?'
792 journeyman = 'why did the chicken cross the road?'
793 apprentice = 'knock, knock!'
794 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
795
796 def test_getattr_getitem(self):
797 class Period(Enum):
798 morning = 1
799 noon = 2
800 evening = 3
801 night = 4
802 self.assertIs(Period(2), Period.noon)
803 self.assertIs(getattr(Period, 'night'), Period.night)
804 self.assertIs(Period['morning'], Period.morning)
805
806 def test_getattr_dunder(self):
807 Season = self.Season
808 self.assertTrue(getattr(Season, '__eq__'))
809
810 def test_iteration_order(self):
811 class Season(Enum):
812 SUMMER = 2
813 WINTER = 4
814 AUTUMN = 3
815 SPRING = 1
816 self.assertEqual(
817 list(Season),
818 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
819 )
820
Ethan Furman2131a4a2013-09-14 18:11:24 -0700821 def test_reversed_iteration_order(self):
822 self.assertEqual(
823 list(reversed(self.Season)),
824 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
825 self.Season.SPRING]
826 )
827
Martin Pantereb995702016-07-28 01:11:04 +0000828 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700829 SummerMonth = Enum('SummerMonth', 'june july august')
830 lst = list(SummerMonth)
831 self.assertEqual(len(lst), len(SummerMonth))
832 self.assertEqual(len(SummerMonth), 3, SummerMonth)
833 self.assertEqual(
834 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
835 lst,
836 )
837 for i, month in enumerate('june july august'.split(), 1):
838 e = SummerMonth(i)
839 self.assertEqual(int(e.value), i)
840 self.assertNotEqual(e, i)
841 self.assertEqual(e.name, month)
842 self.assertIn(e, SummerMonth)
843 self.assertIs(type(e), SummerMonth)
844
Martin Pantereb995702016-07-28 01:11:04 +0000845 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700846 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
847 lst = list(SummerMonth)
848 self.assertEqual(len(lst), len(SummerMonth))
849 self.assertEqual(len(SummerMonth), 3, SummerMonth)
850 self.assertEqual(
851 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
852 lst,
853 )
854 for i, month in enumerate('june july august'.split(), 10):
855 e = SummerMonth(i)
856 self.assertEqual(int(e.value), i)
857 self.assertNotEqual(e, i)
858 self.assertEqual(e.name, month)
859 self.assertIn(e, SummerMonth)
860 self.assertIs(type(e), SummerMonth)
861
Martin Pantereb995702016-07-28 01:11:04 +0000862 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700863 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
864 lst = list(SummerMonth)
865 self.assertEqual(len(lst), len(SummerMonth))
866 self.assertEqual(len(SummerMonth), 3, SummerMonth)
867 self.assertEqual(
868 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
869 lst,
870 )
871 for i, month in enumerate('june july august'.split(), 1):
872 e = SummerMonth(i)
873 self.assertEqual(int(e.value), i)
874 self.assertNotEqual(e, i)
875 self.assertEqual(e.name, month)
876 self.assertIn(e, SummerMonth)
877 self.assertIs(type(e), SummerMonth)
878
Martin Pantereb995702016-07-28 01:11:04 +0000879 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700880 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
881 lst = list(SummerMonth)
882 self.assertEqual(len(lst), len(SummerMonth))
883 self.assertEqual(len(SummerMonth), 3, SummerMonth)
884 self.assertEqual(
885 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
886 lst,
887 )
888 for i, month in enumerate('june july august'.split(), 20):
889 e = SummerMonth(i)
890 self.assertEqual(int(e.value), i)
891 self.assertNotEqual(e, i)
892 self.assertEqual(e.name, month)
893 self.assertIn(e, SummerMonth)
894 self.assertIs(type(e), SummerMonth)
895
Martin Pantereb995702016-07-28 01:11:04 +0000896 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700897 SummerMonth = Enum(
898 'SummerMonth',
899 (('june', 1), ('july', 2), ('august', 3))
900 )
901 lst = list(SummerMonth)
902 self.assertEqual(len(lst), len(SummerMonth))
903 self.assertEqual(len(SummerMonth), 3, SummerMonth)
904 self.assertEqual(
905 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
906 lst,
907 )
908 for i, month in enumerate('june july august'.split(), 1):
909 e = SummerMonth(i)
910 self.assertEqual(int(e.value), i)
911 self.assertNotEqual(e, i)
912 self.assertEqual(e.name, month)
913 self.assertIn(e, SummerMonth)
914 self.assertIs(type(e), SummerMonth)
915
Martin Pantereb995702016-07-28 01:11:04 +0000916 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700917 SummerMonth = Enum(
918 'SummerMonth',
919 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
920 )
921 lst = list(SummerMonth)
922 self.assertEqual(len(lst), len(SummerMonth))
923 self.assertEqual(len(SummerMonth), 3, SummerMonth)
924 self.assertEqual(
925 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
926 lst,
927 )
928 for i, month in enumerate('june july august'.split(), 1):
929 e = SummerMonth(i)
930 self.assertEqual(int(e.value), i)
931 self.assertNotEqual(e, i)
932 self.assertEqual(e.name, month)
933 self.assertIn(e, SummerMonth)
934 self.assertIs(type(e), SummerMonth)
935
Martin Pantereb995702016-07-28 01:11:04 +0000936 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700937 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
938 lst = list(SummerMonth)
939 self.assertEqual(len(lst), len(SummerMonth))
940 self.assertEqual(len(SummerMonth), 3, SummerMonth)
941 self.assertEqual(
942 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
943 lst,
944 )
945 for i, month in enumerate('june july august'.split(), 1):
946 e = SummerMonth(i)
947 self.assertEqual(e, i)
948 self.assertEqual(e.name, month)
949 self.assertIn(e, SummerMonth)
950 self.assertIs(type(e), SummerMonth)
951
Martin Pantereb995702016-07-28 01:11:04 +0000952 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700953 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
954 lst = list(SummerMonth)
955 self.assertEqual(len(lst), len(SummerMonth))
956 self.assertEqual(len(SummerMonth), 3, SummerMonth)
957 self.assertEqual(
958 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
959 lst,
960 )
961 for i, month in enumerate('june july august'.split(), 30):
962 e = SummerMonth(i)
963 self.assertEqual(e, i)
964 self.assertEqual(e.name, month)
965 self.assertIn(e, SummerMonth)
966 self.assertIs(type(e), SummerMonth)
967
Martin Pantereb995702016-07-28 01:11:04 +0000968 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700969 SummerMonth = IntEnum('SummerMonth', 'june july august')
970 lst = list(SummerMonth)
971 self.assertEqual(len(lst), len(SummerMonth))
972 self.assertEqual(len(SummerMonth), 3, SummerMonth)
973 self.assertEqual(
974 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
975 lst,
976 )
977 for i, month in enumerate('june july august'.split(), 1):
978 e = SummerMonth(i)
979 self.assertEqual(e, i)
980 self.assertEqual(e.name, month)
981 self.assertIn(e, SummerMonth)
982 self.assertIs(type(e), SummerMonth)
983
Martin Pantereb995702016-07-28 01:11:04 +0000984 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700985 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
986 lst = list(SummerMonth)
987 self.assertEqual(len(lst), len(SummerMonth))
988 self.assertEqual(len(SummerMonth), 3, SummerMonth)
989 self.assertEqual(
990 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
991 lst,
992 )
993 for i, month in enumerate('june july august'.split(), 40):
994 e = SummerMonth(i)
995 self.assertEqual(e, i)
996 self.assertEqual(e.name, month)
997 self.assertIn(e, SummerMonth)
998 self.assertIs(type(e), SummerMonth)
999
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001000 def test_subclassing(self):
1001 if isinstance(Name, Exception):
1002 raise Name
1003 self.assertEqual(Name.BDFL, 'Guido van Rossum')
1004 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
1005 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001006 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001007
1008 def test_extending(self):
1009 class Color(Enum):
1010 red = 1
1011 green = 2
1012 blue = 3
1013 with self.assertRaises(TypeError):
1014 class MoreColor(Color):
1015 cyan = 4
1016 magenta = 5
1017 yellow = 6
Ethan Furman3064dbf2020-09-16 07:11:57 -07001018 with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1019 class EvenMoreColor(Color, IntEnum):
1020 chartruese = 7
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001021
1022 def test_exclude_methods(self):
1023 class whatever(Enum):
1024 this = 'that'
1025 these = 'those'
1026 def really(self):
1027 return 'no, not %s' % self.value
1028 self.assertIsNot(type(whatever.really), whatever)
1029 self.assertEqual(whatever.this.really(), 'no, not that')
1030
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001031 def test_wrong_inheritance_order(self):
1032 with self.assertRaises(TypeError):
1033 class Wrong(Enum, str):
1034 NotHere = 'error before this point'
1035
1036 def test_intenum_transitivity(self):
1037 class number(IntEnum):
1038 one = 1
1039 two = 2
1040 three = 3
1041 class numero(IntEnum):
1042 uno = 1
1043 dos = 2
1044 tres = 3
1045 self.assertEqual(number.one, numero.uno)
1046 self.assertEqual(number.two, numero.dos)
1047 self.assertEqual(number.three, numero.tres)
1048
1049 def test_wrong_enum_in_call(self):
1050 class Monochrome(Enum):
1051 black = 0
1052 white = 1
1053 class Gender(Enum):
1054 male = 0
1055 female = 1
1056 self.assertRaises(ValueError, Monochrome, Gender.male)
1057
1058 def test_wrong_enum_in_mixed_call(self):
1059 class Monochrome(IntEnum):
1060 black = 0
1061 white = 1
1062 class Gender(Enum):
1063 male = 0
1064 female = 1
1065 self.assertRaises(ValueError, Monochrome, Gender.male)
1066
1067 def test_mixed_enum_in_call_1(self):
1068 class Monochrome(IntEnum):
1069 black = 0
1070 white = 1
1071 class Gender(IntEnum):
1072 male = 0
1073 female = 1
1074 self.assertIs(Monochrome(Gender.female), Monochrome.white)
1075
1076 def test_mixed_enum_in_call_2(self):
1077 class Monochrome(Enum):
1078 black = 0
1079 white = 1
1080 class Gender(IntEnum):
1081 male = 0
1082 female = 1
1083 self.assertIs(Monochrome(Gender.male), Monochrome.black)
1084
1085 def test_flufl_enum(self):
1086 class Fluflnum(Enum):
1087 def __int__(self):
1088 return int(self.value)
1089 class MailManOptions(Fluflnum):
1090 option1 = 1
1091 option2 = 2
1092 option3 = 3
1093 self.assertEqual(int(MailManOptions.option1), 1)
1094
Ethan Furman5e5a8232013-08-04 08:42:23 -07001095 def test_introspection(self):
1096 class Number(IntEnum):
1097 one = 100
1098 two = 200
1099 self.assertIs(Number.one._member_type_, int)
1100 self.assertIs(Number._member_type_, int)
1101 class String(str, Enum):
1102 yarn = 'soft'
1103 rope = 'rough'
1104 wire = 'hard'
1105 self.assertIs(String.yarn._member_type_, str)
1106 self.assertIs(String._member_type_, str)
1107 class Plain(Enum):
1108 vanilla = 'white'
1109 one = 1
1110 self.assertIs(Plain.vanilla._member_type_, object)
1111 self.assertIs(Plain._member_type_, object)
1112
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001113 def test_no_such_enum_member(self):
1114 class Color(Enum):
1115 red = 1
1116 green = 2
1117 blue = 3
1118 with self.assertRaises(ValueError):
1119 Color(4)
1120 with self.assertRaises(KeyError):
1121 Color['chartreuse']
1122
1123 def test_new_repr(self):
1124 class Color(Enum):
1125 red = 1
1126 green = 2
1127 blue = 3
1128 def __repr__(self):
1129 return "don't you just love shades of %s?" % self.name
1130 self.assertEqual(
1131 repr(Color.blue),
1132 "don't you just love shades of blue?",
1133 )
1134
1135 def test_inherited_repr(self):
1136 class MyEnum(Enum):
1137 def __repr__(self):
1138 return "My name is %s." % self.name
1139 class MyIntEnum(int, MyEnum):
1140 this = 1
1141 that = 2
1142 theother = 3
1143 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1144
1145 def test_multiple_mixin_mro(self):
1146 class auto_enum(type(Enum)):
1147 def __new__(metacls, cls, bases, classdict):
1148 temp = type(classdict)()
1149 names = set(classdict._member_names)
1150 i = 0
1151 for k in classdict._member_names:
1152 v = classdict[k]
1153 if v is Ellipsis:
1154 v = i
1155 else:
1156 i = v
1157 i += 1
1158 temp[k] = v
1159 for k, v in classdict.items():
1160 if k not in names:
1161 temp[k] = v
1162 return super(auto_enum, metacls).__new__(
1163 metacls, cls, bases, temp)
1164
1165 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1166 pass
1167
1168 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1169 pass
1170
1171 class TestAutoNumber(AutoNumberedEnum):
1172 a = ...
1173 b = 3
1174 c = ...
1175
1176 class TestAutoInt(AutoIntEnum):
1177 a = ...
1178 b = 3
1179 c = ...
1180
1181 def test_subclasses_with_getnewargs(self):
1182 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001183 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001184 def __new__(cls, *args):
1185 _args = args
1186 name, *args = args
1187 if len(args) == 0:
1188 raise TypeError("name and value must be specified")
1189 self = int.__new__(cls, *args)
1190 self._intname = name
1191 self._args = _args
1192 return self
1193 def __getnewargs__(self):
1194 return self._args
1195 @property
1196 def __name__(self):
1197 return self._intname
1198 def __repr__(self):
1199 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001200 return "{}({!r}, {})".format(
1201 type(self).__name__,
1202 self.__name__,
1203 int.__repr__(self),
1204 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001205 def __str__(self):
1206 # str() is unchanged, even if it relies on the repr() fallback
1207 base = int
1208 base_str = base.__str__
1209 if base_str.__objclass__ is object:
1210 return base.__repr__(self)
1211 return base_str(self)
1212 # for simplicity, we only define one operator that
1213 # propagates expressions
1214 def __add__(self, other):
1215 temp = int(self) + int( other)
1216 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1217 return NamedInt(
1218 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001219 temp,
1220 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001221 else:
1222 return temp
1223
1224 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001225 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001226 x = ('the-x', 1)
1227 y = ('the-y', 2)
1228
Ethan Furman2aa27322013-07-19 19:35:56 -07001229
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001230 self.assertIs(NEI.__new__, Enum.__new__)
1231 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1232 globals()['NamedInt'] = NamedInt
1233 globals()['NEI'] = NEI
1234 NI5 = NamedInt('test', 5)
1235 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001236 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001237 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001238 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001239 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001240
Ethan Furmanca1b7942014-02-08 11:36:27 -08001241 def test_subclasses_with_getnewargs_ex(self):
1242 class NamedInt(int):
1243 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1244 def __new__(cls, *args):
1245 _args = args
1246 name, *args = args
1247 if len(args) == 0:
1248 raise TypeError("name and value must be specified")
1249 self = int.__new__(cls, *args)
1250 self._intname = name
1251 self._args = _args
1252 return self
1253 def __getnewargs_ex__(self):
1254 return self._args, {}
1255 @property
1256 def __name__(self):
1257 return self._intname
1258 def __repr__(self):
1259 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001260 return "{}({!r}, {})".format(
1261 type(self).__name__,
1262 self.__name__,
1263 int.__repr__(self),
1264 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001265 def __str__(self):
1266 # str() is unchanged, even if it relies on the repr() fallback
1267 base = int
1268 base_str = base.__str__
1269 if base_str.__objclass__ is object:
1270 return base.__repr__(self)
1271 return base_str(self)
1272 # for simplicity, we only define one operator that
1273 # propagates expressions
1274 def __add__(self, other):
1275 temp = int(self) + int( other)
1276 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1277 return NamedInt(
1278 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001279 temp,
1280 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001281 else:
1282 return temp
1283
1284 class NEI(NamedInt, Enum):
1285 __qualname__ = 'NEI' # needed for pickle protocol 4
1286 x = ('the-x', 1)
1287 y = ('the-y', 2)
1288
1289
1290 self.assertIs(NEI.__new__, Enum.__new__)
1291 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1292 globals()['NamedInt'] = NamedInt
1293 globals()['NEI'] = NEI
1294 NI5 = NamedInt('test', 5)
1295 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001296 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001297 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001298 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001299 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001300
1301 def test_subclasses_with_reduce(self):
1302 class NamedInt(int):
1303 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1304 def __new__(cls, *args):
1305 _args = args
1306 name, *args = args
1307 if len(args) == 0:
1308 raise TypeError("name and value must be specified")
1309 self = int.__new__(cls, *args)
1310 self._intname = name
1311 self._args = _args
1312 return self
1313 def __reduce__(self):
1314 return self.__class__, self._args
1315 @property
1316 def __name__(self):
1317 return self._intname
1318 def __repr__(self):
1319 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001320 return "{}({!r}, {})".format(
1321 type(self).__name__,
1322 self.__name__,
1323 int.__repr__(self),
1324 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001325 def __str__(self):
1326 # str() is unchanged, even if it relies on the repr() fallback
1327 base = int
1328 base_str = base.__str__
1329 if base_str.__objclass__ is object:
1330 return base.__repr__(self)
1331 return base_str(self)
1332 # for simplicity, we only define one operator that
1333 # propagates expressions
1334 def __add__(self, other):
1335 temp = int(self) + int( other)
1336 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1337 return NamedInt(
1338 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001339 temp,
1340 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001341 else:
1342 return temp
1343
1344 class NEI(NamedInt, Enum):
1345 __qualname__ = 'NEI' # needed for pickle protocol 4
1346 x = ('the-x', 1)
1347 y = ('the-y', 2)
1348
1349
1350 self.assertIs(NEI.__new__, Enum.__new__)
1351 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1352 globals()['NamedInt'] = NamedInt
1353 globals()['NEI'] = NEI
1354 NI5 = NamedInt('test', 5)
1355 self.assertEqual(NI5, 5)
1356 test_pickle_dump_load(self.assertEqual, NI5, 5)
1357 self.assertEqual(NEI.y.value, 2)
1358 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001359 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001360
1361 def test_subclasses_with_reduce_ex(self):
1362 class NamedInt(int):
1363 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1364 def __new__(cls, *args):
1365 _args = args
1366 name, *args = args
1367 if len(args) == 0:
1368 raise TypeError("name and value must be specified")
1369 self = int.__new__(cls, *args)
1370 self._intname = name
1371 self._args = _args
1372 return self
1373 def __reduce_ex__(self, proto):
1374 return self.__class__, self._args
1375 @property
1376 def __name__(self):
1377 return self._intname
1378 def __repr__(self):
1379 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001380 return "{}({!r}, {})".format(
1381 type(self).__name__,
1382 self.__name__,
1383 int.__repr__(self),
1384 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001385 def __str__(self):
1386 # str() is unchanged, even if it relies on the repr() fallback
1387 base = int
1388 base_str = base.__str__
1389 if base_str.__objclass__ is object:
1390 return base.__repr__(self)
1391 return base_str(self)
1392 # for simplicity, we only define one operator that
1393 # propagates expressions
1394 def __add__(self, other):
1395 temp = int(self) + int( other)
1396 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1397 return NamedInt(
1398 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001399 temp,
1400 )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001401 else:
1402 return temp
1403
1404 class NEI(NamedInt, Enum):
1405 __qualname__ = 'NEI' # needed for pickle protocol 4
1406 x = ('the-x', 1)
1407 y = ('the-y', 2)
1408
Ethan Furmanca1b7942014-02-08 11:36:27 -08001409 self.assertIs(NEI.__new__, Enum.__new__)
1410 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1411 globals()['NamedInt'] = NamedInt
1412 globals()['NEI'] = NEI
1413 NI5 = NamedInt('test', 5)
1414 self.assertEqual(NI5, 5)
1415 test_pickle_dump_load(self.assertEqual, NI5, 5)
1416 self.assertEqual(NEI.y.value, 2)
1417 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001418 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001419
Ethan Furmandc870522014-02-18 12:37:12 -08001420 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001421 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001422 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001423 def __new__(cls, *args):
1424 _args = args
1425 name, *args = args
1426 if len(args) == 0:
1427 raise TypeError("name and value must be specified")
1428 self = int.__new__(cls, *args)
1429 self._intname = name
1430 self._args = _args
1431 return self
1432 @property
1433 def __name__(self):
1434 return self._intname
1435 def __repr__(self):
1436 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001437 return "{}({!r}, {})".format(
1438 type(self).__name__,
1439 self.__name__,
1440 int.__repr__(self),
1441 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001442 def __str__(self):
1443 # str() is unchanged, even if it relies on the repr() fallback
1444 base = int
1445 base_str = base.__str__
1446 if base_str.__objclass__ is object:
1447 return base.__repr__(self)
1448 return base_str(self)
1449 # for simplicity, we only define one operator that
1450 # propagates expressions
1451 def __add__(self, other):
1452 temp = int(self) + int( other)
1453 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1454 return NamedInt(
1455 '({0} + {1})'.format(self.__name__, other.__name__),
1456 temp )
1457 else:
1458 return temp
1459
1460 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001461 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001462 x = ('the-x', 1)
1463 y = ('the-y', 2)
1464
1465 self.assertIs(NEI.__new__, Enum.__new__)
1466 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1467 globals()['NamedInt'] = NamedInt
1468 globals()['NEI'] = NEI
1469 NI5 = NamedInt('test', 5)
1470 self.assertEqual(NI5, 5)
1471 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001472 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1473 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001474
Ethan Furmandc870522014-02-18 12:37:12 -08001475 def test_subclasses_without_direct_pickle_support_using_name(self):
1476 class NamedInt(int):
1477 __qualname__ = 'NamedInt'
1478 def __new__(cls, *args):
1479 _args = args
1480 name, *args = args
1481 if len(args) == 0:
1482 raise TypeError("name and value must be specified")
1483 self = int.__new__(cls, *args)
1484 self._intname = name
1485 self._args = _args
1486 return self
1487 @property
1488 def __name__(self):
1489 return self._intname
1490 def __repr__(self):
1491 # repr() is updated to include the name and type info
Ethan Furman5a565b32020-09-15 12:27:06 -07001492 return "{}({!r}, {})".format(
1493 type(self).__name__,
1494 self.__name__,
1495 int.__repr__(self),
1496 )
Ethan Furmandc870522014-02-18 12:37:12 -08001497 def __str__(self):
1498 # str() is unchanged, even if it relies on the repr() fallback
1499 base = int
1500 base_str = base.__str__
1501 if base_str.__objclass__ is object:
1502 return base.__repr__(self)
1503 return base_str(self)
1504 # for simplicity, we only define one operator that
1505 # propagates expressions
1506 def __add__(self, other):
1507 temp = int(self) + int( other)
1508 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1509 return NamedInt(
1510 '({0} + {1})'.format(self.__name__, other.__name__),
Ethan Furman5a565b32020-09-15 12:27:06 -07001511 temp,
1512 )
Ethan Furmandc870522014-02-18 12:37:12 -08001513 else:
1514 return temp
1515
1516 class NEI(NamedInt, Enum):
1517 __qualname__ = 'NEI'
1518 x = ('the-x', 1)
1519 y = ('the-y', 2)
1520 def __reduce_ex__(self, proto):
1521 return getattr, (self.__class__, self._name_)
1522
1523 self.assertIs(NEI.__new__, Enum.__new__)
1524 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1525 globals()['NamedInt'] = NamedInt
1526 globals()['NEI'] = NEI
1527 NI5 = NamedInt('test', 5)
1528 self.assertEqual(NI5, 5)
1529 self.assertEqual(NEI.y.value, 2)
1530 test_pickle_dump_load(self.assertIs, NEI.y)
1531 test_pickle_dump_load(self.assertIs, NEI)
1532
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001533 def test_tuple_subclass(self):
1534 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001535 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001536 first = (1, 'for the money')
1537 second = (2, 'for the show')
1538 third = (3, 'for the music')
1539 self.assertIs(type(SomeTuple.first), SomeTuple)
1540 self.assertIsInstance(SomeTuple.second, tuple)
1541 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1542 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001543 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001544
1545 def test_duplicate_values_give_unique_enum_items(self):
1546 class AutoNumber(Enum):
1547 first = ()
1548 second = ()
1549 third = ()
1550 def __new__(cls):
1551 value = len(cls.__members__) + 1
1552 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001553 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001554 return obj
1555 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001556 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001557 self.assertEqual(
1558 list(AutoNumber),
1559 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1560 )
1561 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001562 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001563 self.assertIs(AutoNumber(1), AutoNumber.first)
1564
1565 def test_inherited_new_from_enhanced_enum(self):
1566 class AutoNumber(Enum):
1567 def __new__(cls):
1568 value = len(cls.__members__) + 1
1569 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001570 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001571 return obj
1572 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001573 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001574 class Color(AutoNumber):
1575 red = ()
1576 green = ()
1577 blue = ()
1578 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1579 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1580
1581 def test_inherited_new_from_mixed_enum(self):
1582 class AutoNumber(IntEnum):
1583 def __new__(cls):
1584 value = len(cls.__members__) + 1
1585 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001586 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001587 return obj
1588 class Color(AutoNumber):
1589 red = ()
1590 green = ()
1591 blue = ()
1592 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1593 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1594
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001595 def test_equality(self):
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001596 class OrdinaryEnum(Enum):
1597 a = 1
Serhiy Storchaka7d44e7a2019-08-08 08:43:18 +03001598 self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
1599 self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001600
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001601 def test_ordered_mixin(self):
1602 class OrderedEnum(Enum):
1603 def __ge__(self, other):
1604 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001605 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001606 return NotImplemented
1607 def __gt__(self, other):
1608 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001609 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001610 return NotImplemented
1611 def __le__(self, other):
1612 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001613 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001614 return NotImplemented
1615 def __lt__(self, other):
1616 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001617 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001618 return NotImplemented
1619 class Grade(OrderedEnum):
1620 A = 5
1621 B = 4
1622 C = 3
1623 D = 2
1624 F = 1
1625 self.assertGreater(Grade.A, Grade.B)
1626 self.assertLessEqual(Grade.F, Grade.C)
1627 self.assertLess(Grade.D, Grade.A)
1628 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001629 self.assertEqual(Grade.B, Grade.B)
1630 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001631
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001632 def test_extending2(self):
1633 class Shade(Enum):
1634 def shade(self):
1635 print(self.name)
1636 class Color(Shade):
1637 red = 1
1638 green = 2
1639 blue = 3
1640 with self.assertRaises(TypeError):
1641 class MoreColor(Color):
1642 cyan = 4
1643 magenta = 5
1644 yellow = 6
1645
1646 def test_extending3(self):
1647 class Shade(Enum):
1648 def shade(self):
1649 return self.name
1650 class Color(Shade):
1651 def hex(self):
1652 return '%s hexlified!' % self.value
1653 class MoreColor(Color):
1654 cyan = 4
1655 magenta = 5
1656 yellow = 6
1657 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1658
orlnub1230fb9fad2018-09-12 20:28:53 +03001659 def test_subclass_duplicate_name(self):
1660 class Base(Enum):
1661 def test(self):
1662 pass
1663 class Test(Base):
1664 test = 1
1665 self.assertIs(type(Test.test), Test)
1666
1667 def test_subclass_duplicate_name_dynamic(self):
1668 from types import DynamicClassAttribute
1669 class Base(Enum):
1670 @DynamicClassAttribute
1671 def test(self):
1672 return 'dynamic'
1673 class Test(Base):
1674 test = 1
1675 self.assertEqual(Test.test.test, 'dynamic')
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001676
1677 def test_no_duplicates(self):
1678 class UniqueEnum(Enum):
1679 def __init__(self, *args):
1680 cls = self.__class__
1681 if any(self.value == e.value for e in cls):
1682 a = self.name
1683 e = cls(self.value).name
1684 raise ValueError(
1685 "aliases not allowed in UniqueEnum: %r --> %r"
1686 % (a, e)
1687 )
1688 class Color(UniqueEnum):
1689 red = 1
1690 green = 2
1691 blue = 3
1692 with self.assertRaises(ValueError):
1693 class Color(UniqueEnum):
1694 red = 1
1695 green = 2
1696 blue = 3
1697 grene = 2
1698
1699 def test_init(self):
1700 class Planet(Enum):
1701 MERCURY = (3.303e+23, 2.4397e6)
1702 VENUS = (4.869e+24, 6.0518e6)
1703 EARTH = (5.976e+24, 6.37814e6)
1704 MARS = (6.421e+23, 3.3972e6)
1705 JUPITER = (1.9e+27, 7.1492e7)
1706 SATURN = (5.688e+26, 6.0268e7)
1707 URANUS = (8.686e+25, 2.5559e7)
1708 NEPTUNE = (1.024e+26, 2.4746e7)
1709 def __init__(self, mass, radius):
1710 self.mass = mass # in kilograms
1711 self.radius = radius # in meters
1712 @property
1713 def surface_gravity(self):
1714 # universal gravitational constant (m3 kg-1 s-2)
1715 G = 6.67300E-11
1716 return G * self.mass / (self.radius * self.radius)
1717 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1718 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1719
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001720 def test_ignore(self):
1721 class Period(timedelta, Enum):
1722 '''
1723 different lengths of time
1724 '''
1725 def __new__(cls, value, period):
1726 obj = timedelta.__new__(cls, value)
1727 obj._value_ = value
1728 obj.period = period
1729 return obj
1730 _ignore_ = 'Period i'
1731 Period = vars()
1732 for i in range(13):
1733 Period['month_%d' % i] = i*30, 'month'
1734 for i in range(53):
1735 Period['week_%d' % i] = i*7, 'week'
1736 for i in range(32):
1737 Period['day_%d' % i] = i, 'day'
1738 OneDay = day_1
1739 OneWeek = week_1
1740 OneMonth = month_1
1741 self.assertFalse(hasattr(Period, '_ignore_'))
1742 self.assertFalse(hasattr(Period, 'Period'))
1743 self.assertFalse(hasattr(Period, 'i'))
1744 self.assertTrue(isinstance(Period.day_1, timedelta))
1745 self.assertTrue(Period.month_1 is Period.day_30)
1746 self.assertTrue(Period.week_4 is Period.day_28)
1747
Ethan Furman2aa27322013-07-19 19:35:56 -07001748 def test_nonhash_value(self):
1749 class AutoNumberInAList(Enum):
1750 def __new__(cls):
1751 value = [len(cls.__members__) + 1]
1752 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001753 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001754 return obj
1755 class ColorInAList(AutoNumberInAList):
1756 red = ()
1757 green = ()
1758 blue = ()
1759 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001760 for enum, value in zip(ColorInAList, range(3)):
1761 value += 1
1762 self.assertEqual(enum.value, [value])
1763 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001764
Ethan Furmanb41803e2013-07-25 13:50:45 -07001765 def test_conflicting_types_resolved_in_new(self):
1766 class LabelledIntEnum(int, Enum):
1767 def __new__(cls, *args):
1768 value, label = args
1769 obj = int.__new__(cls, value)
1770 obj.label = label
1771 obj._value_ = value
1772 return obj
1773
1774 class LabelledList(LabelledIntEnum):
1775 unprocessed = (1, "Unprocessed")
1776 payment_complete = (2, "Payment Complete")
1777
1778 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1779 self.assertEqual(LabelledList.unprocessed, 1)
1780 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001781
Ethan Furmanc16595e2016-09-10 23:36:59 -07001782 def test_auto_number(self):
1783 class Color(Enum):
1784 red = auto()
1785 blue = auto()
1786 green = auto()
1787
1788 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1789 self.assertEqual(Color.red.value, 1)
1790 self.assertEqual(Color.blue.value, 2)
1791 self.assertEqual(Color.green.value, 3)
1792
1793 def test_auto_name(self):
1794 class Color(Enum):
1795 def _generate_next_value_(name, start, count, last):
1796 return name
1797 red = auto()
1798 blue = auto()
1799 green = auto()
1800
1801 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1802 self.assertEqual(Color.red.value, 'red')
1803 self.assertEqual(Color.blue.value, 'blue')
1804 self.assertEqual(Color.green.value, 'green')
1805
1806 def test_auto_name_inherit(self):
1807 class AutoNameEnum(Enum):
1808 def _generate_next_value_(name, start, count, last):
1809 return name
1810 class Color(AutoNameEnum):
1811 red = auto()
1812 blue = auto()
1813 green = auto()
1814
1815 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1816 self.assertEqual(Color.red.value, 'red')
1817 self.assertEqual(Color.blue.value, 'blue')
1818 self.assertEqual(Color.green.value, 'green')
1819
1820 def test_auto_garbage(self):
1821 class Color(Enum):
1822 red = 'red'
1823 blue = auto()
1824 self.assertEqual(Color.blue.value, 1)
1825
1826 def test_auto_garbage_corrected(self):
1827 class Color(Enum):
1828 red = 'red'
1829 blue = 2
1830 green = auto()
1831
1832 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1833 self.assertEqual(Color.red.value, 'red')
1834 self.assertEqual(Color.blue.value, 2)
1835 self.assertEqual(Color.green.value, 3)
1836
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001837 def test_auto_order(self):
1838 with self.assertRaises(TypeError):
1839 class Color(Enum):
1840 red = auto()
1841 green = auto()
1842 blue = auto()
1843 def _generate_next_value_(name, start, count, last):
1844 return name
1845
Ethan Furmanfc23a942020-09-16 12:37:54 -07001846 def test_auto_order_wierd(self):
1847 weird_auto = auto()
1848 weird_auto.value = 'pathological case'
1849 class Color(Enum):
1850 red = weird_auto
1851 def _generate_next_value_(name, start, count, last):
1852 return name
1853 blue = auto()
1854 self.assertEqual(list(Color), [Color.red, Color.blue])
1855 self.assertEqual(Color.red.value, 'pathological case')
1856 self.assertEqual(Color.blue.value, 'blue')
Ethan Onstottd9a43e22020-04-28 13:20:55 -04001857
Ethan Furman3515dcc2016-09-18 13:15:41 -07001858 def test_duplicate_auto(self):
1859 class Dupes(Enum):
1860 first = primero = auto()
1861 second = auto()
1862 third = auto()
1863 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1864
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001865 def test_default_missing(self):
1866 class Color(Enum):
1867 RED = 1
1868 GREEN = 2
1869 BLUE = 3
1870 try:
1871 Color(7)
1872 except ValueError as exc:
1873 self.assertTrue(exc.__context__ is None)
1874 else:
1875 raise Exception('Exception not raised.')
1876
Ethan Furman019f0a02018-09-12 11:43:34 -07001877 def test_missing(self):
1878 class Color(Enum):
1879 red = 1
1880 green = 2
1881 blue = 3
1882 @classmethod
1883 def _missing_(cls, item):
1884 if item == 'three':
1885 return cls.blue
1886 elif item == 'bad return':
1887 # trigger internal error
1888 return 5
1889 elif item == 'error out':
1890 raise ZeroDivisionError
1891 else:
1892 # trigger not found
1893 return None
1894 self.assertIs(Color('three'), Color.blue)
Ethan Furmanc95ad7a2020-09-16 10:26:50 -07001895 try:
1896 Color(7)
1897 except ValueError as exc:
1898 self.assertTrue(exc.__context__ is None)
1899 else:
1900 raise Exception('Exception not raised.')
Ethan Furman019f0a02018-09-12 11:43:34 -07001901 try:
1902 Color('bad return')
1903 except TypeError as exc:
1904 self.assertTrue(isinstance(exc.__context__, ValueError))
1905 else:
1906 raise Exception('Exception not raised.')
1907 try:
1908 Color('error out')
1909 except ZeroDivisionError as exc:
1910 self.assertTrue(isinstance(exc.__context__, ValueError))
1911 else:
1912 raise Exception('Exception not raised.')
1913
Ethan Furman5bdab642018-09-21 19:03:09 -07001914 def test_multiple_mixin(self):
1915 class MaxMixin:
1916 @classproperty
1917 def MAX(cls):
1918 max = len(cls)
1919 cls.MAX = max
1920 return max
1921 class StrMixin:
1922 def __str__(self):
1923 return self._name_.lower()
1924 class SomeEnum(Enum):
1925 def behavior(self):
1926 return 'booyah'
1927 class AnotherEnum(Enum):
1928 def behavior(self):
1929 return 'nuhuh!'
1930 def social(self):
1931 return "what's up?"
1932 class Color(MaxMixin, Enum):
1933 RED = auto()
1934 GREEN = auto()
1935 BLUE = auto()
1936 self.assertEqual(Color.RED.value, 1)
1937 self.assertEqual(Color.GREEN.value, 2)
1938 self.assertEqual(Color.BLUE.value, 3)
1939 self.assertEqual(Color.MAX, 3)
1940 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
1941 class Color(MaxMixin, StrMixin, Enum):
1942 RED = auto()
1943 GREEN = auto()
1944 BLUE = auto()
1945 self.assertEqual(Color.RED.value, 1)
1946 self.assertEqual(Color.GREEN.value, 2)
1947 self.assertEqual(Color.BLUE.value, 3)
1948 self.assertEqual(Color.MAX, 3)
1949 self.assertEqual(str(Color.BLUE), 'blue')
1950 class Color(StrMixin, MaxMixin, Enum):
1951 RED = auto()
1952 GREEN = auto()
1953 BLUE = auto()
1954 self.assertEqual(Color.RED.value, 1)
1955 self.assertEqual(Color.GREEN.value, 2)
1956 self.assertEqual(Color.BLUE.value, 3)
1957 self.assertEqual(Color.MAX, 3)
1958 self.assertEqual(str(Color.BLUE), 'blue')
1959 class CoolColor(StrMixin, SomeEnum, Enum):
1960 RED = auto()
1961 GREEN = auto()
1962 BLUE = auto()
1963 self.assertEqual(CoolColor.RED.value, 1)
1964 self.assertEqual(CoolColor.GREEN.value, 2)
1965 self.assertEqual(CoolColor.BLUE.value, 3)
1966 self.assertEqual(str(CoolColor.BLUE), 'blue')
1967 self.assertEqual(CoolColor.RED.behavior(), 'booyah')
1968 class CoolerColor(StrMixin, AnotherEnum, Enum):
1969 RED = auto()
1970 GREEN = auto()
1971 BLUE = auto()
1972 self.assertEqual(CoolerColor.RED.value, 1)
1973 self.assertEqual(CoolerColor.GREEN.value, 2)
1974 self.assertEqual(CoolerColor.BLUE.value, 3)
1975 self.assertEqual(str(CoolerColor.BLUE), 'blue')
1976 self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
1977 self.assertEqual(CoolerColor.RED.social(), "what's up?")
1978 class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
1979 RED = auto()
1980 GREEN = auto()
1981 BLUE = auto()
1982 self.assertEqual(CoolestColor.RED.value, 1)
1983 self.assertEqual(CoolestColor.GREEN.value, 2)
1984 self.assertEqual(CoolestColor.BLUE.value, 3)
1985 self.assertEqual(str(CoolestColor.BLUE), 'blue')
1986 self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
1987 self.assertEqual(CoolestColor.RED.social(), "what's up?")
1988 class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
1989 RED = auto()
1990 GREEN = auto()
1991 BLUE = auto()
1992 self.assertEqual(ConfusedColor.RED.value, 1)
1993 self.assertEqual(ConfusedColor.GREEN.value, 2)
1994 self.assertEqual(ConfusedColor.BLUE.value, 3)
1995 self.assertEqual(str(ConfusedColor.BLUE), 'blue')
1996 self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
1997 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
1998 class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
1999 RED = auto()
2000 GREEN = auto()
2001 BLUE = auto()
2002 self.assertEqual(ReformedColor.RED.value, 1)
2003 self.assertEqual(ReformedColor.GREEN.value, 2)
2004 self.assertEqual(ReformedColor.BLUE.value, 3)
2005 self.assertEqual(str(ReformedColor.BLUE), 'blue')
2006 self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
2007 self.assertEqual(ConfusedColor.RED.social(), "what's up?")
2008 self.assertTrue(issubclass(ReformedColor, int))
2009
Ethan Furmancd453852018-10-05 23:29:36 -07002010 def test_multiple_inherited_mixin(self):
Ethan Furmancd453852018-10-05 23:29:36 -07002011 @unique
2012 class Decision1(StrEnum):
2013 REVERT = "REVERT"
2014 REVERT_ALL = "REVERT_ALL"
2015 RETRY = "RETRY"
2016 class MyEnum(StrEnum):
2017 pass
2018 @unique
2019 class Decision2(MyEnum):
2020 REVERT = "REVERT"
2021 REVERT_ALL = "REVERT_ALL"
2022 RETRY = "RETRY"
2023
Ethan Furmanc2667362020-12-07 00:17:31 -08002024 def test_multiple_mixin_inherited(self):
2025 class MyInt(int):
2026 def __new__(cls, value):
2027 return super().__new__(cls, value)
2028
2029 class HexMixin:
2030 def __repr__(self):
2031 return hex(self)
2032
2033 class MyIntEnum(HexMixin, MyInt, enum.Enum):
2034 pass
2035
2036 class Foo(MyIntEnum):
2037 TEST = 1
2038 self.assertTrue(isinstance(Foo.TEST, MyInt))
2039 self.assertEqual(repr(Foo.TEST), "0x1")
2040
2041 class Fee(MyIntEnum):
2042 TEST = 1
2043 def __new__(cls, value):
2044 value += 1
2045 member = int.__new__(cls, value)
2046 member._value_ = value
2047 return member
2048 self.assertEqual(Fee.TEST, 2)
2049
Rémi Lapeyre1fd06f12019-01-24 20:43:13 +01002050 def test_empty_globals(self):
2051 # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
2052 # when using compile and exec because f_globals is empty
2053 code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
2054 code = compile(code, "<string>", "exec")
2055 global_ns = {}
2056 local_ls = {}
2057 exec(code, global_ns, local_ls)
2058
Ethan Furman0063ff42020-09-21 17:23:13 -07002059 def test_strenum(self):
2060 class GoodStrEnum(StrEnum):
2061 one = '1'
2062 two = '2'
2063 three = b'3', 'ascii'
2064 four = b'4', 'latin1', 'strict'
Ethan Furmand986d162020-09-22 13:00:07 -07002065 self.assertEqual(GoodStrEnum.one, '1')
2066 self.assertEqual(str(GoodStrEnum.one), '1')
2067 self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
2068 self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
2069 #
2070 class DumbMixin:
2071 def __str__(self):
2072 return "don't do this"
2073 class DumbStrEnum(DumbMixin, StrEnum):
2074 five = '5'
2075 six = '6'
2076 seven = '7'
2077 self.assertEqual(DumbStrEnum.seven, '7')
2078 self.assertEqual(str(DumbStrEnum.seven), "don't do this")
2079 #
2080 class EnumMixin(Enum):
2081 def hello(self):
2082 print('hello from %s' % (self, ))
2083 class HelloEnum(EnumMixin, StrEnum):
2084 eight = '8'
2085 self.assertEqual(HelloEnum.eight, '8')
2086 self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
2087 #
2088 class GoodbyeMixin:
2089 def goodbye(self):
2090 print('%s wishes you a fond farewell')
2091 class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
2092 nine = '9'
2093 self.assertEqual(GoodbyeEnum.nine, '9')
2094 self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
2095 #
Ethan Furman0063ff42020-09-21 17:23:13 -07002096 with self.assertRaisesRegex(TypeError, '1 is not a string'):
2097 class FirstFailedStrEnum(StrEnum):
2098 one = 1
2099 two = '2'
2100 with self.assertRaisesRegex(TypeError, "2 is not a string"):
2101 class SecondFailedStrEnum(StrEnum):
2102 one = '1'
2103 two = 2,
2104 three = '3'
2105 with self.assertRaisesRegex(TypeError, '2 is not a string'):
2106 class ThirdFailedStrEnum(StrEnum):
2107 one = '1'
2108 two = 2
2109 with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
2110 class ThirdFailedStrEnum(StrEnum):
2111 one = '1'
2112 two = b'2', sys.getdefaultencoding
2113 with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
2114 class ThirdFailedStrEnum(StrEnum):
2115 one = '1'
2116 two = b'2', 'ascii', 9
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002117
Ethan Furmane8e61272016-08-20 07:19:31 -07002118class TestOrder(unittest.TestCase):
2119
2120 def test_same_members(self):
2121 class Color(Enum):
2122 _order_ = 'red green blue'
2123 red = 1
2124 green = 2
2125 blue = 3
2126
2127 def test_same_members_with_aliases(self):
2128 class Color(Enum):
2129 _order_ = 'red green blue'
2130 red = 1
2131 green = 2
2132 blue = 3
2133 verde = green
2134
2135 def test_same_members_wrong_order(self):
2136 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2137 class Color(Enum):
2138 _order_ = 'red green blue'
2139 red = 1
2140 blue = 3
2141 green = 2
2142
2143 def test_order_has_extra_members(self):
2144 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2145 class Color(Enum):
2146 _order_ = 'red green blue purple'
2147 red = 1
2148 green = 2
2149 blue = 3
2150
2151 def test_order_has_extra_members_with_aliases(self):
2152 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2153 class Color(Enum):
2154 _order_ = 'red green blue purple'
2155 red = 1
2156 green = 2
2157 blue = 3
2158 verde = green
2159
2160 def test_enum_has_extra_members(self):
2161 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2162 class Color(Enum):
2163 _order_ = 'red green blue'
2164 red = 1
2165 green = 2
2166 blue = 3
2167 purple = 4
2168
2169 def test_enum_has_extra_members_with_aliases(self):
2170 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
2171 class Color(Enum):
2172 _order_ = 'red green blue'
2173 red = 1
2174 green = 2
2175 blue = 3
2176 purple = 4
2177 verde = green
2178
2179
Ethan Furman65a5a472016-09-01 23:55:19 -07002180class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002181 """Tests of the Flags."""
2182
Ethan Furman65a5a472016-09-01 23:55:19 -07002183 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002184 R, W, X = 4, 2, 1
2185
Ethan Furman65a5a472016-09-01 23:55:19 -07002186 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002187 RO = 0
2188 WO = 1
2189 RW = 2
2190 AC = 3
2191 CE = 1<<19
2192
Rahul Jha94306522018-09-10 23:51:04 +05302193 class Color(Flag):
2194 BLACK = 0
2195 RED = 1
2196 GREEN = 2
2197 BLUE = 4
2198 PURPLE = RED|BLUE
2199
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002200 def test_str(self):
2201 Perm = self.Perm
2202 self.assertEqual(str(Perm.R), 'Perm.R')
2203 self.assertEqual(str(Perm.W), 'Perm.W')
2204 self.assertEqual(str(Perm.X), 'Perm.X')
2205 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2206 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2207 self.assertEqual(str(Perm(0)), 'Perm.0')
2208 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2209 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2210 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2211 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
2212 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
2213 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2214
2215 Open = self.Open
2216 self.assertEqual(str(Open.RO), 'Open.RO')
2217 self.assertEqual(str(Open.WO), 'Open.WO')
2218 self.assertEqual(str(Open.AC), 'Open.AC')
2219 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2220 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002221 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002222 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2223 self.assertEqual(str(~Open.AC), 'Open.CE')
2224 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
2225 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2226
2227 def test_repr(self):
2228 Perm = self.Perm
2229 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2230 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2231 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2232 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2233 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002234 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002235 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
2236 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
2237 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
2238 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07002239 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002240 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
2241
2242 Open = self.Open
2243 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2244 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2245 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2246 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2247 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002248 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002249 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
2250 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
2251 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
2252 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
2253
2254 def test_or(self):
2255 Perm = self.Perm
2256 for i in Perm:
2257 for j in Perm:
2258 self.assertEqual((i | j), Perm(i.value | j.value))
2259 self.assertEqual((i | j).value, i.value | j.value)
2260 self.assertIs(type(i | j), Perm)
2261 for i in Perm:
2262 self.assertIs(i | i, i)
2263 Open = self.Open
2264 self.assertIs(Open.RO | Open.CE, Open.CE)
2265
2266 def test_and(self):
2267 Perm = self.Perm
2268 RW = Perm.R | Perm.W
2269 RX = Perm.R | Perm.X
2270 WX = Perm.W | Perm.X
2271 RWX = Perm.R | Perm.W | Perm.X
2272 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2273 for i in values:
2274 for j in values:
2275 self.assertEqual((i & j).value, i.value & j.value)
2276 self.assertIs(type(i & j), Perm)
2277 for i in Perm:
2278 self.assertIs(i & i, i)
2279 self.assertIs(i & RWX, i)
2280 self.assertIs(RWX & i, i)
2281 Open = self.Open
2282 self.assertIs(Open.RO & Open.CE, Open.RO)
2283
2284 def test_xor(self):
2285 Perm = self.Perm
2286 for i in Perm:
2287 for j in Perm:
2288 self.assertEqual((i ^ j).value, i.value ^ j.value)
2289 self.assertIs(type(i ^ j), Perm)
2290 for i in Perm:
2291 self.assertIs(i ^ Perm(0), i)
2292 self.assertIs(Perm(0) ^ i, i)
2293 Open = self.Open
2294 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2295 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2296
2297 def test_invert(self):
2298 Perm = self.Perm
2299 RW = Perm.R | Perm.W
2300 RX = Perm.R | Perm.X
2301 WX = Perm.W | Perm.X
2302 RWX = Perm.R | Perm.W | Perm.X
2303 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2304 for i in values:
2305 self.assertIs(type(~i), Perm)
2306 self.assertEqual(~~i, i)
2307 for i in Perm:
2308 self.assertIs(~~i, i)
2309 Open = self.Open
2310 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2311 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2312
Ethan Furman25d94bb2016-09-02 16:32:32 -07002313 def test_bool(self):
2314 Perm = self.Perm
2315 for f in Perm:
2316 self.assertTrue(f)
2317 Open = self.Open
2318 for f in Open:
2319 self.assertEqual(bool(f.value), bool(f))
2320
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002321 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002322 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002323 lst = list(Perm)
2324 self.assertEqual(len(lst), len(Perm))
2325 self.assertEqual(len(Perm), 3, Perm)
2326 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2327 for i, n in enumerate('R W X'.split()):
2328 v = 1<<i
2329 e = Perm(v)
2330 self.assertEqual(e.value, v)
2331 self.assertEqual(type(e.value), int)
2332 self.assertEqual(e.name, n)
2333 self.assertIn(e, Perm)
2334 self.assertIs(type(e), Perm)
2335
2336 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002337 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002338 lst = list(Perm)
2339 self.assertEqual(len(lst), len(Perm))
2340 self.assertEqual(len(Perm), 3, Perm)
2341 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2342 for i, n in enumerate('R W X'.split()):
2343 v = 8<<i
2344 e = Perm(v)
2345 self.assertEqual(e.value, v)
2346 self.assertEqual(type(e.value), int)
2347 self.assertEqual(e.name, n)
2348 self.assertIn(e, Perm)
2349 self.assertIs(type(e), Perm)
2350
2351 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002352 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002353 lst = list(Perm)
2354 self.assertEqual(len(lst), len(Perm))
2355 self.assertEqual(len(Perm), 3, Perm)
2356 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2357 for i, n in enumerate('R W X'.split()):
2358 v = 1<<i
2359 e = Perm(v)
2360 self.assertEqual(e.value, v)
2361 self.assertEqual(type(e.value), int)
2362 self.assertEqual(e.name, n)
2363 self.assertIn(e, Perm)
2364 self.assertIs(type(e), Perm)
2365
2366 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002367 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002368 lst = list(Perm)
2369 self.assertEqual(len(lst), len(Perm))
2370 self.assertEqual(len(Perm), 3, Perm)
2371 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2372 for i, n in enumerate('R W X'.split()):
2373 v = 1<<(2*i+1)
2374 e = Perm(v)
2375 self.assertEqual(e.value, v)
2376 self.assertEqual(type(e.value), int)
2377 self.assertEqual(e.name, n)
2378 self.assertIn(e, Perm)
2379 self.assertIs(type(e), Perm)
2380
2381 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002382 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002383 lst = list(Perm)
2384 self.assertEqual(len(lst), len(Perm))
2385 self.assertEqual(len(Perm), 3, Perm)
2386 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2387 for i, n in enumerate('R W X'.split()):
2388 v = 1<<(2*i+1)
2389 e = Perm(v)
2390 self.assertEqual(e.value, v)
2391 self.assertEqual(type(e.value), int)
2392 self.assertEqual(e.name, n)
2393 self.assertIn(e, Perm)
2394 self.assertIs(type(e), Perm)
2395
Ethan Furman65a5a472016-09-01 23:55:19 -07002396 def test_pickle(self):
2397 if isinstance(FlagStooges, Exception):
2398 raise FlagStooges
2399 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
2400 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002401
Rahul Jha94306522018-09-10 23:51:04 +05302402 def test_contains(self):
2403 Open = self.Open
2404 Color = self.Color
2405 self.assertFalse(Color.BLACK in Open)
2406 self.assertFalse(Open.RO in Color)
2407 with self.assertRaises(TypeError):
2408 'BLACK' in Color
2409 with self.assertRaises(TypeError):
2410 'RO' in Open
2411 with self.assertRaises(TypeError):
2412 1 in Color
2413 with self.assertRaises(TypeError):
2414 1 in Open
2415
2416 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002417 Perm = self.Perm
2418 R, W, X = Perm
2419 RW = R | W
2420 RX = R | X
2421 WX = W | X
2422 RWX = R | W | X
2423 self.assertTrue(R in RW)
2424 self.assertTrue(R in RX)
2425 self.assertTrue(R in RWX)
2426 self.assertTrue(W in RW)
2427 self.assertTrue(W in WX)
2428 self.assertTrue(W in RWX)
2429 self.assertTrue(X in RX)
2430 self.assertTrue(X in WX)
2431 self.assertTrue(X in RWX)
2432 self.assertFalse(R in WX)
2433 self.assertFalse(W in RX)
2434 self.assertFalse(X in RW)
2435
Ethan Furman7219e272020-09-16 13:01:00 -07002436 def test_member_iter(self):
2437 Color = self.Color
2438 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2439 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2440 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2441
Ethan Furmanc16595e2016-09-10 23:36:59 -07002442 def test_auto_number(self):
2443 class Color(Flag):
2444 red = auto()
2445 blue = auto()
2446 green = auto()
2447
2448 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
2449 self.assertEqual(Color.red.value, 1)
2450 self.assertEqual(Color.blue.value, 2)
2451 self.assertEqual(Color.green.value, 4)
2452
2453 def test_auto_number_garbage(self):
2454 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
2455 class Color(Flag):
2456 red = 'not an int'
2457 blue = auto()
2458
Ethan Furman3515dcc2016-09-18 13:15:41 -07002459 def test_cascading_failure(self):
2460 class Bizarre(Flag):
2461 c = 3
2462 d = 4
2463 f = 6
2464 # Bizarre.c | Bizarre.d
Walter Dörwald323842c2019-07-18 20:37:13 +02002465 name = "TestFlag.test_cascading_failure.<locals>.Bizarre"
2466 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2467 self.assertRaisesRegex(ValueError, "5 is not a valid " + name, Bizarre, 5)
2468 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2469 self.assertRaisesRegex(ValueError, "2 is not a valid " + name, Bizarre, 2)
2470 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
2471 self.assertRaisesRegex(ValueError, "1 is not a valid " + name, Bizarre, 1)
Ethan Furman3515dcc2016-09-18 13:15:41 -07002472
2473 def test_duplicate_auto(self):
2474 class Dupes(Enum):
2475 first = primero = auto()
2476 second = auto()
2477 third = auto()
2478 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2479
2480 def test_bizarre(self):
2481 class Bizarre(Flag):
2482 b = 3
2483 c = 4
2484 d = 6
2485 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2486
Ethan Furman5bdab642018-09-21 19:03:09 -07002487 def test_multiple_mixin(self):
2488 class AllMixin:
2489 @classproperty
2490 def ALL(cls):
2491 members = list(cls)
2492 all_value = None
2493 if members:
2494 all_value = members[0]
2495 for member in members[1:]:
2496 all_value |= member
2497 cls.ALL = all_value
2498 return all_value
2499 class StrMixin:
2500 def __str__(self):
2501 return self._name_.lower()
2502 class Color(AllMixin, Flag):
2503 RED = auto()
2504 GREEN = auto()
2505 BLUE = auto()
2506 self.assertEqual(Color.RED.value, 1)
2507 self.assertEqual(Color.GREEN.value, 2)
2508 self.assertEqual(Color.BLUE.value, 4)
2509 self.assertEqual(Color.ALL.value, 7)
2510 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2511 class Color(AllMixin, StrMixin, Flag):
2512 RED = auto()
2513 GREEN = auto()
2514 BLUE = auto()
2515 self.assertEqual(Color.RED.value, 1)
2516 self.assertEqual(Color.GREEN.value, 2)
2517 self.assertEqual(Color.BLUE.value, 4)
2518 self.assertEqual(Color.ALL.value, 7)
2519 self.assertEqual(str(Color.BLUE), 'blue')
2520 class Color(StrMixin, AllMixin, Flag):
2521 RED = auto()
2522 GREEN = auto()
2523 BLUE = auto()
2524 self.assertEqual(Color.RED.value, 1)
2525 self.assertEqual(Color.GREEN.value, 2)
2526 self.assertEqual(Color.BLUE.value, 4)
2527 self.assertEqual(Color.ALL.value, 7)
2528 self.assertEqual(str(Color.BLUE), 'blue')
2529
Hai Shie80697d2020-05-28 06:10:27 +08002530 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002531 def test_unique_composite(self):
2532 # override __eq__ to be identity only
2533 class TestFlag(Flag):
2534 one = auto()
2535 two = auto()
2536 three = auto()
2537 four = auto()
2538 five = auto()
2539 six = auto()
2540 seven = auto()
2541 eight = auto()
2542 def __eq__(self, other):
2543 return self is other
2544 def __hash__(self):
2545 return hash(self._value_)
2546 # have multiple threads competing to complete the composite members
2547 seen = set()
2548 failed = False
2549 def cycle_enum():
2550 nonlocal failed
2551 try:
2552 for i in range(256):
2553 seen.add(TestFlag(i))
2554 except Exception:
2555 failed = True
2556 threads = [
2557 threading.Thread(target=cycle_enum)
2558 for _ in range(8)
2559 ]
Hai Shie80697d2020-05-28 06:10:27 +08002560 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002561 pass
2562 # check that only 248 members were created
2563 self.assertFalse(
2564 failed,
2565 'at least one thread failed while creating composite members')
2566 self.assertEqual(256, len(seen), 'too many composite members created')
2567
Ethan Furmanc16595e2016-09-10 23:36:59 -07002568
Ethan Furman65a5a472016-09-01 23:55:19 -07002569class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002570 """Tests of the IntFlags."""
2571
Ethan Furman65a5a472016-09-01 23:55:19 -07002572 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002573 X = 1 << 0
2574 W = 1 << 1
2575 R = 1 << 2
2576
Ethan Furman65a5a472016-09-01 23:55:19 -07002577 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002578 RO = 0
2579 WO = 1
2580 RW = 2
2581 AC = 3
2582 CE = 1<<19
2583
Rahul Jha94306522018-09-10 23:51:04 +05302584 class Color(IntFlag):
2585 BLACK = 0
2586 RED = 1
2587 GREEN = 2
2588 BLUE = 4
2589 PURPLE = RED|BLUE
2590
Ethan Furman3515dcc2016-09-18 13:15:41 -07002591 def test_type(self):
2592 Perm = self.Perm
2593 Open = self.Open
2594 for f in Perm:
2595 self.assertTrue(isinstance(f, Perm))
2596 self.assertEqual(f, f.value)
2597 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2598 self.assertEqual(Perm.W | Perm.X, 3)
2599 for f in Open:
2600 self.assertTrue(isinstance(f, Open))
2601 self.assertEqual(f, f.value)
2602 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2603 self.assertEqual(Open.WO | Open.RW, 3)
2604
2605
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002606 def test_str(self):
2607 Perm = self.Perm
2608 self.assertEqual(str(Perm.R), 'Perm.R')
2609 self.assertEqual(str(Perm.W), 'Perm.W')
2610 self.assertEqual(str(Perm.X), 'Perm.X')
2611 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2612 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2613 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2614 self.assertEqual(str(Perm(0)), 'Perm.0')
2615 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002616 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2617 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2618 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2619 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002620 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002621 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2622 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2623 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002624
2625 Open = self.Open
2626 self.assertEqual(str(Open.RO), 'Open.RO')
2627 self.assertEqual(str(Open.WO), 'Open.WO')
2628 self.assertEqual(str(Open.AC), 'Open.AC')
2629 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2630 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2631 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002632 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2633 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2634 self.assertEqual(str(~Open.AC), 'Open.CE')
2635 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2636 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2637 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002638
2639 def test_repr(self):
2640 Perm = self.Perm
2641 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2642 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2643 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2644 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2645 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2646 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002647 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2648 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002649 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2650 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2651 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2652 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002653 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002654 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2655 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2656 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002657
2658 Open = self.Open
2659 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2660 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2661 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2662 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2663 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002664 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002665 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2666 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2667 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2668 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2669 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2670 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002671
2672 def test_or(self):
2673 Perm = self.Perm
2674 for i in Perm:
2675 for j in Perm:
2676 self.assertEqual(i | j, i.value | j.value)
2677 self.assertEqual((i | j).value, i.value | j.value)
2678 self.assertIs(type(i | j), Perm)
2679 for j in range(8):
2680 self.assertEqual(i | j, i.value | j)
2681 self.assertEqual((i | j).value, i.value | j)
2682 self.assertIs(type(i | j), Perm)
2683 self.assertEqual(j | i, j | i.value)
2684 self.assertEqual((j | i).value, j | i.value)
2685 self.assertIs(type(j | i), Perm)
2686 for i in Perm:
2687 self.assertIs(i | i, i)
2688 self.assertIs(i | 0, i)
2689 self.assertIs(0 | i, i)
2690 Open = self.Open
2691 self.assertIs(Open.RO | Open.CE, Open.CE)
2692
2693 def test_and(self):
2694 Perm = self.Perm
2695 RW = Perm.R | Perm.W
2696 RX = Perm.R | Perm.X
2697 WX = Perm.W | Perm.X
2698 RWX = Perm.R | Perm.W | Perm.X
2699 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2700 for i in values:
2701 for j in values:
2702 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2703 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2704 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2705 for j in range(8):
2706 self.assertEqual(i & j, i.value & j)
2707 self.assertEqual((i & j).value, i.value & j)
2708 self.assertIs(type(i & j), Perm)
2709 self.assertEqual(j & i, j & i.value)
2710 self.assertEqual((j & i).value, j & i.value)
2711 self.assertIs(type(j & i), Perm)
2712 for i in Perm:
2713 self.assertIs(i & i, i)
2714 self.assertIs(i & 7, i)
2715 self.assertIs(7 & i, i)
2716 Open = self.Open
2717 self.assertIs(Open.RO & Open.CE, Open.RO)
2718
2719 def test_xor(self):
2720 Perm = self.Perm
2721 for i in Perm:
2722 for j in Perm:
2723 self.assertEqual(i ^ j, i.value ^ j.value)
2724 self.assertEqual((i ^ j).value, i.value ^ j.value)
2725 self.assertIs(type(i ^ j), Perm)
2726 for j in range(8):
2727 self.assertEqual(i ^ j, i.value ^ j)
2728 self.assertEqual((i ^ j).value, i.value ^ j)
2729 self.assertIs(type(i ^ j), Perm)
2730 self.assertEqual(j ^ i, j ^ i.value)
2731 self.assertEqual((j ^ i).value, j ^ i.value)
2732 self.assertIs(type(j ^ i), Perm)
2733 for i in Perm:
2734 self.assertIs(i ^ 0, i)
2735 self.assertIs(0 ^ i, i)
2736 Open = self.Open
2737 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2738 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2739
2740 def test_invert(self):
2741 Perm = self.Perm
2742 RW = Perm.R | Perm.W
2743 RX = Perm.R | Perm.X
2744 WX = Perm.W | Perm.X
2745 RWX = Perm.R | Perm.W | Perm.X
2746 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2747 for i in values:
2748 self.assertEqual(~i, ~i.value)
2749 self.assertEqual((~i).value, ~i.value)
2750 self.assertIs(type(~i), Perm)
2751 self.assertEqual(~~i, i)
2752 for i in Perm:
2753 self.assertIs(~~i, i)
2754 Open = self.Open
2755 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2756 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2757
2758 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002759 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002760 lst = list(Perm)
2761 self.assertEqual(len(lst), len(Perm))
2762 self.assertEqual(len(Perm), 3, Perm)
2763 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2764 for i, n in enumerate('R W X'.split()):
2765 v = 1<<i
2766 e = Perm(v)
2767 self.assertEqual(e.value, v)
2768 self.assertEqual(type(e.value), int)
2769 self.assertEqual(e, v)
2770 self.assertEqual(e.name, n)
2771 self.assertIn(e, Perm)
2772 self.assertIs(type(e), Perm)
2773
2774 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002775 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002776 lst = list(Perm)
2777 self.assertEqual(len(lst), len(Perm))
2778 self.assertEqual(len(Perm), 3, Perm)
2779 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2780 for i, n in enumerate('R W X'.split()):
2781 v = 8<<i
2782 e = Perm(v)
2783 self.assertEqual(e.value, v)
2784 self.assertEqual(type(e.value), int)
2785 self.assertEqual(e, v)
2786 self.assertEqual(e.name, n)
2787 self.assertIn(e, Perm)
2788 self.assertIs(type(e), Perm)
2789
2790 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002791 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002792 lst = list(Perm)
2793 self.assertEqual(len(lst), len(Perm))
2794 self.assertEqual(len(Perm), 3, Perm)
2795 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2796 for i, n in enumerate('R W X'.split()):
2797 v = 1<<i
2798 e = Perm(v)
2799 self.assertEqual(e.value, v)
2800 self.assertEqual(type(e.value), int)
2801 self.assertEqual(e, v)
2802 self.assertEqual(e.name, n)
2803 self.assertIn(e, Perm)
2804 self.assertIs(type(e), Perm)
2805
2806 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002807 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002808 lst = list(Perm)
2809 self.assertEqual(len(lst), len(Perm))
2810 self.assertEqual(len(Perm), 3, Perm)
2811 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2812 for i, n in enumerate('R W X'.split()):
2813 v = 1<<(2*i+1)
2814 e = Perm(v)
2815 self.assertEqual(e.value, v)
2816 self.assertEqual(type(e.value), int)
2817 self.assertEqual(e, v)
2818 self.assertEqual(e.name, n)
2819 self.assertIn(e, Perm)
2820 self.assertIs(type(e), Perm)
2821
2822 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002823 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002824 lst = list(Perm)
2825 self.assertEqual(len(lst), len(Perm))
2826 self.assertEqual(len(Perm), 3, Perm)
2827 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2828 for i, n in enumerate('R W X'.split()):
2829 v = 1<<(2*i+1)
2830 e = Perm(v)
2831 self.assertEqual(e.value, v)
2832 self.assertEqual(type(e.value), int)
2833 self.assertEqual(e, v)
2834 self.assertEqual(e.name, n)
2835 self.assertIn(e, Perm)
2836 self.assertIs(type(e), Perm)
2837
2838
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002839 def test_programatic_function_from_empty_list(self):
2840 Perm = enum.IntFlag('Perm', [])
2841 lst = list(Perm)
2842 self.assertEqual(len(lst), len(Perm))
2843 self.assertEqual(len(Perm), 0, Perm)
2844 Thing = enum.Enum('Thing', [])
2845 lst = list(Thing)
2846 self.assertEqual(len(lst), len(Thing))
2847 self.assertEqual(len(Thing), 0, Thing)
2848
2849
2850 def test_programatic_function_from_empty_tuple(self):
2851 Perm = enum.IntFlag('Perm', ())
2852 lst = list(Perm)
2853 self.assertEqual(len(lst), len(Perm))
2854 self.assertEqual(len(Perm), 0, Perm)
2855 Thing = enum.Enum('Thing', ())
2856 self.assertEqual(len(lst), len(Thing))
2857 self.assertEqual(len(Thing), 0, Thing)
2858
Rahul Jha94306522018-09-10 23:51:04 +05302859 def test_contains(self):
2860 Open = self.Open
2861 Color = self.Color
2862 self.assertTrue(Color.GREEN in Color)
2863 self.assertTrue(Open.RW in Open)
2864 self.assertFalse(Color.GREEN in Open)
2865 self.assertFalse(Open.RW in Color)
2866 with self.assertRaises(TypeError):
2867 'GREEN' in Color
2868 with self.assertRaises(TypeError):
2869 'RW' in Open
2870 with self.assertRaises(TypeError):
2871 2 in Color
2872 with self.assertRaises(TypeError):
2873 2 in Open
2874
2875 def test_member_contains(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002876 Perm = self.Perm
2877 R, W, X = Perm
2878 RW = R | W
2879 RX = R | X
2880 WX = W | X
2881 RWX = R | W | X
2882 self.assertTrue(R in RW)
2883 self.assertTrue(R in RX)
2884 self.assertTrue(R in RWX)
2885 self.assertTrue(W in RW)
2886 self.assertTrue(W in WX)
2887 self.assertTrue(W in RWX)
2888 self.assertTrue(X in RX)
2889 self.assertTrue(X in WX)
2890 self.assertTrue(X in RWX)
2891 self.assertFalse(R in WX)
2892 self.assertFalse(W in RX)
2893 self.assertFalse(X in RW)
Rahul Jha94306522018-09-10 23:51:04 +05302894 with self.assertRaises(TypeError):
2895 self.assertFalse('test' in RW)
Ethan Furman65a5a472016-09-01 23:55:19 -07002896
Ethan Furman7219e272020-09-16 13:01:00 -07002897 def test_member_iter(self):
2898 Color = self.Color
2899 self.assertEqual(list(Color.PURPLE), [Color.BLUE, Color.RED])
2900 self.assertEqual(list(Color.BLUE), [Color.BLUE])
2901 self.assertEqual(list(Color.GREEN), [Color.GREEN])
2902
Ethan Furman25d94bb2016-09-02 16:32:32 -07002903 def test_bool(self):
2904 Perm = self.Perm
2905 for f in Perm:
2906 self.assertTrue(f)
2907 Open = self.Open
2908 for f in Open:
2909 self.assertEqual(bool(f.value), bool(f))
2910
Ethan Furman5bdab642018-09-21 19:03:09 -07002911 def test_multiple_mixin(self):
2912 class AllMixin:
2913 @classproperty
2914 def ALL(cls):
2915 members = list(cls)
2916 all_value = None
2917 if members:
2918 all_value = members[0]
2919 for member in members[1:]:
2920 all_value |= member
2921 cls.ALL = all_value
2922 return all_value
2923 class StrMixin:
2924 def __str__(self):
2925 return self._name_.lower()
2926 class Color(AllMixin, IntFlag):
2927 RED = auto()
2928 GREEN = auto()
2929 BLUE = auto()
2930 self.assertEqual(Color.RED.value, 1)
2931 self.assertEqual(Color.GREEN.value, 2)
2932 self.assertEqual(Color.BLUE.value, 4)
2933 self.assertEqual(Color.ALL.value, 7)
2934 self.assertEqual(str(Color.BLUE), 'Color.BLUE')
2935 class Color(AllMixin, StrMixin, IntFlag):
2936 RED = auto()
2937 GREEN = auto()
2938 BLUE = auto()
2939 self.assertEqual(Color.RED.value, 1)
2940 self.assertEqual(Color.GREEN.value, 2)
2941 self.assertEqual(Color.BLUE.value, 4)
2942 self.assertEqual(Color.ALL.value, 7)
2943 self.assertEqual(str(Color.BLUE), 'blue')
2944 class Color(StrMixin, AllMixin, IntFlag):
2945 RED = auto()
2946 GREEN = auto()
2947 BLUE = auto()
2948 self.assertEqual(Color.RED.value, 1)
2949 self.assertEqual(Color.GREEN.value, 2)
2950 self.assertEqual(Color.BLUE.value, 4)
2951 self.assertEqual(Color.ALL.value, 7)
2952 self.assertEqual(str(Color.BLUE), 'blue')
2953
Hai Shie80697d2020-05-28 06:10:27 +08002954 @threading_helper.reap_threads
Ethan Furman28cf6632017-01-24 12:12:06 -08002955 def test_unique_composite(self):
2956 # override __eq__ to be identity only
2957 class TestFlag(IntFlag):
2958 one = auto()
2959 two = auto()
2960 three = auto()
2961 four = auto()
2962 five = auto()
2963 six = auto()
2964 seven = auto()
2965 eight = auto()
2966 def __eq__(self, other):
2967 return self is other
2968 def __hash__(self):
2969 return hash(self._value_)
2970 # have multiple threads competing to complete the composite members
2971 seen = set()
2972 failed = False
2973 def cycle_enum():
2974 nonlocal failed
2975 try:
2976 for i in range(256):
2977 seen.add(TestFlag(i))
2978 except Exception:
2979 failed = True
2980 threads = [
2981 threading.Thread(target=cycle_enum)
2982 for _ in range(8)
2983 ]
Hai Shie80697d2020-05-28 06:10:27 +08002984 with threading_helper.start_threads(threads):
Ethan Furman28cf6632017-01-24 12:12:06 -08002985 pass
2986 # check that only 248 members were created
2987 self.assertFalse(
2988 failed,
2989 'at least one thread failed while creating composite members')
2990 self.assertEqual(256, len(seen), 'too many composite members created')
2991
2992
Brennan D Baraban8b914d22019-03-03 14:09:11 -08002993class TestEmptyAndNonLatinStrings(unittest.TestCase):
2994
2995 def test_empty_string(self):
2996 with self.assertRaises(ValueError):
2997 empty_abc = Enum('empty_abc', ('', 'B', 'C'))
2998
2999 def test_non_latin_character_string(self):
3000 greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
3001 item = getattr(greek_abc, '\u03B1')
3002 self.assertEqual(item.value, 1)
3003
3004 def test_non_latin_number_string(self):
3005 hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
3006 item = getattr(hebrew_123, '\u05D0')
3007 self.assertEqual(item.value, 1)
3008
3009
Ethan Furmanf24bb352013-07-18 17:05:39 -07003010class TestUnique(unittest.TestCase):
3011
3012 def test_unique_clean(self):
3013 @unique
3014 class Clean(Enum):
3015 one = 1
3016 two = 'dos'
3017 tres = 4.0
3018 @unique
3019 class Cleaner(IntEnum):
3020 single = 1
3021 double = 2
3022 triple = 3
3023
3024 def test_unique_dirty(self):
3025 with self.assertRaisesRegex(ValueError, 'tres.*one'):
3026 @unique
3027 class Dirty(Enum):
3028 one = 1
3029 two = 'dos'
3030 tres = 1
3031 with self.assertRaisesRegex(
3032 ValueError,
3033 'double.*single.*turkey.*triple',
3034 ):
3035 @unique
3036 class Dirtier(IntEnum):
3037 single = 1
3038 double = 1
3039 triple = 3
3040 turkey = 3
3041
Ethan Furman3803ad42016-05-01 10:03:53 -07003042 def test_unique_with_name(self):
3043 @unique
3044 class Silly(Enum):
3045 one = 1
3046 two = 'dos'
3047 name = 3
3048 @unique
3049 class Sillier(IntEnum):
3050 single = 1
3051 name = 2
3052 triple = 3
3053 value = 4
3054
Ethan Furmanf24bb352013-07-18 17:05:39 -07003055
Ethan Furman5bdab642018-09-21 19:03:09 -07003056
Ethan Furman3323da92015-04-11 09:39:59 -07003057expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07003058Help on class Color in module %s:
3059
3060class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003061 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3062 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07003063 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03003064 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07003065 | Method resolution order:
3066 | Color
3067 | enum.Enum
3068 | builtins.object
3069 |\x20\x20
3070 | Data and other attributes defined here:
3071 |\x20\x20
3072 | blue = <Color.blue: 3>
3073 |\x20\x20
3074 | green = <Color.green: 2>
3075 |\x20\x20
3076 | red = <Color.red: 1>
3077 |\x20\x20
3078 | ----------------------------------------------------------------------
3079 | Data descriptors inherited from enum.Enum:
3080 |\x20\x20
3081 | name
3082 | The name of the Enum member.
3083 |\x20\x20
3084 | value
3085 | The value of the Enum member.
3086 |\x20\x20
3087 | ----------------------------------------------------------------------
Raymond Hettinger62be3382019-03-24 17:07:47 -07003088 | Readonly properties inherited from enum.EnumMeta:
Ethan Furman5875d742013-10-21 20:45:55 -07003089 |\x20\x20
3090 | __members__
3091 | Returns a mapping of member name->value.
3092 |\x20\x20\x20\x20\x20\x20
3093 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07003094 | is a read-only view of the internal mapping."""
3095
3096expected_help_output_without_docs = """\
3097Help on class Color in module %s:
3098
3099class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02003100 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
3101 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07003102 | Method resolution order:
3103 | Color
3104 | enum.Enum
3105 | builtins.object
3106 |\x20\x20
3107 | Data and other attributes defined here:
3108 |\x20\x20
3109 | blue = <Color.blue: 3>
3110 |\x20\x20
3111 | green = <Color.green: 2>
3112 |\x20\x20
3113 | red = <Color.red: 1>
3114 |\x20\x20
3115 | ----------------------------------------------------------------------
3116 | Data descriptors inherited from enum.Enum:
3117 |\x20\x20
3118 | name
3119 |\x20\x20
3120 | value
3121 |\x20\x20
3122 | ----------------------------------------------------------------------
3123 | Data descriptors inherited from enum.EnumMeta:
3124 |\x20\x20
3125 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07003126
3127class TestStdLib(unittest.TestCase):
3128
Ethan Furman48a724f2015-04-11 23:23:06 -07003129 maxDiff = None
3130
Ethan Furman5875d742013-10-21 20:45:55 -07003131 class Color(Enum):
3132 red = 1
3133 green = 2
3134 blue = 3
3135
3136 def test_pydoc(self):
3137 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07003138 if StrEnum.__doc__ is None:
3139 expected_text = expected_help_output_without_docs % __name__
3140 else:
3141 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07003142 output = StringIO()
3143 helper = pydoc.Helper(output=output)
3144 helper(self.Color)
3145 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02003146 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07003147
3148 def test_inspect_getmembers(self):
3149 values = dict((
3150 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07003151 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003152 ('__members__', self.Color.__members__),
3153 ('__module__', __name__),
3154 ('blue', self.Color.blue),
3155 ('green', self.Color.green),
3156 ('name', Enum.__dict__['name']),
3157 ('red', self.Color.red),
3158 ('value', Enum.__dict__['value']),
3159 ))
3160 result = dict(inspect.getmembers(self.Color))
3161 self.assertEqual(values.keys(), result.keys())
3162 failed = False
3163 for k in values.keys():
3164 if result[k] != values[k]:
3165 print()
3166 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
3167 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
3168 failed = True
3169 if failed:
3170 self.fail("result does not equal expected, see print above")
3171
3172 def test_inspect_classify_class_attrs(self):
3173 # indirectly test __objclass__
3174 from inspect import Attribute
3175 values = [
3176 Attribute(name='__class__', kind='data',
3177 defining_class=object, object=EnumMeta),
3178 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07003179 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07003180 Attribute(name='__members__', kind='property',
3181 defining_class=EnumMeta, object=EnumMeta.__members__),
3182 Attribute(name='__module__', kind='data',
3183 defining_class=self.Color, object=__name__),
3184 Attribute(name='blue', kind='data',
3185 defining_class=self.Color, object=self.Color.blue),
3186 Attribute(name='green', kind='data',
3187 defining_class=self.Color, object=self.Color.green),
3188 Attribute(name='red', kind='data',
3189 defining_class=self.Color, object=self.Color.red),
3190 Attribute(name='name', kind='data',
3191 defining_class=Enum, object=Enum.__dict__['name']),
3192 Attribute(name='value', kind='data',
3193 defining_class=Enum, object=Enum.__dict__['value']),
3194 ]
3195 values.sort(key=lambda item: item.name)
3196 result = list(inspect.classify_class_attrs(self.Color))
3197 result.sort(key=lambda item: item.name)
3198 failed = False
3199 for v, r in zip(values, result):
3200 if r != v:
3201 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
3202 failed = True
3203 if failed:
3204 self.fail("result does not equal expected, see print above")
3205
Martin Panter19e69c52015-11-14 12:46:42 +00003206
3207class MiscTestCase(unittest.TestCase):
3208 def test__all__(self):
3209 support.check__all__(self, enum)
3210
3211
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003212# These are unordered here on purpose to ensure that declaration order
3213# makes no difference.
3214CONVERT_TEST_NAME_D = 5
3215CONVERT_TEST_NAME_C = 5
3216CONVERT_TEST_NAME_B = 5
3217CONVERT_TEST_NAME_A = 5 # This one should sort first.
3218CONVERT_TEST_NAME_E = 5
3219CONVERT_TEST_NAME_F = 5
3220
3221class TestIntEnumConvert(unittest.TestCase):
3222 def test_convert_value_lookup_priority(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003223 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003224 'UnittestConvert',
3225 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003226 filter=lambda x: x.startswith('CONVERT_TEST_'))
3227 # We don't want the reverse lookup value to vary when there are
3228 # multiple possible names for a given value. It should always
3229 # report the first lexigraphical name in that case.
3230 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
3231
3232 def test_convert(self):
orlnub1230fb9fad2018-09-12 20:28:53 +03003233 test_type = enum.IntEnum._convert_(
Ethan Furman28cf6632017-01-24 12:12:06 -08003234 'UnittestConvert',
3235 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003236 filter=lambda x: x.startswith('CONVERT_TEST_'))
3237 # Ensure that test_type has all of the desired names and values.
3238 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
3239 test_type.CONVERT_TEST_NAME_A)
3240 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
3241 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
3242 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
3243 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
3244 # Ensure that test_type only picked up names matching the filter.
3245 self.assertEqual([name for name in dir(test_type)
3246 if name[0:2] not in ('CO', '__')],
3247 [], msg='Names other than CONVERT_TEST_* found.')
3248
orlnub1230fb9fad2018-09-12 20:28:53 +03003249 @unittest.skipUnless(sys.version_info[:2] == (3, 8),
3250 '_convert was deprecated in 3.8')
3251 def test_convert_warn(self):
3252 with self.assertWarns(DeprecationWarning):
3253 enum.IntEnum._convert(
3254 'UnittestConvert',
3255 ('test.test_enum', '__main__')[__name__=='__main__'],
3256 filter=lambda x: x.startswith('CONVERT_TEST_'))
3257
3258 @unittest.skipUnless(sys.version_info >= (3, 9),
3259 '_convert was removed in 3.9')
3260 def test_convert_raise(self):
3261 with self.assertRaises(AttributeError):
3262 enum.IntEnum._convert(
3263 'UnittestConvert',
3264 ('test.test_enum', '__main__')[__name__=='__main__'],
3265 filter=lambda x: x.startswith('CONVERT_TEST_'))
3266
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00003267
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003268if __name__ == '__main__':
3269 unittest.main()