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