blob: ea52de7a5f39c1dcf2075a854aa291ed9c513dc3 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004import unittest
5from collections import OrderedDict
Ethan Furmanc16595e2016-09-10 23:36:59 -07006from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07007from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -08008from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +00009from test import support
Ethan Furman28cf6632017-01-24 12:12:06 -080010try:
11 import threading
12except ImportError:
13 threading = None
14
Ethan Furman6b3d64a2013-06-14 16:55:46 -070015
16# for pickle tests
17try:
18 class Stooges(Enum):
19 LARRY = 1
20 CURLY = 2
21 MOE = 3
22except Exception as exc:
23 Stooges = exc
24
25try:
26 class IntStooges(int, Enum):
27 LARRY = 1
28 CURLY = 2
29 MOE = 3
30except Exception as exc:
31 IntStooges = exc
32
33try:
34 class FloatStooges(float, Enum):
35 LARRY = 1.39
36 CURLY = 2.72
37 MOE = 3.142596
38except Exception as exc:
39 FloatStooges = exc
40
Ethan Furman65a5a472016-09-01 23:55:19 -070041try:
42 class FlagStooges(Flag):
43 LARRY = 1
44 CURLY = 2
45 MOE = 3
46except Exception as exc:
47 FlagStooges = exc
48
Ethan Furman6b3d64a2013-06-14 16:55:46 -070049# for pickle test and subclass tests
50try:
51 class StrEnum(str, Enum):
52 'accepts only string values'
53 class Name(StrEnum):
54 BDFL = 'Guido van Rossum'
55 FLUFL = 'Barry Warsaw'
56except Exception as exc:
57 Name = exc
58
59try:
60 Question = Enum('Question', 'who what when where why', module=__name__)
61except Exception as exc:
62 Question = exc
63
64try:
65 Answer = Enum('Answer', 'him this then there because')
66except Exception as exc:
67 Answer = exc
68
Ethan Furmanca1b7942014-02-08 11:36:27 -080069try:
70 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
71except Exception as exc:
72 Theory = exc
73
Ethan Furman6b3d64a2013-06-14 16:55:46 -070074# for doctests
75try:
76 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080077 TOMATO = 1
78 BANANA = 2
79 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070080except Exception:
81 pass
82
Serhiy Storchakae50e7802015-03-31 16:56:49 +030083def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080084 if target is None:
85 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030086 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080087 assertion(loads(dumps(source, protocol=protocol)), target)
88
Serhiy Storchakae50e7802015-03-31 16:56:49 +030089def test_pickle_exception(assertion, exception, obj):
90 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080091 with assertion(exception):
92 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070093
94class TestHelpers(unittest.TestCase):
95 # _is_descriptor, _is_sunder, _is_dunder
96
97 def test_is_descriptor(self):
98 class foo:
99 pass
100 for attr in ('__get__','__set__','__delete__'):
101 obj = foo()
102 self.assertFalse(enum._is_descriptor(obj))
103 setattr(obj, attr, 1)
104 self.assertTrue(enum._is_descriptor(obj))
105
106 def test_is_sunder(self):
107 for s in ('_a_', '_aa_'):
108 self.assertTrue(enum._is_sunder(s))
109
110 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
111 '__', '___', '____', '_____',):
112 self.assertFalse(enum._is_sunder(s))
113
114 def test_is_dunder(self):
115 for s in ('__a__', '__aa__'):
116 self.assertTrue(enum._is_dunder(s))
117 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
118 '__', '___', '____', '_____',):
119 self.assertFalse(enum._is_dunder(s))
120
Ethan Furmanc16595e2016-09-10 23:36:59 -0700121# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700122
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700123class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800124
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700125 def setUp(self):
126 class Season(Enum):
127 SPRING = 1
128 SUMMER = 2
129 AUTUMN = 3
130 WINTER = 4
131 self.Season = Season
132
Ethan Furmanec15a822013-08-31 19:17:41 -0700133 class Konstants(float, Enum):
134 E = 2.7182818
135 PI = 3.1415926
136 TAU = 2 * PI
137 self.Konstants = Konstants
138
139 class Grades(IntEnum):
140 A = 5
141 B = 4
142 C = 3
143 D = 2
144 F = 0
145 self.Grades = Grades
146
147 class Directional(str, Enum):
148 EAST = 'east'
149 WEST = 'west'
150 NORTH = 'north'
151 SOUTH = 'south'
152 self.Directional = Directional
153
154 from datetime import date
155 class Holiday(date, Enum):
156 NEW_YEAR = 2013, 1, 1
157 IDES_OF_MARCH = 2013, 3, 15
158 self.Holiday = Holiday
159
Ethan Furman388a3922013-08-12 06:51:41 -0700160 def test_dir_on_class(self):
161 Season = self.Season
162 self.assertEqual(
163 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700164 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700165 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
166 )
167
168 def test_dir_on_item(self):
169 Season = self.Season
170 self.assertEqual(
171 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700172 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700173 )
174
Ethan Furmanc850f342013-09-15 16:59:35 -0700175 def test_dir_with_added_behavior(self):
176 class Test(Enum):
177 this = 'that'
178 these = 'those'
179 def wowser(self):
180 return ("Wowser! I'm %s!" % self.name)
181 self.assertEqual(
182 set(dir(Test)),
183 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
184 )
185 self.assertEqual(
186 set(dir(Test.this)),
187 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
188 )
189
Ethan Furman0ae550b2014-10-14 08:58:32 -0700190 def test_dir_on_sub_with_behavior_on_super(self):
191 # see issue22506
192 class SuperEnum(Enum):
193 def invisible(self):
194 return "did you see me?"
195 class SubEnum(SuperEnum):
196 sample = 5
197 self.assertEqual(
198 set(dir(SubEnum.sample)),
199 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
200 )
201
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700202 def test_enum_in_enum_out(self):
203 Season = self.Season
204 self.assertIs(Season(Season.WINTER), Season.WINTER)
205
206 def test_enum_value(self):
207 Season = self.Season
208 self.assertEqual(Season.SPRING.value, 1)
209
210 def test_intenum_value(self):
211 self.assertEqual(IntStooges.CURLY.value, 2)
212
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700213 def test_enum(self):
214 Season = self.Season
215 lst = list(Season)
216 self.assertEqual(len(lst), len(Season))
217 self.assertEqual(len(Season), 4, Season)
218 self.assertEqual(
219 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
220
221 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
222 e = Season(i)
223 self.assertEqual(e, getattr(Season, season))
224 self.assertEqual(e.value, i)
225 self.assertNotEqual(e, i)
226 self.assertEqual(e.name, season)
227 self.assertIn(e, Season)
228 self.assertIs(type(e), Season)
229 self.assertIsInstance(e, Season)
230 self.assertEqual(str(e), 'Season.' + season)
231 self.assertEqual(
232 repr(e),
233 '<Season.{0}: {1}>'.format(season, i),
234 )
235
236 def test_value_name(self):
237 Season = self.Season
238 self.assertEqual(Season.SPRING.name, 'SPRING')
239 self.assertEqual(Season.SPRING.value, 1)
240 with self.assertRaises(AttributeError):
241 Season.SPRING.name = 'invierno'
242 with self.assertRaises(AttributeError):
243 Season.SPRING.value = 2
244
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700245 def test_changing_member(self):
246 Season = self.Season
247 with self.assertRaises(AttributeError):
248 Season.WINTER = 'really cold'
249
Ethan Furman64a99722013-09-22 16:18:19 -0700250 def test_attribute_deletion(self):
251 class Season(Enum):
252 SPRING = 1
253 SUMMER = 2
254 AUTUMN = 3
255 WINTER = 4
256
257 def spam(cls):
258 pass
259
260 self.assertTrue(hasattr(Season, 'spam'))
261 del Season.spam
262 self.assertFalse(hasattr(Season, 'spam'))
263
264 with self.assertRaises(AttributeError):
265 del Season.SPRING
266 with self.assertRaises(AttributeError):
267 del Season.DRY
268 with self.assertRaises(AttributeError):
269 del Season.SPRING.name
270
Ethan Furman5de67b12016-04-13 23:52:09 -0700271 def test_bool_of_class(self):
272 class Empty(Enum):
273 pass
274 self.assertTrue(bool(Empty))
275
276 def test_bool_of_member(self):
277 class Count(Enum):
278 zero = 0
279 one = 1
280 two = 2
281 for member in Count:
282 self.assertTrue(bool(member))
283
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700284 def test_invalid_names(self):
285 with self.assertRaises(ValueError):
286 class Wrong(Enum):
287 mro = 9
288 with self.assertRaises(ValueError):
289 class Wrong(Enum):
290 _create_= 11
291 with self.assertRaises(ValueError):
292 class Wrong(Enum):
293 _get_mixins_ = 9
294 with self.assertRaises(ValueError):
295 class Wrong(Enum):
296 _find_new_ = 1
297 with self.assertRaises(ValueError):
298 class Wrong(Enum):
299 _any_name_ = 9
300
Ethan Furman6db1fd52015-09-17 21:49:12 -0700301 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800302 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700303 class Logic(Enum):
304 true = True
305 false = False
306 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800307 self.assertTrue(Logic.false)
308 # unless overridden
309 class RealLogic(Enum):
310 true = True
311 false = False
312 def __bool__(self):
313 return bool(self._value_)
314 self.assertTrue(RealLogic.true)
315 self.assertFalse(RealLogic.false)
316 # mixed Enums depend on mixed-in type
317 class IntLogic(int, Enum):
318 true = 1
319 false = 0
320 self.assertTrue(IntLogic.true)
321 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700322
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700323 def test_contains(self):
324 Season = self.Season
325 self.assertIn(Season.AUTUMN, Season)
326 self.assertNotIn(3, Season)
327
328 val = Season(3)
329 self.assertIn(val, Season)
330
331 class OtherEnum(Enum):
332 one = 1; two = 2
333 self.assertNotIn(OtherEnum.two, Season)
334
335 def test_comparisons(self):
336 Season = self.Season
337 with self.assertRaises(TypeError):
338 Season.SPRING < Season.WINTER
339 with self.assertRaises(TypeError):
340 Season.SPRING > 4
341
342 self.assertNotEqual(Season.SPRING, 1)
343
344 class Part(Enum):
345 SPRING = 1
346 CLIP = 2
347 BARREL = 3
348
349 self.assertNotEqual(Season.SPRING, Part.SPRING)
350 with self.assertRaises(TypeError):
351 Season.SPRING < Part.CLIP
352
353 def test_enum_duplicates(self):
354 class Season(Enum):
355 SPRING = 1
356 SUMMER = 2
357 AUTUMN = FALL = 3
358 WINTER = 4
359 ANOTHER_SPRING = 1
360 lst = list(Season)
361 self.assertEqual(
362 lst,
363 [Season.SPRING, Season.SUMMER,
364 Season.AUTUMN, Season.WINTER,
365 ])
366 self.assertIs(Season.FALL, Season.AUTUMN)
367 self.assertEqual(Season.FALL.value, 3)
368 self.assertEqual(Season.AUTUMN.value, 3)
369 self.assertIs(Season(3), Season.AUTUMN)
370 self.assertIs(Season(1), Season.SPRING)
371 self.assertEqual(Season.FALL.name, 'AUTUMN')
372 self.assertEqual(
373 [k for k,v in Season.__members__.items() if v.name != k],
374 ['FALL', 'ANOTHER_SPRING'],
375 )
376
Ethan Furman101e0742013-09-15 12:34:36 -0700377 def test_duplicate_name(self):
378 with self.assertRaises(TypeError):
379 class Color(Enum):
380 red = 1
381 green = 2
382 blue = 3
383 red = 4
384
385 with self.assertRaises(TypeError):
386 class Color(Enum):
387 red = 1
388 green = 2
389 blue = 3
390 def red(self):
391 return 'red'
392
393 with self.assertRaises(TypeError):
394 class Color(Enum):
395 @property
396 def red(self):
397 return 'redder'
398 red = 1
399 green = 2
400 blue = 3
401
402
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700403 def test_enum_with_value_name(self):
404 class Huh(Enum):
405 name = 1
406 value = 2
407 self.assertEqual(
408 list(Huh),
409 [Huh.name, Huh.value],
410 )
411 self.assertIs(type(Huh.name), Huh)
412 self.assertEqual(Huh.name.name, 'name')
413 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700414
415 def test_format_enum(self):
416 Season = self.Season
417 self.assertEqual('{}'.format(Season.SPRING),
418 '{}'.format(str(Season.SPRING)))
419 self.assertEqual( '{:}'.format(Season.SPRING),
420 '{:}'.format(str(Season.SPRING)))
421 self.assertEqual('{:20}'.format(Season.SPRING),
422 '{:20}'.format(str(Season.SPRING)))
423 self.assertEqual('{:^20}'.format(Season.SPRING),
424 '{:^20}'.format(str(Season.SPRING)))
425 self.assertEqual('{:>20}'.format(Season.SPRING),
426 '{:>20}'.format(str(Season.SPRING)))
427 self.assertEqual('{:<20}'.format(Season.SPRING),
428 '{:<20}'.format(str(Season.SPRING)))
429
430 def test_format_enum_custom(self):
431 class TestFloat(float, Enum):
432 one = 1.0
433 two = 2.0
434 def __format__(self, spec):
435 return 'TestFloat success!'
436 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
437
438 def assertFormatIsValue(self, spec, member):
439 self.assertEqual(spec.format(member), spec.format(member.value))
440
441 def test_format_enum_date(self):
442 Holiday = self.Holiday
443 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
444 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
445 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
446 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
447 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
448 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
449 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
450 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
451
452 def test_format_enum_float(self):
453 Konstants = self.Konstants
454 self.assertFormatIsValue('{}', Konstants.TAU)
455 self.assertFormatIsValue('{:}', Konstants.TAU)
456 self.assertFormatIsValue('{:20}', Konstants.TAU)
457 self.assertFormatIsValue('{:^20}', Konstants.TAU)
458 self.assertFormatIsValue('{:>20}', Konstants.TAU)
459 self.assertFormatIsValue('{:<20}', Konstants.TAU)
460 self.assertFormatIsValue('{:n}', Konstants.TAU)
461 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
462 self.assertFormatIsValue('{:f}', Konstants.TAU)
463
464 def test_format_enum_int(self):
465 Grades = self.Grades
466 self.assertFormatIsValue('{}', Grades.C)
467 self.assertFormatIsValue('{:}', Grades.C)
468 self.assertFormatIsValue('{:20}', Grades.C)
469 self.assertFormatIsValue('{:^20}', Grades.C)
470 self.assertFormatIsValue('{:>20}', Grades.C)
471 self.assertFormatIsValue('{:<20}', Grades.C)
472 self.assertFormatIsValue('{:+}', Grades.C)
473 self.assertFormatIsValue('{:08X}', Grades.C)
474 self.assertFormatIsValue('{:b}', Grades.C)
475
476 def test_format_enum_str(self):
477 Directional = self.Directional
478 self.assertFormatIsValue('{}', Directional.WEST)
479 self.assertFormatIsValue('{:}', Directional.WEST)
480 self.assertFormatIsValue('{:20}', Directional.WEST)
481 self.assertFormatIsValue('{:^20}', Directional.WEST)
482 self.assertFormatIsValue('{:>20}', Directional.WEST)
483 self.assertFormatIsValue('{:<20}', Directional.WEST)
484
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700485 def test_hash(self):
486 Season = self.Season
487 dates = {}
488 dates[Season.WINTER] = '1225'
489 dates[Season.SPRING] = '0315'
490 dates[Season.SUMMER] = '0704'
491 dates[Season.AUTUMN] = '1031'
492 self.assertEqual(dates[Season.AUTUMN], '1031')
493
494 def test_intenum_from_scratch(self):
495 class phy(int, Enum):
496 pi = 3
497 tau = 2 * pi
498 self.assertTrue(phy.pi < phy.tau)
499
500 def test_intenum_inherited(self):
501 class IntEnum(int, Enum):
502 pass
503 class phy(IntEnum):
504 pi = 3
505 tau = 2 * pi
506 self.assertTrue(phy.pi < phy.tau)
507
508 def test_floatenum_from_scratch(self):
509 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700510 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700511 tau = 2 * pi
512 self.assertTrue(phy.pi < phy.tau)
513
514 def test_floatenum_inherited(self):
515 class FloatEnum(float, Enum):
516 pass
517 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700518 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700519 tau = 2 * pi
520 self.assertTrue(phy.pi < phy.tau)
521
522 def test_strenum_from_scratch(self):
523 class phy(str, Enum):
524 pi = 'Pi'
525 tau = 'Tau'
526 self.assertTrue(phy.pi < phy.tau)
527
528 def test_strenum_inherited(self):
529 class StrEnum(str, Enum):
530 pass
531 class phy(StrEnum):
532 pi = 'Pi'
533 tau = 'Tau'
534 self.assertTrue(phy.pi < phy.tau)
535
536
537 def test_intenum(self):
538 class WeekDay(IntEnum):
539 SUNDAY = 1
540 MONDAY = 2
541 TUESDAY = 3
542 WEDNESDAY = 4
543 THURSDAY = 5
544 FRIDAY = 6
545 SATURDAY = 7
546
547 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
548 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
549
550 lst = list(WeekDay)
551 self.assertEqual(len(lst), len(WeekDay))
552 self.assertEqual(len(WeekDay), 7)
553 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
554 target = target.split()
555 for i, weekday in enumerate(target, 1):
556 e = WeekDay(i)
557 self.assertEqual(e, i)
558 self.assertEqual(int(e), i)
559 self.assertEqual(e.name, weekday)
560 self.assertIn(e, WeekDay)
561 self.assertEqual(lst.index(e)+1, i)
562 self.assertTrue(0 < e < 8)
563 self.assertIs(type(e), WeekDay)
564 self.assertIsInstance(e, int)
565 self.assertIsInstance(e, Enum)
566
567 def test_intenum_duplicates(self):
568 class WeekDay(IntEnum):
569 SUNDAY = 1
570 MONDAY = 2
571 TUESDAY = TEUSDAY = 3
572 WEDNESDAY = 4
573 THURSDAY = 5
574 FRIDAY = 6
575 SATURDAY = 7
576 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
577 self.assertEqual(WeekDay(3).name, 'TUESDAY')
578 self.assertEqual([k for k,v in WeekDay.__members__.items()
579 if v.name != k], ['TEUSDAY', ])
580
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300581 def test_intenum_from_bytes(self):
582 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
583 with self.assertRaises(ValueError):
584 IntStooges.from_bytes(b'\x00\x05', 'big')
585
586 def test_floatenum_fromhex(self):
587 h = float.hex(FloatStooges.MOE.value)
588 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
589 h = float.hex(FloatStooges.MOE.value + 0.01)
590 with self.assertRaises(ValueError):
591 FloatStooges.fromhex(h)
592
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700593 def test_pickle_enum(self):
594 if isinstance(Stooges, Exception):
595 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800596 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
597 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700598
599 def test_pickle_int(self):
600 if isinstance(IntStooges, Exception):
601 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800602 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
603 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700604
605 def test_pickle_float(self):
606 if isinstance(FloatStooges, Exception):
607 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800608 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
609 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700610
611 def test_pickle_enum_function(self):
612 if isinstance(Answer, Exception):
613 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800614 test_pickle_dump_load(self.assertIs, Answer.him)
615 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700616
617 def test_pickle_enum_function_with_module(self):
618 if isinstance(Question, Exception):
619 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800620 test_pickle_dump_load(self.assertIs, Question.who)
621 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700622
Ethan Furmanca1b7942014-02-08 11:36:27 -0800623 def test_enum_function_with_qualname(self):
624 if isinstance(Theory, Exception):
625 raise Theory
626 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
627
628 def test_class_nested_enum_and_pickle_protocol_four(self):
629 # would normally just have this directly in the class namespace
630 class NestedEnum(Enum):
631 twigs = 'common'
632 shiny = 'rare'
633
634 self.__class__.NestedEnum = NestedEnum
635 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300636 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800637
Ethan Furman24e837f2015-03-18 17:27:57 -0700638 def test_pickle_by_name(self):
639 class ReplaceGlobalInt(IntEnum):
640 ONE = 1
641 TWO = 2
642 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
643 for proto in range(HIGHEST_PROTOCOL):
644 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
645
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700646 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800647 BadPickle = Enum(
648 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700649 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800650 # now break BadPickle to test exception raising
651 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800652 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
653 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700654
655 def test_string_enum(self):
656 class SkillLevel(str, Enum):
657 master = 'what is the sound of one hand clapping?'
658 journeyman = 'why did the chicken cross the road?'
659 apprentice = 'knock, knock!'
660 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
661
662 def test_getattr_getitem(self):
663 class Period(Enum):
664 morning = 1
665 noon = 2
666 evening = 3
667 night = 4
668 self.assertIs(Period(2), Period.noon)
669 self.assertIs(getattr(Period, 'night'), Period.night)
670 self.assertIs(Period['morning'], Period.morning)
671
672 def test_getattr_dunder(self):
673 Season = self.Season
674 self.assertTrue(getattr(Season, '__eq__'))
675
676 def test_iteration_order(self):
677 class Season(Enum):
678 SUMMER = 2
679 WINTER = 4
680 AUTUMN = 3
681 SPRING = 1
682 self.assertEqual(
683 list(Season),
684 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
685 )
686
Ethan Furman2131a4a2013-09-14 18:11:24 -0700687 def test_reversed_iteration_order(self):
688 self.assertEqual(
689 list(reversed(self.Season)),
690 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
691 self.Season.SPRING]
692 )
693
Martin Pantereb995702016-07-28 01:11:04 +0000694 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700695 SummerMonth = Enum('SummerMonth', 'june july august')
696 lst = list(SummerMonth)
697 self.assertEqual(len(lst), len(SummerMonth))
698 self.assertEqual(len(SummerMonth), 3, SummerMonth)
699 self.assertEqual(
700 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
701 lst,
702 )
703 for i, month in enumerate('june july august'.split(), 1):
704 e = SummerMonth(i)
705 self.assertEqual(int(e.value), i)
706 self.assertNotEqual(e, i)
707 self.assertEqual(e.name, month)
708 self.assertIn(e, SummerMonth)
709 self.assertIs(type(e), SummerMonth)
710
Martin Pantereb995702016-07-28 01:11:04 +0000711 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700712 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
713 lst = list(SummerMonth)
714 self.assertEqual(len(lst), len(SummerMonth))
715 self.assertEqual(len(SummerMonth), 3, SummerMonth)
716 self.assertEqual(
717 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
718 lst,
719 )
720 for i, month in enumerate('june july august'.split(), 10):
721 e = SummerMonth(i)
722 self.assertEqual(int(e.value), i)
723 self.assertNotEqual(e, i)
724 self.assertEqual(e.name, month)
725 self.assertIn(e, SummerMonth)
726 self.assertIs(type(e), SummerMonth)
727
Martin Pantereb995702016-07-28 01:11:04 +0000728 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700729 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
730 lst = list(SummerMonth)
731 self.assertEqual(len(lst), len(SummerMonth))
732 self.assertEqual(len(SummerMonth), 3, SummerMonth)
733 self.assertEqual(
734 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
735 lst,
736 )
737 for i, month in enumerate('june july august'.split(), 1):
738 e = SummerMonth(i)
739 self.assertEqual(int(e.value), i)
740 self.assertNotEqual(e, i)
741 self.assertEqual(e.name, month)
742 self.assertIn(e, SummerMonth)
743 self.assertIs(type(e), SummerMonth)
744
Martin Pantereb995702016-07-28 01:11:04 +0000745 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700746 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
747 lst = list(SummerMonth)
748 self.assertEqual(len(lst), len(SummerMonth))
749 self.assertEqual(len(SummerMonth), 3, SummerMonth)
750 self.assertEqual(
751 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
752 lst,
753 )
754 for i, month in enumerate('june july august'.split(), 20):
755 e = SummerMonth(i)
756 self.assertEqual(int(e.value), i)
757 self.assertNotEqual(e, i)
758 self.assertEqual(e.name, month)
759 self.assertIn(e, SummerMonth)
760 self.assertIs(type(e), SummerMonth)
761
Martin Pantereb995702016-07-28 01:11:04 +0000762 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700763 SummerMonth = Enum(
764 'SummerMonth',
765 (('june', 1), ('july', 2), ('august', 3))
766 )
767 lst = list(SummerMonth)
768 self.assertEqual(len(lst), len(SummerMonth))
769 self.assertEqual(len(SummerMonth), 3, SummerMonth)
770 self.assertEqual(
771 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
772 lst,
773 )
774 for i, month in enumerate('june july august'.split(), 1):
775 e = SummerMonth(i)
776 self.assertEqual(int(e.value), i)
777 self.assertNotEqual(e, i)
778 self.assertEqual(e.name, month)
779 self.assertIn(e, SummerMonth)
780 self.assertIs(type(e), SummerMonth)
781
Martin Pantereb995702016-07-28 01:11:04 +0000782 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700783 SummerMonth = Enum(
784 'SummerMonth',
785 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
786 )
787 lst = list(SummerMonth)
788 self.assertEqual(len(lst), len(SummerMonth))
789 self.assertEqual(len(SummerMonth), 3, SummerMonth)
790 self.assertEqual(
791 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
792 lst,
793 )
794 for i, month in enumerate('june july august'.split(), 1):
795 e = SummerMonth(i)
796 self.assertEqual(int(e.value), i)
797 self.assertNotEqual(e, i)
798 self.assertEqual(e.name, month)
799 self.assertIn(e, SummerMonth)
800 self.assertIs(type(e), SummerMonth)
801
Martin Pantereb995702016-07-28 01:11:04 +0000802 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700803 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
804 lst = list(SummerMonth)
805 self.assertEqual(len(lst), len(SummerMonth))
806 self.assertEqual(len(SummerMonth), 3, SummerMonth)
807 self.assertEqual(
808 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
809 lst,
810 )
811 for i, month in enumerate('june july august'.split(), 1):
812 e = SummerMonth(i)
813 self.assertEqual(e, i)
814 self.assertEqual(e.name, month)
815 self.assertIn(e, SummerMonth)
816 self.assertIs(type(e), SummerMonth)
817
Martin Pantereb995702016-07-28 01:11:04 +0000818 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700819 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
820 lst = list(SummerMonth)
821 self.assertEqual(len(lst), len(SummerMonth))
822 self.assertEqual(len(SummerMonth), 3, SummerMonth)
823 self.assertEqual(
824 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
825 lst,
826 )
827 for i, month in enumerate('june july august'.split(), 30):
828 e = SummerMonth(i)
829 self.assertEqual(e, i)
830 self.assertEqual(e.name, month)
831 self.assertIn(e, SummerMonth)
832 self.assertIs(type(e), SummerMonth)
833
Martin Pantereb995702016-07-28 01:11:04 +0000834 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700835 SummerMonth = IntEnum('SummerMonth', 'june july august')
836 lst = list(SummerMonth)
837 self.assertEqual(len(lst), len(SummerMonth))
838 self.assertEqual(len(SummerMonth), 3, SummerMonth)
839 self.assertEqual(
840 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
841 lst,
842 )
843 for i, month in enumerate('june july august'.split(), 1):
844 e = SummerMonth(i)
845 self.assertEqual(e, i)
846 self.assertEqual(e.name, month)
847 self.assertIn(e, SummerMonth)
848 self.assertIs(type(e), SummerMonth)
849
Martin Pantereb995702016-07-28 01:11:04 +0000850 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700851 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
852 lst = list(SummerMonth)
853 self.assertEqual(len(lst), len(SummerMonth))
854 self.assertEqual(len(SummerMonth), 3, SummerMonth)
855 self.assertEqual(
856 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
857 lst,
858 )
859 for i, month in enumerate('june july august'.split(), 40):
860 e = SummerMonth(i)
861 self.assertEqual(e, i)
862 self.assertEqual(e.name, month)
863 self.assertIn(e, SummerMonth)
864 self.assertIs(type(e), SummerMonth)
865
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700866 def test_subclassing(self):
867 if isinstance(Name, Exception):
868 raise Name
869 self.assertEqual(Name.BDFL, 'Guido van Rossum')
870 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
871 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800872 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700873
874 def test_extending(self):
875 class Color(Enum):
876 red = 1
877 green = 2
878 blue = 3
879 with self.assertRaises(TypeError):
880 class MoreColor(Color):
881 cyan = 4
882 magenta = 5
883 yellow = 6
884
885 def test_exclude_methods(self):
886 class whatever(Enum):
887 this = 'that'
888 these = 'those'
889 def really(self):
890 return 'no, not %s' % self.value
891 self.assertIsNot(type(whatever.really), whatever)
892 self.assertEqual(whatever.this.really(), 'no, not that')
893
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700894 def test_wrong_inheritance_order(self):
895 with self.assertRaises(TypeError):
896 class Wrong(Enum, str):
897 NotHere = 'error before this point'
898
899 def test_intenum_transitivity(self):
900 class number(IntEnum):
901 one = 1
902 two = 2
903 three = 3
904 class numero(IntEnum):
905 uno = 1
906 dos = 2
907 tres = 3
908 self.assertEqual(number.one, numero.uno)
909 self.assertEqual(number.two, numero.dos)
910 self.assertEqual(number.three, numero.tres)
911
912 def test_wrong_enum_in_call(self):
913 class Monochrome(Enum):
914 black = 0
915 white = 1
916 class Gender(Enum):
917 male = 0
918 female = 1
919 self.assertRaises(ValueError, Monochrome, Gender.male)
920
921 def test_wrong_enum_in_mixed_call(self):
922 class Monochrome(IntEnum):
923 black = 0
924 white = 1
925 class Gender(Enum):
926 male = 0
927 female = 1
928 self.assertRaises(ValueError, Monochrome, Gender.male)
929
930 def test_mixed_enum_in_call_1(self):
931 class Monochrome(IntEnum):
932 black = 0
933 white = 1
934 class Gender(IntEnum):
935 male = 0
936 female = 1
937 self.assertIs(Monochrome(Gender.female), Monochrome.white)
938
939 def test_mixed_enum_in_call_2(self):
940 class Monochrome(Enum):
941 black = 0
942 white = 1
943 class Gender(IntEnum):
944 male = 0
945 female = 1
946 self.assertIs(Monochrome(Gender.male), Monochrome.black)
947
948 def test_flufl_enum(self):
949 class Fluflnum(Enum):
950 def __int__(self):
951 return int(self.value)
952 class MailManOptions(Fluflnum):
953 option1 = 1
954 option2 = 2
955 option3 = 3
956 self.assertEqual(int(MailManOptions.option1), 1)
957
Ethan Furman5e5a8232013-08-04 08:42:23 -0700958 def test_introspection(self):
959 class Number(IntEnum):
960 one = 100
961 two = 200
962 self.assertIs(Number.one._member_type_, int)
963 self.assertIs(Number._member_type_, int)
964 class String(str, Enum):
965 yarn = 'soft'
966 rope = 'rough'
967 wire = 'hard'
968 self.assertIs(String.yarn._member_type_, str)
969 self.assertIs(String._member_type_, str)
970 class Plain(Enum):
971 vanilla = 'white'
972 one = 1
973 self.assertIs(Plain.vanilla._member_type_, object)
974 self.assertIs(Plain._member_type_, object)
975
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700976 def test_no_such_enum_member(self):
977 class Color(Enum):
978 red = 1
979 green = 2
980 blue = 3
981 with self.assertRaises(ValueError):
982 Color(4)
983 with self.assertRaises(KeyError):
984 Color['chartreuse']
985
986 def test_new_repr(self):
987 class Color(Enum):
988 red = 1
989 green = 2
990 blue = 3
991 def __repr__(self):
992 return "don't you just love shades of %s?" % self.name
993 self.assertEqual(
994 repr(Color.blue),
995 "don't you just love shades of blue?",
996 )
997
998 def test_inherited_repr(self):
999 class MyEnum(Enum):
1000 def __repr__(self):
1001 return "My name is %s." % self.name
1002 class MyIntEnum(int, MyEnum):
1003 this = 1
1004 that = 2
1005 theother = 3
1006 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1007
1008 def test_multiple_mixin_mro(self):
1009 class auto_enum(type(Enum)):
1010 def __new__(metacls, cls, bases, classdict):
1011 temp = type(classdict)()
1012 names = set(classdict._member_names)
1013 i = 0
1014 for k in classdict._member_names:
1015 v = classdict[k]
1016 if v is Ellipsis:
1017 v = i
1018 else:
1019 i = v
1020 i += 1
1021 temp[k] = v
1022 for k, v in classdict.items():
1023 if k not in names:
1024 temp[k] = v
1025 return super(auto_enum, metacls).__new__(
1026 metacls, cls, bases, temp)
1027
1028 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1029 pass
1030
1031 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1032 pass
1033
1034 class TestAutoNumber(AutoNumberedEnum):
1035 a = ...
1036 b = 3
1037 c = ...
1038
1039 class TestAutoInt(AutoIntEnum):
1040 a = ...
1041 b = 3
1042 c = ...
1043
1044 def test_subclasses_with_getnewargs(self):
1045 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001046 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001047 def __new__(cls, *args):
1048 _args = args
1049 name, *args = args
1050 if len(args) == 0:
1051 raise TypeError("name and value must be specified")
1052 self = int.__new__(cls, *args)
1053 self._intname = name
1054 self._args = _args
1055 return self
1056 def __getnewargs__(self):
1057 return self._args
1058 @property
1059 def __name__(self):
1060 return self._intname
1061 def __repr__(self):
1062 # repr() is updated to include the name and type info
1063 return "{}({!r}, {})".format(type(self).__name__,
1064 self.__name__,
1065 int.__repr__(self))
1066 def __str__(self):
1067 # str() is unchanged, even if it relies on the repr() fallback
1068 base = int
1069 base_str = base.__str__
1070 if base_str.__objclass__ is object:
1071 return base.__repr__(self)
1072 return base_str(self)
1073 # for simplicity, we only define one operator that
1074 # propagates expressions
1075 def __add__(self, other):
1076 temp = int(self) + int( other)
1077 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1078 return NamedInt(
1079 '({0} + {1})'.format(self.__name__, other.__name__),
1080 temp )
1081 else:
1082 return temp
1083
1084 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001085 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001086 x = ('the-x', 1)
1087 y = ('the-y', 2)
1088
Ethan Furman2aa27322013-07-19 19:35:56 -07001089
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001090 self.assertIs(NEI.__new__, Enum.__new__)
1091 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1092 globals()['NamedInt'] = NamedInt
1093 globals()['NEI'] = NEI
1094 NI5 = NamedInt('test', 5)
1095 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001096 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001097 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001098 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001099 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001100
Ethan Furmanca1b7942014-02-08 11:36:27 -08001101 def test_subclasses_with_getnewargs_ex(self):
1102 class NamedInt(int):
1103 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1104 def __new__(cls, *args):
1105 _args = args
1106 name, *args = args
1107 if len(args) == 0:
1108 raise TypeError("name and value must be specified")
1109 self = int.__new__(cls, *args)
1110 self._intname = name
1111 self._args = _args
1112 return self
1113 def __getnewargs_ex__(self):
1114 return self._args, {}
1115 @property
1116 def __name__(self):
1117 return self._intname
1118 def __repr__(self):
1119 # repr() is updated to include the name and type info
1120 return "{}({!r}, {})".format(type(self).__name__,
1121 self.__name__,
1122 int.__repr__(self))
1123 def __str__(self):
1124 # str() is unchanged, even if it relies on the repr() fallback
1125 base = int
1126 base_str = base.__str__
1127 if base_str.__objclass__ is object:
1128 return base.__repr__(self)
1129 return base_str(self)
1130 # for simplicity, we only define one operator that
1131 # propagates expressions
1132 def __add__(self, other):
1133 temp = int(self) + int( other)
1134 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1135 return NamedInt(
1136 '({0} + {1})'.format(self.__name__, other.__name__),
1137 temp )
1138 else:
1139 return temp
1140
1141 class NEI(NamedInt, Enum):
1142 __qualname__ = 'NEI' # needed for pickle protocol 4
1143 x = ('the-x', 1)
1144 y = ('the-y', 2)
1145
1146
1147 self.assertIs(NEI.__new__, Enum.__new__)
1148 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1149 globals()['NamedInt'] = NamedInt
1150 globals()['NEI'] = NEI
1151 NI5 = NamedInt('test', 5)
1152 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001153 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001154 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001155 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001156 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001157
1158 def test_subclasses_with_reduce(self):
1159 class NamedInt(int):
1160 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1161 def __new__(cls, *args):
1162 _args = args
1163 name, *args = args
1164 if len(args) == 0:
1165 raise TypeError("name and value must be specified")
1166 self = int.__new__(cls, *args)
1167 self._intname = name
1168 self._args = _args
1169 return self
1170 def __reduce__(self):
1171 return self.__class__, self._args
1172 @property
1173 def __name__(self):
1174 return self._intname
1175 def __repr__(self):
1176 # repr() is updated to include the name and type info
1177 return "{}({!r}, {})".format(type(self).__name__,
1178 self.__name__,
1179 int.__repr__(self))
1180 def __str__(self):
1181 # str() is unchanged, even if it relies on the repr() fallback
1182 base = int
1183 base_str = base.__str__
1184 if base_str.__objclass__ is object:
1185 return base.__repr__(self)
1186 return base_str(self)
1187 # for simplicity, we only define one operator that
1188 # propagates expressions
1189 def __add__(self, other):
1190 temp = int(self) + int( other)
1191 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1192 return NamedInt(
1193 '({0} + {1})'.format(self.__name__, other.__name__),
1194 temp )
1195 else:
1196 return temp
1197
1198 class NEI(NamedInt, Enum):
1199 __qualname__ = 'NEI' # needed for pickle protocol 4
1200 x = ('the-x', 1)
1201 y = ('the-y', 2)
1202
1203
1204 self.assertIs(NEI.__new__, Enum.__new__)
1205 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1206 globals()['NamedInt'] = NamedInt
1207 globals()['NEI'] = NEI
1208 NI5 = NamedInt('test', 5)
1209 self.assertEqual(NI5, 5)
1210 test_pickle_dump_load(self.assertEqual, NI5, 5)
1211 self.assertEqual(NEI.y.value, 2)
1212 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001213 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001214
1215 def test_subclasses_with_reduce_ex(self):
1216 class NamedInt(int):
1217 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1218 def __new__(cls, *args):
1219 _args = args
1220 name, *args = args
1221 if len(args) == 0:
1222 raise TypeError("name and value must be specified")
1223 self = int.__new__(cls, *args)
1224 self._intname = name
1225 self._args = _args
1226 return self
1227 def __reduce_ex__(self, proto):
1228 return self.__class__, self._args
1229 @property
1230 def __name__(self):
1231 return self._intname
1232 def __repr__(self):
1233 # repr() is updated to include the name and type info
1234 return "{}({!r}, {})".format(type(self).__name__,
1235 self.__name__,
1236 int.__repr__(self))
1237 def __str__(self):
1238 # str() is unchanged, even if it relies on the repr() fallback
1239 base = int
1240 base_str = base.__str__
1241 if base_str.__objclass__ is object:
1242 return base.__repr__(self)
1243 return base_str(self)
1244 # for simplicity, we only define one operator that
1245 # propagates expressions
1246 def __add__(self, other):
1247 temp = int(self) + int( other)
1248 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1249 return NamedInt(
1250 '({0} + {1})'.format(self.__name__, other.__name__),
1251 temp )
1252 else:
1253 return temp
1254
1255 class NEI(NamedInt, Enum):
1256 __qualname__ = 'NEI' # needed for pickle protocol 4
1257 x = ('the-x', 1)
1258 y = ('the-y', 2)
1259
1260
1261 self.assertIs(NEI.__new__, Enum.__new__)
1262 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1263 globals()['NamedInt'] = NamedInt
1264 globals()['NEI'] = NEI
1265 NI5 = NamedInt('test', 5)
1266 self.assertEqual(NI5, 5)
1267 test_pickle_dump_load(self.assertEqual, NI5, 5)
1268 self.assertEqual(NEI.y.value, 2)
1269 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001270 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001271
Ethan Furmandc870522014-02-18 12:37:12 -08001272 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001273 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001274 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001275 def __new__(cls, *args):
1276 _args = args
1277 name, *args = args
1278 if len(args) == 0:
1279 raise TypeError("name and value must be specified")
1280 self = int.__new__(cls, *args)
1281 self._intname = name
1282 self._args = _args
1283 return self
1284 @property
1285 def __name__(self):
1286 return self._intname
1287 def __repr__(self):
1288 # repr() is updated to include the name and type info
1289 return "{}({!r}, {})".format(type(self).__name__,
1290 self.__name__,
1291 int.__repr__(self))
1292 def __str__(self):
1293 # str() is unchanged, even if it relies on the repr() fallback
1294 base = int
1295 base_str = base.__str__
1296 if base_str.__objclass__ is object:
1297 return base.__repr__(self)
1298 return base_str(self)
1299 # for simplicity, we only define one operator that
1300 # propagates expressions
1301 def __add__(self, other):
1302 temp = int(self) + int( other)
1303 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1304 return NamedInt(
1305 '({0} + {1})'.format(self.__name__, other.__name__),
1306 temp )
1307 else:
1308 return temp
1309
1310 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001311 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001312 x = ('the-x', 1)
1313 y = ('the-y', 2)
1314
1315 self.assertIs(NEI.__new__, Enum.__new__)
1316 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1317 globals()['NamedInt'] = NamedInt
1318 globals()['NEI'] = NEI
1319 NI5 = NamedInt('test', 5)
1320 self.assertEqual(NI5, 5)
1321 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001322 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1323 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001324
Ethan Furmandc870522014-02-18 12:37:12 -08001325 def test_subclasses_without_direct_pickle_support_using_name(self):
1326 class NamedInt(int):
1327 __qualname__ = 'NamedInt'
1328 def __new__(cls, *args):
1329 _args = args
1330 name, *args = args
1331 if len(args) == 0:
1332 raise TypeError("name and value must be specified")
1333 self = int.__new__(cls, *args)
1334 self._intname = name
1335 self._args = _args
1336 return self
1337 @property
1338 def __name__(self):
1339 return self._intname
1340 def __repr__(self):
1341 # repr() is updated to include the name and type info
1342 return "{}({!r}, {})".format(type(self).__name__,
1343 self.__name__,
1344 int.__repr__(self))
1345 def __str__(self):
1346 # str() is unchanged, even if it relies on the repr() fallback
1347 base = int
1348 base_str = base.__str__
1349 if base_str.__objclass__ is object:
1350 return base.__repr__(self)
1351 return base_str(self)
1352 # for simplicity, we only define one operator that
1353 # propagates expressions
1354 def __add__(self, other):
1355 temp = int(self) + int( other)
1356 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1357 return NamedInt(
1358 '({0} + {1})'.format(self.__name__, other.__name__),
1359 temp )
1360 else:
1361 return temp
1362
1363 class NEI(NamedInt, Enum):
1364 __qualname__ = 'NEI'
1365 x = ('the-x', 1)
1366 y = ('the-y', 2)
1367 def __reduce_ex__(self, proto):
1368 return getattr, (self.__class__, self._name_)
1369
1370 self.assertIs(NEI.__new__, Enum.__new__)
1371 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1372 globals()['NamedInt'] = NamedInt
1373 globals()['NEI'] = NEI
1374 NI5 = NamedInt('test', 5)
1375 self.assertEqual(NI5, 5)
1376 self.assertEqual(NEI.y.value, 2)
1377 test_pickle_dump_load(self.assertIs, NEI.y)
1378 test_pickle_dump_load(self.assertIs, NEI)
1379
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001380 def test_tuple_subclass(self):
1381 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001382 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001383 first = (1, 'for the money')
1384 second = (2, 'for the show')
1385 third = (3, 'for the music')
1386 self.assertIs(type(SomeTuple.first), SomeTuple)
1387 self.assertIsInstance(SomeTuple.second, tuple)
1388 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1389 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001390 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001391
1392 def test_duplicate_values_give_unique_enum_items(self):
1393 class AutoNumber(Enum):
1394 first = ()
1395 second = ()
1396 third = ()
1397 def __new__(cls):
1398 value = len(cls.__members__) + 1
1399 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001400 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001401 return obj
1402 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001403 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001404 self.assertEqual(
1405 list(AutoNumber),
1406 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1407 )
1408 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001409 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001410 self.assertIs(AutoNumber(1), AutoNumber.first)
1411
1412 def test_inherited_new_from_enhanced_enum(self):
1413 class AutoNumber(Enum):
1414 def __new__(cls):
1415 value = len(cls.__members__) + 1
1416 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001417 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001418 return obj
1419 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001420 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001421 class Color(AutoNumber):
1422 red = ()
1423 green = ()
1424 blue = ()
1425 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1426 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1427
1428 def test_inherited_new_from_mixed_enum(self):
1429 class AutoNumber(IntEnum):
1430 def __new__(cls):
1431 value = len(cls.__members__) + 1
1432 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001433 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001434 return obj
1435 class Color(AutoNumber):
1436 red = ()
1437 green = ()
1438 blue = ()
1439 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1440 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1441
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001442 def test_equality(self):
1443 class AlwaysEqual:
1444 def __eq__(self, other):
1445 return True
1446 class OrdinaryEnum(Enum):
1447 a = 1
1448 self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1449 self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1450
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001451 def test_ordered_mixin(self):
1452 class OrderedEnum(Enum):
1453 def __ge__(self, other):
1454 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001455 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001456 return NotImplemented
1457 def __gt__(self, other):
1458 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001459 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001460 return NotImplemented
1461 def __le__(self, other):
1462 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001463 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001464 return NotImplemented
1465 def __lt__(self, other):
1466 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001467 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001468 return NotImplemented
1469 class Grade(OrderedEnum):
1470 A = 5
1471 B = 4
1472 C = 3
1473 D = 2
1474 F = 1
1475 self.assertGreater(Grade.A, Grade.B)
1476 self.assertLessEqual(Grade.F, Grade.C)
1477 self.assertLess(Grade.D, Grade.A)
1478 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001479 self.assertEqual(Grade.B, Grade.B)
1480 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001481
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001482 def test_extending2(self):
1483 class Shade(Enum):
1484 def shade(self):
1485 print(self.name)
1486 class Color(Shade):
1487 red = 1
1488 green = 2
1489 blue = 3
1490 with self.assertRaises(TypeError):
1491 class MoreColor(Color):
1492 cyan = 4
1493 magenta = 5
1494 yellow = 6
1495
1496 def test_extending3(self):
1497 class Shade(Enum):
1498 def shade(self):
1499 return self.name
1500 class Color(Shade):
1501 def hex(self):
1502 return '%s hexlified!' % self.value
1503 class MoreColor(Color):
1504 cyan = 4
1505 magenta = 5
1506 yellow = 6
1507 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1508
1509
1510 def test_no_duplicates(self):
1511 class UniqueEnum(Enum):
1512 def __init__(self, *args):
1513 cls = self.__class__
1514 if any(self.value == e.value for e in cls):
1515 a = self.name
1516 e = cls(self.value).name
1517 raise ValueError(
1518 "aliases not allowed in UniqueEnum: %r --> %r"
1519 % (a, e)
1520 )
1521 class Color(UniqueEnum):
1522 red = 1
1523 green = 2
1524 blue = 3
1525 with self.assertRaises(ValueError):
1526 class Color(UniqueEnum):
1527 red = 1
1528 green = 2
1529 blue = 3
1530 grene = 2
1531
1532 def test_init(self):
1533 class Planet(Enum):
1534 MERCURY = (3.303e+23, 2.4397e6)
1535 VENUS = (4.869e+24, 6.0518e6)
1536 EARTH = (5.976e+24, 6.37814e6)
1537 MARS = (6.421e+23, 3.3972e6)
1538 JUPITER = (1.9e+27, 7.1492e7)
1539 SATURN = (5.688e+26, 6.0268e7)
1540 URANUS = (8.686e+25, 2.5559e7)
1541 NEPTUNE = (1.024e+26, 2.4746e7)
1542 def __init__(self, mass, radius):
1543 self.mass = mass # in kilograms
1544 self.radius = radius # in meters
1545 @property
1546 def surface_gravity(self):
1547 # universal gravitational constant (m3 kg-1 s-2)
1548 G = 6.67300E-11
1549 return G * self.mass / (self.radius * self.radius)
1550 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1551 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1552
Ethan Furman2aa27322013-07-19 19:35:56 -07001553 def test_nonhash_value(self):
1554 class AutoNumberInAList(Enum):
1555 def __new__(cls):
1556 value = [len(cls.__members__) + 1]
1557 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001558 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001559 return obj
1560 class ColorInAList(AutoNumberInAList):
1561 red = ()
1562 green = ()
1563 blue = ()
1564 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001565 for enum, value in zip(ColorInAList, range(3)):
1566 value += 1
1567 self.assertEqual(enum.value, [value])
1568 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001569
Ethan Furmanb41803e2013-07-25 13:50:45 -07001570 def test_conflicting_types_resolved_in_new(self):
1571 class LabelledIntEnum(int, Enum):
1572 def __new__(cls, *args):
1573 value, label = args
1574 obj = int.__new__(cls, value)
1575 obj.label = label
1576 obj._value_ = value
1577 return obj
1578
1579 class LabelledList(LabelledIntEnum):
1580 unprocessed = (1, "Unprocessed")
1581 payment_complete = (2, "Payment Complete")
1582
1583 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1584 self.assertEqual(LabelledList.unprocessed, 1)
1585 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001586
Ethan Furmanc16595e2016-09-10 23:36:59 -07001587 def test_auto_number(self):
1588 class Color(Enum):
1589 red = auto()
1590 blue = auto()
1591 green = auto()
1592
1593 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1594 self.assertEqual(Color.red.value, 1)
1595 self.assertEqual(Color.blue.value, 2)
1596 self.assertEqual(Color.green.value, 3)
1597
1598 def test_auto_name(self):
1599 class Color(Enum):
1600 def _generate_next_value_(name, start, count, last):
1601 return name
1602 red = auto()
1603 blue = auto()
1604 green = auto()
1605
1606 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1607 self.assertEqual(Color.red.value, 'red')
1608 self.assertEqual(Color.blue.value, 'blue')
1609 self.assertEqual(Color.green.value, 'green')
1610
1611 def test_auto_name_inherit(self):
1612 class AutoNameEnum(Enum):
1613 def _generate_next_value_(name, start, count, last):
1614 return name
1615 class Color(AutoNameEnum):
1616 red = auto()
1617 blue = auto()
1618 green = auto()
1619
1620 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1621 self.assertEqual(Color.red.value, 'red')
1622 self.assertEqual(Color.blue.value, 'blue')
1623 self.assertEqual(Color.green.value, 'green')
1624
1625 def test_auto_garbage(self):
1626 class Color(Enum):
1627 red = 'red'
1628 blue = auto()
1629 self.assertEqual(Color.blue.value, 1)
1630
1631 def test_auto_garbage_corrected(self):
1632 class Color(Enum):
1633 red = 'red'
1634 blue = 2
1635 green = auto()
1636
1637 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1638 self.assertEqual(Color.red.value, 'red')
1639 self.assertEqual(Color.blue.value, 2)
1640 self.assertEqual(Color.green.value, 3)
1641
Ethan Furman3515dcc2016-09-18 13:15:41 -07001642 def test_duplicate_auto(self):
1643 class Dupes(Enum):
1644 first = primero = auto()
1645 second = auto()
1646 third = auto()
1647 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1648
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001649
Ethan Furmane8e61272016-08-20 07:19:31 -07001650class TestOrder(unittest.TestCase):
1651
1652 def test_same_members(self):
1653 class Color(Enum):
1654 _order_ = 'red green blue'
1655 red = 1
1656 green = 2
1657 blue = 3
1658
1659 def test_same_members_with_aliases(self):
1660 class Color(Enum):
1661 _order_ = 'red green blue'
1662 red = 1
1663 green = 2
1664 blue = 3
1665 verde = green
1666
1667 def test_same_members_wrong_order(self):
1668 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1669 class Color(Enum):
1670 _order_ = 'red green blue'
1671 red = 1
1672 blue = 3
1673 green = 2
1674
1675 def test_order_has_extra_members(self):
1676 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1677 class Color(Enum):
1678 _order_ = 'red green blue purple'
1679 red = 1
1680 green = 2
1681 blue = 3
1682
1683 def test_order_has_extra_members_with_aliases(self):
1684 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1685 class Color(Enum):
1686 _order_ = 'red green blue purple'
1687 red = 1
1688 green = 2
1689 blue = 3
1690 verde = green
1691
1692 def test_enum_has_extra_members(self):
1693 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1694 class Color(Enum):
1695 _order_ = 'red green blue'
1696 red = 1
1697 green = 2
1698 blue = 3
1699 purple = 4
1700
1701 def test_enum_has_extra_members_with_aliases(self):
1702 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1703 class Color(Enum):
1704 _order_ = 'red green blue'
1705 red = 1
1706 green = 2
1707 blue = 3
1708 purple = 4
1709 verde = green
1710
1711
Ethan Furman65a5a472016-09-01 23:55:19 -07001712class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001713 """Tests of the Flags."""
1714
Ethan Furman65a5a472016-09-01 23:55:19 -07001715 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001716 R, W, X = 4, 2, 1
1717
Ethan Furman65a5a472016-09-01 23:55:19 -07001718 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001719 RO = 0
1720 WO = 1
1721 RW = 2
1722 AC = 3
1723 CE = 1<<19
1724
1725 def test_str(self):
1726 Perm = self.Perm
1727 self.assertEqual(str(Perm.R), 'Perm.R')
1728 self.assertEqual(str(Perm.W), 'Perm.W')
1729 self.assertEqual(str(Perm.X), 'Perm.X')
1730 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1731 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1732 self.assertEqual(str(Perm(0)), 'Perm.0')
1733 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1734 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1735 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1736 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1737 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1738 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1739
1740 Open = self.Open
1741 self.assertEqual(str(Open.RO), 'Open.RO')
1742 self.assertEqual(str(Open.WO), 'Open.WO')
1743 self.assertEqual(str(Open.AC), 'Open.AC')
1744 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1745 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001746 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001747 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1748 self.assertEqual(str(~Open.AC), 'Open.CE')
1749 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1750 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1751
1752 def test_repr(self):
1753 Perm = self.Perm
1754 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1755 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1756 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1757 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1758 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001759 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001760 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1761 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1762 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1763 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001764 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001765 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1766
1767 Open = self.Open
1768 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1769 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1770 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1771 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1772 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001773 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001774 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
1775 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
1776 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
1777 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
1778
1779 def test_or(self):
1780 Perm = self.Perm
1781 for i in Perm:
1782 for j in Perm:
1783 self.assertEqual((i | j), Perm(i.value | j.value))
1784 self.assertEqual((i | j).value, i.value | j.value)
1785 self.assertIs(type(i | j), Perm)
1786 for i in Perm:
1787 self.assertIs(i | i, i)
1788 Open = self.Open
1789 self.assertIs(Open.RO | Open.CE, Open.CE)
1790
1791 def test_and(self):
1792 Perm = self.Perm
1793 RW = Perm.R | Perm.W
1794 RX = Perm.R | Perm.X
1795 WX = Perm.W | Perm.X
1796 RWX = Perm.R | Perm.W | Perm.X
1797 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1798 for i in values:
1799 for j in values:
1800 self.assertEqual((i & j).value, i.value & j.value)
1801 self.assertIs(type(i & j), Perm)
1802 for i in Perm:
1803 self.assertIs(i & i, i)
1804 self.assertIs(i & RWX, i)
1805 self.assertIs(RWX & i, i)
1806 Open = self.Open
1807 self.assertIs(Open.RO & Open.CE, Open.RO)
1808
1809 def test_xor(self):
1810 Perm = self.Perm
1811 for i in Perm:
1812 for j in Perm:
1813 self.assertEqual((i ^ j).value, i.value ^ j.value)
1814 self.assertIs(type(i ^ j), Perm)
1815 for i in Perm:
1816 self.assertIs(i ^ Perm(0), i)
1817 self.assertIs(Perm(0) ^ i, i)
1818 Open = self.Open
1819 self.assertIs(Open.RO ^ Open.CE, Open.CE)
1820 self.assertIs(Open.CE ^ Open.CE, Open.RO)
1821
1822 def test_invert(self):
1823 Perm = self.Perm
1824 RW = Perm.R | Perm.W
1825 RX = Perm.R | Perm.X
1826 WX = Perm.W | Perm.X
1827 RWX = Perm.R | Perm.W | Perm.X
1828 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1829 for i in values:
1830 self.assertIs(type(~i), Perm)
1831 self.assertEqual(~~i, i)
1832 for i in Perm:
1833 self.assertIs(~~i, i)
1834 Open = self.Open
1835 self.assertIs(Open.WO & ~Open.WO, Open.RO)
1836 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
1837
Ethan Furman25d94bb2016-09-02 16:32:32 -07001838 def test_bool(self):
1839 Perm = self.Perm
1840 for f in Perm:
1841 self.assertTrue(f)
1842 Open = self.Open
1843 for f in Open:
1844 self.assertEqual(bool(f.value), bool(f))
1845
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001846 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001847 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001848 lst = list(Perm)
1849 self.assertEqual(len(lst), len(Perm))
1850 self.assertEqual(len(Perm), 3, Perm)
1851 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1852 for i, n in enumerate('R W X'.split()):
1853 v = 1<<i
1854 e = Perm(v)
1855 self.assertEqual(e.value, v)
1856 self.assertEqual(type(e.value), int)
1857 self.assertEqual(e.name, n)
1858 self.assertIn(e, Perm)
1859 self.assertIs(type(e), Perm)
1860
1861 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001862 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001863 lst = list(Perm)
1864 self.assertEqual(len(lst), len(Perm))
1865 self.assertEqual(len(Perm), 3, Perm)
1866 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1867 for i, n in enumerate('R W X'.split()):
1868 v = 8<<i
1869 e = Perm(v)
1870 self.assertEqual(e.value, v)
1871 self.assertEqual(type(e.value), int)
1872 self.assertEqual(e.name, n)
1873 self.assertIn(e, Perm)
1874 self.assertIs(type(e), Perm)
1875
1876 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001877 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001878 lst = list(Perm)
1879 self.assertEqual(len(lst), len(Perm))
1880 self.assertEqual(len(Perm), 3, Perm)
1881 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1882 for i, n in enumerate('R W X'.split()):
1883 v = 1<<i
1884 e = Perm(v)
1885 self.assertEqual(e.value, v)
1886 self.assertEqual(type(e.value), int)
1887 self.assertEqual(e.name, n)
1888 self.assertIn(e, Perm)
1889 self.assertIs(type(e), Perm)
1890
1891 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001892 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001893 lst = list(Perm)
1894 self.assertEqual(len(lst), len(Perm))
1895 self.assertEqual(len(Perm), 3, Perm)
1896 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1897 for i, n in enumerate('R W X'.split()):
1898 v = 1<<(2*i+1)
1899 e = Perm(v)
1900 self.assertEqual(e.value, v)
1901 self.assertEqual(type(e.value), int)
1902 self.assertEqual(e.name, n)
1903 self.assertIn(e, Perm)
1904 self.assertIs(type(e), Perm)
1905
1906 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001907 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001908 lst = list(Perm)
1909 self.assertEqual(len(lst), len(Perm))
1910 self.assertEqual(len(Perm), 3, Perm)
1911 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1912 for i, n in enumerate('R W X'.split()):
1913 v = 1<<(2*i+1)
1914 e = Perm(v)
1915 self.assertEqual(e.value, v)
1916 self.assertEqual(type(e.value), int)
1917 self.assertEqual(e.name, n)
1918 self.assertIn(e, Perm)
1919 self.assertIs(type(e), Perm)
1920
Ethan Furman65a5a472016-09-01 23:55:19 -07001921 def test_pickle(self):
1922 if isinstance(FlagStooges, Exception):
1923 raise FlagStooges
1924 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
1925 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001926
Ethan Furman65a5a472016-09-01 23:55:19 -07001927 def test_containment(self):
1928 Perm = self.Perm
1929 R, W, X = Perm
1930 RW = R | W
1931 RX = R | X
1932 WX = W | X
1933 RWX = R | W | X
1934 self.assertTrue(R in RW)
1935 self.assertTrue(R in RX)
1936 self.assertTrue(R in RWX)
1937 self.assertTrue(W in RW)
1938 self.assertTrue(W in WX)
1939 self.assertTrue(W in RWX)
1940 self.assertTrue(X in RX)
1941 self.assertTrue(X in WX)
1942 self.assertTrue(X in RWX)
1943 self.assertFalse(R in WX)
1944 self.assertFalse(W in RX)
1945 self.assertFalse(X in RW)
1946
Ethan Furmanc16595e2016-09-10 23:36:59 -07001947 def test_auto_number(self):
1948 class Color(Flag):
1949 red = auto()
1950 blue = auto()
1951 green = auto()
1952
1953 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1954 self.assertEqual(Color.red.value, 1)
1955 self.assertEqual(Color.blue.value, 2)
1956 self.assertEqual(Color.green.value, 4)
1957
1958 def test_auto_number_garbage(self):
1959 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
1960 class Color(Flag):
1961 red = 'not an int'
1962 blue = auto()
1963
Ethan Furman3515dcc2016-09-18 13:15:41 -07001964 def test_cascading_failure(self):
1965 class Bizarre(Flag):
1966 c = 3
1967 d = 4
1968 f = 6
1969 # Bizarre.c | Bizarre.d
1970 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
1971 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
1972 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
1973 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
1974 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
1975 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
1976
1977 def test_duplicate_auto(self):
1978 class Dupes(Enum):
1979 first = primero = auto()
1980 second = auto()
1981 third = auto()
1982 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1983
1984 def test_bizarre(self):
1985 class Bizarre(Flag):
1986 b = 3
1987 c = 4
1988 d = 6
1989 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
1990
Ethan Furman28cf6632017-01-24 12:12:06 -08001991 @unittest.skipUnless(threading, 'Threading required for this test.')
1992 @support.reap_threads
1993 def test_unique_composite(self):
1994 # override __eq__ to be identity only
1995 class TestFlag(Flag):
1996 one = auto()
1997 two = auto()
1998 three = auto()
1999 four = auto()
2000 five = auto()
2001 six = auto()
2002 seven = auto()
2003 eight = auto()
2004 def __eq__(self, other):
2005 return self is other
2006 def __hash__(self):
2007 return hash(self._value_)
2008 # have multiple threads competing to complete the composite members
2009 seen = set()
2010 failed = False
2011 def cycle_enum():
2012 nonlocal failed
2013 try:
2014 for i in range(256):
2015 seen.add(TestFlag(i))
2016 except Exception:
2017 failed = True
2018 threads = [
2019 threading.Thread(target=cycle_enum)
2020 for _ in range(8)
2021 ]
2022 with support.start_threads(threads):
2023 pass
2024 # check that only 248 members were created
2025 self.assertFalse(
2026 failed,
2027 'at least one thread failed while creating composite members')
2028 self.assertEqual(256, len(seen), 'too many composite members created')
2029
Ethan Furmanc16595e2016-09-10 23:36:59 -07002030
Ethan Furman65a5a472016-09-01 23:55:19 -07002031class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002032 """Tests of the IntFlags."""
2033
Ethan Furman65a5a472016-09-01 23:55:19 -07002034 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002035 X = 1 << 0
2036 W = 1 << 1
2037 R = 1 << 2
2038
Ethan Furman65a5a472016-09-01 23:55:19 -07002039 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002040 RO = 0
2041 WO = 1
2042 RW = 2
2043 AC = 3
2044 CE = 1<<19
2045
Ethan Furman3515dcc2016-09-18 13:15:41 -07002046 def test_type(self):
2047 Perm = self.Perm
2048 Open = self.Open
2049 for f in Perm:
2050 self.assertTrue(isinstance(f, Perm))
2051 self.assertEqual(f, f.value)
2052 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2053 self.assertEqual(Perm.W | Perm.X, 3)
2054 for f in Open:
2055 self.assertTrue(isinstance(f, Open))
2056 self.assertEqual(f, f.value)
2057 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2058 self.assertEqual(Open.WO | Open.RW, 3)
2059
2060
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002061 def test_str(self):
2062 Perm = self.Perm
2063 self.assertEqual(str(Perm.R), 'Perm.R')
2064 self.assertEqual(str(Perm.W), 'Perm.W')
2065 self.assertEqual(str(Perm.X), 'Perm.X')
2066 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2067 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2068 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2069 self.assertEqual(str(Perm(0)), 'Perm.0')
2070 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002071 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2072 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2073 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2074 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002075 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002076 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2077 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2078 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002079
2080 Open = self.Open
2081 self.assertEqual(str(Open.RO), 'Open.RO')
2082 self.assertEqual(str(Open.WO), 'Open.WO')
2083 self.assertEqual(str(Open.AC), 'Open.AC')
2084 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2085 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2086 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002087 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2088 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2089 self.assertEqual(str(~Open.AC), 'Open.CE')
2090 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2091 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2092 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002093
2094 def test_repr(self):
2095 Perm = self.Perm
2096 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2097 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2098 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2099 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2100 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2101 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002102 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2103 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002104 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2105 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2106 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2107 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002108 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002109 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2110 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2111 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002112
2113 Open = self.Open
2114 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2115 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2116 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2117 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2118 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002119 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002120 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2121 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2122 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2123 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2124 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2125 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002126
2127 def test_or(self):
2128 Perm = self.Perm
2129 for i in Perm:
2130 for j in Perm:
2131 self.assertEqual(i | j, i.value | j.value)
2132 self.assertEqual((i | j).value, i.value | j.value)
2133 self.assertIs(type(i | j), Perm)
2134 for j in range(8):
2135 self.assertEqual(i | j, i.value | j)
2136 self.assertEqual((i | j).value, i.value | j)
2137 self.assertIs(type(i | j), Perm)
2138 self.assertEqual(j | i, j | i.value)
2139 self.assertEqual((j | i).value, j | i.value)
2140 self.assertIs(type(j | i), Perm)
2141 for i in Perm:
2142 self.assertIs(i | i, i)
2143 self.assertIs(i | 0, i)
2144 self.assertIs(0 | i, i)
2145 Open = self.Open
2146 self.assertIs(Open.RO | Open.CE, Open.CE)
2147
2148 def test_and(self):
2149 Perm = self.Perm
2150 RW = Perm.R | Perm.W
2151 RX = Perm.R | Perm.X
2152 WX = Perm.W | Perm.X
2153 RWX = Perm.R | Perm.W | Perm.X
2154 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2155 for i in values:
2156 for j in values:
2157 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2158 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2159 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2160 for j in range(8):
2161 self.assertEqual(i & j, i.value & j)
2162 self.assertEqual((i & j).value, i.value & j)
2163 self.assertIs(type(i & j), Perm)
2164 self.assertEqual(j & i, j & i.value)
2165 self.assertEqual((j & i).value, j & i.value)
2166 self.assertIs(type(j & i), Perm)
2167 for i in Perm:
2168 self.assertIs(i & i, i)
2169 self.assertIs(i & 7, i)
2170 self.assertIs(7 & i, i)
2171 Open = self.Open
2172 self.assertIs(Open.RO & Open.CE, Open.RO)
2173
2174 def test_xor(self):
2175 Perm = self.Perm
2176 for i in Perm:
2177 for j in Perm:
2178 self.assertEqual(i ^ j, i.value ^ j.value)
2179 self.assertEqual((i ^ j).value, i.value ^ j.value)
2180 self.assertIs(type(i ^ j), Perm)
2181 for j in range(8):
2182 self.assertEqual(i ^ j, i.value ^ j)
2183 self.assertEqual((i ^ j).value, i.value ^ j)
2184 self.assertIs(type(i ^ j), Perm)
2185 self.assertEqual(j ^ i, j ^ i.value)
2186 self.assertEqual((j ^ i).value, j ^ i.value)
2187 self.assertIs(type(j ^ i), Perm)
2188 for i in Perm:
2189 self.assertIs(i ^ 0, i)
2190 self.assertIs(0 ^ i, i)
2191 Open = self.Open
2192 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2193 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2194
2195 def test_invert(self):
2196 Perm = self.Perm
2197 RW = Perm.R | Perm.W
2198 RX = Perm.R | Perm.X
2199 WX = Perm.W | Perm.X
2200 RWX = Perm.R | Perm.W | Perm.X
2201 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2202 for i in values:
2203 self.assertEqual(~i, ~i.value)
2204 self.assertEqual((~i).value, ~i.value)
2205 self.assertIs(type(~i), Perm)
2206 self.assertEqual(~~i, i)
2207 for i in Perm:
2208 self.assertIs(~~i, i)
2209 Open = self.Open
2210 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2211 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2212
2213 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002214 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002215 lst = list(Perm)
2216 self.assertEqual(len(lst), len(Perm))
2217 self.assertEqual(len(Perm), 3, Perm)
2218 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2219 for i, n in enumerate('R W X'.split()):
2220 v = 1<<i
2221 e = Perm(v)
2222 self.assertEqual(e.value, v)
2223 self.assertEqual(type(e.value), int)
2224 self.assertEqual(e, v)
2225 self.assertEqual(e.name, n)
2226 self.assertIn(e, Perm)
2227 self.assertIs(type(e), Perm)
2228
2229 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002230 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002231 lst = list(Perm)
2232 self.assertEqual(len(lst), len(Perm))
2233 self.assertEqual(len(Perm), 3, Perm)
2234 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2235 for i, n in enumerate('R W X'.split()):
2236 v = 8<<i
2237 e = Perm(v)
2238 self.assertEqual(e.value, v)
2239 self.assertEqual(type(e.value), int)
2240 self.assertEqual(e, v)
2241 self.assertEqual(e.name, n)
2242 self.assertIn(e, Perm)
2243 self.assertIs(type(e), Perm)
2244
2245 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002246 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002247 lst = list(Perm)
2248 self.assertEqual(len(lst), len(Perm))
2249 self.assertEqual(len(Perm), 3, Perm)
2250 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2251 for i, n in enumerate('R W X'.split()):
2252 v = 1<<i
2253 e = Perm(v)
2254 self.assertEqual(e.value, v)
2255 self.assertEqual(type(e.value), int)
2256 self.assertEqual(e, v)
2257 self.assertEqual(e.name, n)
2258 self.assertIn(e, Perm)
2259 self.assertIs(type(e), Perm)
2260
2261 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002262 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002263 lst = list(Perm)
2264 self.assertEqual(len(lst), len(Perm))
2265 self.assertEqual(len(Perm), 3, Perm)
2266 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2267 for i, n in enumerate('R W X'.split()):
2268 v = 1<<(2*i+1)
2269 e = Perm(v)
2270 self.assertEqual(e.value, v)
2271 self.assertEqual(type(e.value), int)
2272 self.assertEqual(e, v)
2273 self.assertEqual(e.name, n)
2274 self.assertIn(e, Perm)
2275 self.assertIs(type(e), Perm)
2276
2277 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002278 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002279 lst = list(Perm)
2280 self.assertEqual(len(lst), len(Perm))
2281 self.assertEqual(len(Perm), 3, Perm)
2282 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2283 for i, n in enumerate('R W X'.split()):
2284 v = 1<<(2*i+1)
2285 e = Perm(v)
2286 self.assertEqual(e.value, v)
2287 self.assertEqual(type(e.value), int)
2288 self.assertEqual(e, v)
2289 self.assertEqual(e.name, n)
2290 self.assertIn(e, Perm)
2291 self.assertIs(type(e), Perm)
2292
2293
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002294 def test_programatic_function_from_empty_list(self):
2295 Perm = enum.IntFlag('Perm', [])
2296 lst = list(Perm)
2297 self.assertEqual(len(lst), len(Perm))
2298 self.assertEqual(len(Perm), 0, Perm)
2299 Thing = enum.Enum('Thing', [])
2300 lst = list(Thing)
2301 self.assertEqual(len(lst), len(Thing))
2302 self.assertEqual(len(Thing), 0, Thing)
2303
2304
2305 def test_programatic_function_from_empty_tuple(self):
2306 Perm = enum.IntFlag('Perm', ())
2307 lst = list(Perm)
2308 self.assertEqual(len(lst), len(Perm))
2309 self.assertEqual(len(Perm), 0, Perm)
2310 Thing = enum.Enum('Thing', ())
2311 self.assertEqual(len(lst), len(Thing))
2312 self.assertEqual(len(Thing), 0, Thing)
2313
Ethan Furman65a5a472016-09-01 23:55:19 -07002314 def test_containment(self):
2315 Perm = self.Perm
2316 R, W, X = Perm
2317 RW = R | W
2318 RX = R | X
2319 WX = W | X
2320 RWX = R | W | X
2321 self.assertTrue(R in RW)
2322 self.assertTrue(R in RX)
2323 self.assertTrue(R in RWX)
2324 self.assertTrue(W in RW)
2325 self.assertTrue(W in WX)
2326 self.assertTrue(W in RWX)
2327 self.assertTrue(X in RX)
2328 self.assertTrue(X in WX)
2329 self.assertTrue(X in RWX)
2330 self.assertFalse(R in WX)
2331 self.assertFalse(W in RX)
2332 self.assertFalse(X in RW)
2333
Ethan Furman25d94bb2016-09-02 16:32:32 -07002334 def test_bool(self):
2335 Perm = self.Perm
2336 for f in Perm:
2337 self.assertTrue(f)
2338 Open = self.Open
2339 for f in Open:
2340 self.assertEqual(bool(f.value), bool(f))
2341
Ethan Furman28cf6632017-01-24 12:12:06 -08002342 @unittest.skipUnless(threading, 'Threading required for this test.')
2343 @support.reap_threads
2344 def test_unique_composite(self):
2345 # override __eq__ to be identity only
2346 class TestFlag(IntFlag):
2347 one = auto()
2348 two = auto()
2349 three = auto()
2350 four = auto()
2351 five = auto()
2352 six = auto()
2353 seven = auto()
2354 eight = auto()
2355 def __eq__(self, other):
2356 return self is other
2357 def __hash__(self):
2358 return hash(self._value_)
2359 # have multiple threads competing to complete the composite members
2360 seen = set()
2361 failed = False
2362 def cycle_enum():
2363 nonlocal failed
2364 try:
2365 for i in range(256):
2366 seen.add(TestFlag(i))
2367 except Exception:
2368 failed = True
2369 threads = [
2370 threading.Thread(target=cycle_enum)
2371 for _ in range(8)
2372 ]
2373 with support.start_threads(threads):
2374 pass
2375 # check that only 248 members were created
2376 self.assertFalse(
2377 failed,
2378 'at least one thread failed while creating composite members')
2379 self.assertEqual(256, len(seen), 'too many composite members created')
2380
2381
Ethan Furmanf24bb352013-07-18 17:05:39 -07002382class TestUnique(unittest.TestCase):
2383
2384 def test_unique_clean(self):
2385 @unique
2386 class Clean(Enum):
2387 one = 1
2388 two = 'dos'
2389 tres = 4.0
2390 @unique
2391 class Cleaner(IntEnum):
2392 single = 1
2393 double = 2
2394 triple = 3
2395
2396 def test_unique_dirty(self):
2397 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2398 @unique
2399 class Dirty(Enum):
2400 one = 1
2401 two = 'dos'
2402 tres = 1
2403 with self.assertRaisesRegex(
2404 ValueError,
2405 'double.*single.*turkey.*triple',
2406 ):
2407 @unique
2408 class Dirtier(IntEnum):
2409 single = 1
2410 double = 1
2411 triple = 3
2412 turkey = 3
2413
Ethan Furman3803ad42016-05-01 10:03:53 -07002414 def test_unique_with_name(self):
2415 @unique
2416 class Silly(Enum):
2417 one = 1
2418 two = 'dos'
2419 name = 3
2420 @unique
2421 class Sillier(IntEnum):
2422 single = 1
2423 name = 2
2424 triple = 3
2425 value = 4
2426
Ethan Furmanf24bb352013-07-18 17:05:39 -07002427
Ethan Furman3323da92015-04-11 09:39:59 -07002428expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002429Help on class Color in module %s:
2430
2431class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002432 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2433 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002434 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002435 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002436 | Method resolution order:
2437 | Color
2438 | enum.Enum
2439 | builtins.object
2440 |\x20\x20
2441 | Data and other attributes defined here:
2442 |\x20\x20
2443 | blue = <Color.blue: 3>
2444 |\x20\x20
2445 | green = <Color.green: 2>
2446 |\x20\x20
2447 | red = <Color.red: 1>
2448 |\x20\x20
2449 | ----------------------------------------------------------------------
2450 | Data descriptors inherited from enum.Enum:
2451 |\x20\x20
2452 | name
2453 | The name of the Enum member.
2454 |\x20\x20
2455 | value
2456 | The value of the Enum member.
2457 |\x20\x20
2458 | ----------------------------------------------------------------------
2459 | Data descriptors inherited from enum.EnumMeta:
2460 |\x20\x20
2461 | __members__
2462 | Returns a mapping of member name->value.
2463 |\x20\x20\x20\x20\x20\x20
2464 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002465 | is a read-only view of the internal mapping."""
2466
2467expected_help_output_without_docs = """\
2468Help on class Color in module %s:
2469
2470class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002471 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2472 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002473 | Method resolution order:
2474 | Color
2475 | enum.Enum
2476 | builtins.object
2477 |\x20\x20
2478 | Data and other attributes defined here:
2479 |\x20\x20
2480 | blue = <Color.blue: 3>
2481 |\x20\x20
2482 | green = <Color.green: 2>
2483 |\x20\x20
2484 | red = <Color.red: 1>
2485 |\x20\x20
2486 | ----------------------------------------------------------------------
2487 | Data descriptors inherited from enum.Enum:
2488 |\x20\x20
2489 | name
2490 |\x20\x20
2491 | value
2492 |\x20\x20
2493 | ----------------------------------------------------------------------
2494 | Data descriptors inherited from enum.EnumMeta:
2495 |\x20\x20
2496 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002497
2498class TestStdLib(unittest.TestCase):
2499
Ethan Furman48a724f2015-04-11 23:23:06 -07002500 maxDiff = None
2501
Ethan Furman5875d742013-10-21 20:45:55 -07002502 class Color(Enum):
2503 red = 1
2504 green = 2
2505 blue = 3
2506
2507 def test_pydoc(self):
2508 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002509 if StrEnum.__doc__ is None:
2510 expected_text = expected_help_output_without_docs % __name__
2511 else:
2512 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002513 output = StringIO()
2514 helper = pydoc.Helper(output=output)
2515 helper(self.Color)
2516 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002517 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002518
2519 def test_inspect_getmembers(self):
2520 values = dict((
2521 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002522 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002523 ('__members__', self.Color.__members__),
2524 ('__module__', __name__),
2525 ('blue', self.Color.blue),
2526 ('green', self.Color.green),
2527 ('name', Enum.__dict__['name']),
2528 ('red', self.Color.red),
2529 ('value', Enum.__dict__['value']),
2530 ))
2531 result = dict(inspect.getmembers(self.Color))
2532 self.assertEqual(values.keys(), result.keys())
2533 failed = False
2534 for k in values.keys():
2535 if result[k] != values[k]:
2536 print()
2537 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2538 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2539 failed = True
2540 if failed:
2541 self.fail("result does not equal expected, see print above")
2542
2543 def test_inspect_classify_class_attrs(self):
2544 # indirectly test __objclass__
2545 from inspect import Attribute
2546 values = [
2547 Attribute(name='__class__', kind='data',
2548 defining_class=object, object=EnumMeta),
2549 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002550 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002551 Attribute(name='__members__', kind='property',
2552 defining_class=EnumMeta, object=EnumMeta.__members__),
2553 Attribute(name='__module__', kind='data',
2554 defining_class=self.Color, object=__name__),
2555 Attribute(name='blue', kind='data',
2556 defining_class=self.Color, object=self.Color.blue),
2557 Attribute(name='green', kind='data',
2558 defining_class=self.Color, object=self.Color.green),
2559 Attribute(name='red', kind='data',
2560 defining_class=self.Color, object=self.Color.red),
2561 Attribute(name='name', kind='data',
2562 defining_class=Enum, object=Enum.__dict__['name']),
2563 Attribute(name='value', kind='data',
2564 defining_class=Enum, object=Enum.__dict__['value']),
2565 ]
2566 values.sort(key=lambda item: item.name)
2567 result = list(inspect.classify_class_attrs(self.Color))
2568 result.sort(key=lambda item: item.name)
2569 failed = False
2570 for v, r in zip(values, result):
2571 if r != v:
2572 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2573 failed = True
2574 if failed:
2575 self.fail("result does not equal expected, see print above")
2576
Martin Panter19e69c52015-11-14 12:46:42 +00002577
2578class MiscTestCase(unittest.TestCase):
2579 def test__all__(self):
2580 support.check__all__(self, enum)
2581
2582
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002583# These are unordered here on purpose to ensure that declaration order
2584# makes no difference.
2585CONVERT_TEST_NAME_D = 5
2586CONVERT_TEST_NAME_C = 5
2587CONVERT_TEST_NAME_B = 5
2588CONVERT_TEST_NAME_A = 5 # This one should sort first.
2589CONVERT_TEST_NAME_E = 5
2590CONVERT_TEST_NAME_F = 5
2591
2592class TestIntEnumConvert(unittest.TestCase):
2593 def test_convert_value_lookup_priority(self):
2594 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002595 'UnittestConvert',
2596 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002597 filter=lambda x: x.startswith('CONVERT_TEST_'))
2598 # We don't want the reverse lookup value to vary when there are
2599 # multiple possible names for a given value. It should always
2600 # report the first lexigraphical name in that case.
2601 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2602
2603 def test_convert(self):
2604 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002605 'UnittestConvert',
2606 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002607 filter=lambda x: x.startswith('CONVERT_TEST_'))
2608 # Ensure that test_type has all of the desired names and values.
2609 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2610 test_type.CONVERT_TEST_NAME_A)
2611 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2612 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2613 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2614 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2615 # Ensure that test_type only picked up names matching the filter.
2616 self.assertEqual([name for name in dir(test_type)
2617 if name[0:2] not in ('CO', '__')],
2618 [], msg='Names other than CONVERT_TEST_* found.')
2619
2620
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002621if __name__ == '__main__':
2622 unittest.main()