blob: e6324d4d8c8d147e992ea5ebcf4790d58fc9de72 [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
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02005import threading
Ethan Furman6b3d64a2013-06-14 16:55:46 -07006from collections import OrderedDict
Ethan Furmanc16595e2016-09-10 23:36:59 -07007from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07008from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -08009from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +000010from test import support
Ethan Furman28cf6632017-01-24 12:12:06 -080011
Ethan Furman6b3d64a2013-06-14 16:55:46 -070012
13# for pickle tests
14try:
15 class Stooges(Enum):
16 LARRY = 1
17 CURLY = 2
18 MOE = 3
19except Exception as exc:
20 Stooges = exc
21
22try:
23 class IntStooges(int, Enum):
24 LARRY = 1
25 CURLY = 2
26 MOE = 3
27except Exception as exc:
28 IntStooges = exc
29
30try:
31 class FloatStooges(float, Enum):
32 LARRY = 1.39
33 CURLY = 2.72
34 MOE = 3.142596
35except Exception as exc:
36 FloatStooges = exc
37
Ethan Furman65a5a472016-09-01 23:55:19 -070038try:
39 class FlagStooges(Flag):
40 LARRY = 1
41 CURLY = 2
42 MOE = 3
43except Exception as exc:
44 FlagStooges = exc
45
Ethan Furman6b3d64a2013-06-14 16:55:46 -070046# for pickle test and subclass tests
47try:
48 class StrEnum(str, Enum):
49 'accepts only string values'
50 class Name(StrEnum):
51 BDFL = 'Guido van Rossum'
52 FLUFL = 'Barry Warsaw'
53except Exception as exc:
54 Name = exc
55
56try:
57 Question = Enum('Question', 'who what when where why', module=__name__)
58except Exception as exc:
59 Question = exc
60
61try:
62 Answer = Enum('Answer', 'him this then there because')
63except Exception as exc:
64 Answer = exc
65
Ethan Furmanca1b7942014-02-08 11:36:27 -080066try:
67 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
68except Exception as exc:
69 Theory = exc
70
Ethan Furman6b3d64a2013-06-14 16:55:46 -070071# for doctests
72try:
73 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080074 TOMATO = 1
75 BANANA = 2
76 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070077except Exception:
78 pass
79
Serhiy Storchakae50e7802015-03-31 16:56:49 +030080def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080081 if target is None:
82 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030083 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080084 assertion(loads(dumps(source, protocol=protocol)), target)
85
Serhiy Storchakae50e7802015-03-31 16:56:49 +030086def test_pickle_exception(assertion, exception, obj):
87 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080088 with assertion(exception):
89 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070090
91class TestHelpers(unittest.TestCase):
92 # _is_descriptor, _is_sunder, _is_dunder
93
94 def test_is_descriptor(self):
95 class foo:
96 pass
97 for attr in ('__get__','__set__','__delete__'):
98 obj = foo()
99 self.assertFalse(enum._is_descriptor(obj))
100 setattr(obj, attr, 1)
101 self.assertTrue(enum._is_descriptor(obj))
102
103 def test_is_sunder(self):
104 for s in ('_a_', '_aa_'):
105 self.assertTrue(enum._is_sunder(s))
106
107 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
108 '__', '___', '____', '_____',):
109 self.assertFalse(enum._is_sunder(s))
110
111 def test_is_dunder(self):
112 for s in ('__a__', '__aa__'):
113 self.assertTrue(enum._is_dunder(s))
114 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
115 '__', '___', '____', '_____',):
116 self.assertFalse(enum._is_dunder(s))
117
Ethan Furmanc16595e2016-09-10 23:36:59 -0700118# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700119
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700120class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800121
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700122 def setUp(self):
123 class Season(Enum):
124 SPRING = 1
125 SUMMER = 2
126 AUTUMN = 3
127 WINTER = 4
128 self.Season = Season
129
Ethan Furmanec15a822013-08-31 19:17:41 -0700130 class Konstants(float, Enum):
131 E = 2.7182818
132 PI = 3.1415926
133 TAU = 2 * PI
134 self.Konstants = Konstants
135
136 class Grades(IntEnum):
137 A = 5
138 B = 4
139 C = 3
140 D = 2
141 F = 0
142 self.Grades = Grades
143
144 class Directional(str, Enum):
145 EAST = 'east'
146 WEST = 'west'
147 NORTH = 'north'
148 SOUTH = 'south'
149 self.Directional = Directional
150
151 from datetime import date
152 class Holiday(date, Enum):
153 NEW_YEAR = 2013, 1, 1
154 IDES_OF_MARCH = 2013, 3, 15
155 self.Holiday = Holiday
156
Ethan Furman388a3922013-08-12 06:51:41 -0700157 def test_dir_on_class(self):
158 Season = self.Season
159 self.assertEqual(
160 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700161 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700162 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
163 )
164
165 def test_dir_on_item(self):
166 Season = self.Season
167 self.assertEqual(
168 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700169 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700170 )
171
Ethan Furmanc850f342013-09-15 16:59:35 -0700172 def test_dir_with_added_behavior(self):
173 class Test(Enum):
174 this = 'that'
175 these = 'those'
176 def wowser(self):
177 return ("Wowser! I'm %s!" % self.name)
178 self.assertEqual(
179 set(dir(Test)),
180 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
181 )
182 self.assertEqual(
183 set(dir(Test.this)),
184 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
185 )
186
Ethan Furman0ae550b2014-10-14 08:58:32 -0700187 def test_dir_on_sub_with_behavior_on_super(self):
188 # see issue22506
189 class SuperEnum(Enum):
190 def invisible(self):
191 return "did you see me?"
192 class SubEnum(SuperEnum):
193 sample = 5
194 self.assertEqual(
195 set(dir(SubEnum.sample)),
196 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
197 )
198
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700199 def test_enum_in_enum_out(self):
200 Season = self.Season
201 self.assertIs(Season(Season.WINTER), Season.WINTER)
202
203 def test_enum_value(self):
204 Season = self.Season
205 self.assertEqual(Season.SPRING.value, 1)
206
207 def test_intenum_value(self):
208 self.assertEqual(IntStooges.CURLY.value, 2)
209
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700210 def test_enum(self):
211 Season = self.Season
212 lst = list(Season)
213 self.assertEqual(len(lst), len(Season))
214 self.assertEqual(len(Season), 4, Season)
215 self.assertEqual(
216 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
217
218 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
219 e = Season(i)
220 self.assertEqual(e, getattr(Season, season))
221 self.assertEqual(e.value, i)
222 self.assertNotEqual(e, i)
223 self.assertEqual(e.name, season)
224 self.assertIn(e, Season)
225 self.assertIs(type(e), Season)
226 self.assertIsInstance(e, Season)
227 self.assertEqual(str(e), 'Season.' + season)
228 self.assertEqual(
229 repr(e),
230 '<Season.{0}: {1}>'.format(season, i),
231 )
232
233 def test_value_name(self):
234 Season = self.Season
235 self.assertEqual(Season.SPRING.name, 'SPRING')
236 self.assertEqual(Season.SPRING.value, 1)
237 with self.assertRaises(AttributeError):
238 Season.SPRING.name = 'invierno'
239 with self.assertRaises(AttributeError):
240 Season.SPRING.value = 2
241
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700242 def test_changing_member(self):
243 Season = self.Season
244 with self.assertRaises(AttributeError):
245 Season.WINTER = 'really cold'
246
Ethan Furman64a99722013-09-22 16:18:19 -0700247 def test_attribute_deletion(self):
248 class Season(Enum):
249 SPRING = 1
250 SUMMER = 2
251 AUTUMN = 3
252 WINTER = 4
253
254 def spam(cls):
255 pass
256
257 self.assertTrue(hasattr(Season, 'spam'))
258 del Season.spam
259 self.assertFalse(hasattr(Season, 'spam'))
260
261 with self.assertRaises(AttributeError):
262 del Season.SPRING
263 with self.assertRaises(AttributeError):
264 del Season.DRY
265 with self.assertRaises(AttributeError):
266 del Season.SPRING.name
267
Ethan Furman5de67b12016-04-13 23:52:09 -0700268 def test_bool_of_class(self):
269 class Empty(Enum):
270 pass
271 self.assertTrue(bool(Empty))
272
273 def test_bool_of_member(self):
274 class Count(Enum):
275 zero = 0
276 one = 1
277 two = 2
278 for member in Count:
279 self.assertTrue(bool(member))
280
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700281 def test_invalid_names(self):
282 with self.assertRaises(ValueError):
283 class Wrong(Enum):
284 mro = 9
285 with self.assertRaises(ValueError):
286 class Wrong(Enum):
287 _create_= 11
288 with self.assertRaises(ValueError):
289 class Wrong(Enum):
290 _get_mixins_ = 9
291 with self.assertRaises(ValueError):
292 class Wrong(Enum):
293 _find_new_ = 1
294 with self.assertRaises(ValueError):
295 class Wrong(Enum):
296 _any_name_ = 9
297
Ethan Furman6db1fd52015-09-17 21:49:12 -0700298 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800299 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700300 class Logic(Enum):
301 true = True
302 false = False
303 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800304 self.assertTrue(Logic.false)
305 # unless overridden
306 class RealLogic(Enum):
307 true = True
308 false = False
309 def __bool__(self):
310 return bool(self._value_)
311 self.assertTrue(RealLogic.true)
312 self.assertFalse(RealLogic.false)
313 # mixed Enums depend on mixed-in type
314 class IntLogic(int, Enum):
315 true = 1
316 false = 0
317 self.assertTrue(IntLogic.true)
318 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700319
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700320 def test_contains(self):
321 Season = self.Season
322 self.assertIn(Season.AUTUMN, Season)
323 self.assertNotIn(3, Season)
324
325 val = Season(3)
326 self.assertIn(val, Season)
327
328 class OtherEnum(Enum):
329 one = 1; two = 2
330 self.assertNotIn(OtherEnum.two, Season)
331
332 def test_comparisons(self):
333 Season = self.Season
334 with self.assertRaises(TypeError):
335 Season.SPRING < Season.WINTER
336 with self.assertRaises(TypeError):
337 Season.SPRING > 4
338
339 self.assertNotEqual(Season.SPRING, 1)
340
341 class Part(Enum):
342 SPRING = 1
343 CLIP = 2
344 BARREL = 3
345
346 self.assertNotEqual(Season.SPRING, Part.SPRING)
347 with self.assertRaises(TypeError):
348 Season.SPRING < Part.CLIP
349
350 def test_enum_duplicates(self):
351 class Season(Enum):
352 SPRING = 1
353 SUMMER = 2
354 AUTUMN = FALL = 3
355 WINTER = 4
356 ANOTHER_SPRING = 1
357 lst = list(Season)
358 self.assertEqual(
359 lst,
360 [Season.SPRING, Season.SUMMER,
361 Season.AUTUMN, Season.WINTER,
362 ])
363 self.assertIs(Season.FALL, Season.AUTUMN)
364 self.assertEqual(Season.FALL.value, 3)
365 self.assertEqual(Season.AUTUMN.value, 3)
366 self.assertIs(Season(3), Season.AUTUMN)
367 self.assertIs(Season(1), Season.SPRING)
368 self.assertEqual(Season.FALL.name, 'AUTUMN')
369 self.assertEqual(
370 [k for k,v in Season.__members__.items() if v.name != k],
371 ['FALL', 'ANOTHER_SPRING'],
372 )
373
Ethan Furman101e0742013-09-15 12:34:36 -0700374 def test_duplicate_name(self):
375 with self.assertRaises(TypeError):
376 class Color(Enum):
377 red = 1
378 green = 2
379 blue = 3
380 red = 4
381
382 with self.assertRaises(TypeError):
383 class Color(Enum):
384 red = 1
385 green = 2
386 blue = 3
387 def red(self):
388 return 'red'
389
390 with self.assertRaises(TypeError):
391 class Color(Enum):
392 @property
393 def red(self):
394 return 'redder'
395 red = 1
396 green = 2
397 blue = 3
398
399
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700400 def test_enum_with_value_name(self):
401 class Huh(Enum):
402 name = 1
403 value = 2
404 self.assertEqual(
405 list(Huh),
406 [Huh.name, Huh.value],
407 )
408 self.assertIs(type(Huh.name), Huh)
409 self.assertEqual(Huh.name.name, 'name')
410 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700411
412 def test_format_enum(self):
413 Season = self.Season
414 self.assertEqual('{}'.format(Season.SPRING),
415 '{}'.format(str(Season.SPRING)))
416 self.assertEqual( '{:}'.format(Season.SPRING),
417 '{:}'.format(str(Season.SPRING)))
418 self.assertEqual('{:20}'.format(Season.SPRING),
419 '{:20}'.format(str(Season.SPRING)))
420 self.assertEqual('{:^20}'.format(Season.SPRING),
421 '{:^20}'.format(str(Season.SPRING)))
422 self.assertEqual('{:>20}'.format(Season.SPRING),
423 '{:>20}'.format(str(Season.SPRING)))
424 self.assertEqual('{:<20}'.format(Season.SPRING),
425 '{:<20}'.format(str(Season.SPRING)))
426
427 def test_format_enum_custom(self):
428 class TestFloat(float, Enum):
429 one = 1.0
430 two = 2.0
431 def __format__(self, spec):
432 return 'TestFloat success!'
433 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
434
435 def assertFormatIsValue(self, spec, member):
436 self.assertEqual(spec.format(member), spec.format(member.value))
437
438 def test_format_enum_date(self):
439 Holiday = self.Holiday
440 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
441 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
442 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
443 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
444 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
445 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
446 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
447 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
448
449 def test_format_enum_float(self):
450 Konstants = self.Konstants
451 self.assertFormatIsValue('{}', Konstants.TAU)
452 self.assertFormatIsValue('{:}', Konstants.TAU)
453 self.assertFormatIsValue('{:20}', Konstants.TAU)
454 self.assertFormatIsValue('{:^20}', Konstants.TAU)
455 self.assertFormatIsValue('{:>20}', Konstants.TAU)
456 self.assertFormatIsValue('{:<20}', Konstants.TAU)
457 self.assertFormatIsValue('{:n}', Konstants.TAU)
458 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
459 self.assertFormatIsValue('{:f}', Konstants.TAU)
460
461 def test_format_enum_int(self):
462 Grades = self.Grades
463 self.assertFormatIsValue('{}', Grades.C)
464 self.assertFormatIsValue('{:}', Grades.C)
465 self.assertFormatIsValue('{:20}', Grades.C)
466 self.assertFormatIsValue('{:^20}', Grades.C)
467 self.assertFormatIsValue('{:>20}', Grades.C)
468 self.assertFormatIsValue('{:<20}', Grades.C)
469 self.assertFormatIsValue('{:+}', Grades.C)
470 self.assertFormatIsValue('{:08X}', Grades.C)
471 self.assertFormatIsValue('{:b}', Grades.C)
472
473 def test_format_enum_str(self):
474 Directional = self.Directional
475 self.assertFormatIsValue('{}', Directional.WEST)
476 self.assertFormatIsValue('{:}', Directional.WEST)
477 self.assertFormatIsValue('{:20}', Directional.WEST)
478 self.assertFormatIsValue('{:^20}', Directional.WEST)
479 self.assertFormatIsValue('{:>20}', Directional.WEST)
480 self.assertFormatIsValue('{:<20}', Directional.WEST)
481
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700482 def test_hash(self):
483 Season = self.Season
484 dates = {}
485 dates[Season.WINTER] = '1225'
486 dates[Season.SPRING] = '0315'
487 dates[Season.SUMMER] = '0704'
488 dates[Season.AUTUMN] = '1031'
489 self.assertEqual(dates[Season.AUTUMN], '1031')
490
491 def test_intenum_from_scratch(self):
492 class phy(int, Enum):
493 pi = 3
494 tau = 2 * pi
495 self.assertTrue(phy.pi < phy.tau)
496
497 def test_intenum_inherited(self):
498 class IntEnum(int, Enum):
499 pass
500 class phy(IntEnum):
501 pi = 3
502 tau = 2 * pi
503 self.assertTrue(phy.pi < phy.tau)
504
505 def test_floatenum_from_scratch(self):
506 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700507 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700508 tau = 2 * pi
509 self.assertTrue(phy.pi < phy.tau)
510
511 def test_floatenum_inherited(self):
512 class FloatEnum(float, Enum):
513 pass
514 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700515 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700516 tau = 2 * pi
517 self.assertTrue(phy.pi < phy.tau)
518
519 def test_strenum_from_scratch(self):
520 class phy(str, Enum):
521 pi = 'Pi'
522 tau = 'Tau'
523 self.assertTrue(phy.pi < phy.tau)
524
525 def test_strenum_inherited(self):
526 class StrEnum(str, Enum):
527 pass
528 class phy(StrEnum):
529 pi = 'Pi'
530 tau = 'Tau'
531 self.assertTrue(phy.pi < phy.tau)
532
533
534 def test_intenum(self):
535 class WeekDay(IntEnum):
536 SUNDAY = 1
537 MONDAY = 2
538 TUESDAY = 3
539 WEDNESDAY = 4
540 THURSDAY = 5
541 FRIDAY = 6
542 SATURDAY = 7
543
544 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
545 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
546
547 lst = list(WeekDay)
548 self.assertEqual(len(lst), len(WeekDay))
549 self.assertEqual(len(WeekDay), 7)
550 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
551 target = target.split()
552 for i, weekday in enumerate(target, 1):
553 e = WeekDay(i)
554 self.assertEqual(e, i)
555 self.assertEqual(int(e), i)
556 self.assertEqual(e.name, weekday)
557 self.assertIn(e, WeekDay)
558 self.assertEqual(lst.index(e)+1, i)
559 self.assertTrue(0 < e < 8)
560 self.assertIs(type(e), WeekDay)
561 self.assertIsInstance(e, int)
562 self.assertIsInstance(e, Enum)
563
564 def test_intenum_duplicates(self):
565 class WeekDay(IntEnum):
566 SUNDAY = 1
567 MONDAY = 2
568 TUESDAY = TEUSDAY = 3
569 WEDNESDAY = 4
570 THURSDAY = 5
571 FRIDAY = 6
572 SATURDAY = 7
573 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
574 self.assertEqual(WeekDay(3).name, 'TUESDAY')
575 self.assertEqual([k for k,v in WeekDay.__members__.items()
576 if v.name != k], ['TEUSDAY', ])
577
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300578 def test_intenum_from_bytes(self):
579 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
580 with self.assertRaises(ValueError):
581 IntStooges.from_bytes(b'\x00\x05', 'big')
582
583 def test_floatenum_fromhex(self):
584 h = float.hex(FloatStooges.MOE.value)
585 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
586 h = float.hex(FloatStooges.MOE.value + 0.01)
587 with self.assertRaises(ValueError):
588 FloatStooges.fromhex(h)
589
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700590 def test_pickle_enum(self):
591 if isinstance(Stooges, Exception):
592 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800593 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
594 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700595
596 def test_pickle_int(self):
597 if isinstance(IntStooges, Exception):
598 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800599 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
600 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700601
602 def test_pickle_float(self):
603 if isinstance(FloatStooges, Exception):
604 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800605 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
606 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700607
608 def test_pickle_enum_function(self):
609 if isinstance(Answer, Exception):
610 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800611 test_pickle_dump_load(self.assertIs, Answer.him)
612 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700613
614 def test_pickle_enum_function_with_module(self):
615 if isinstance(Question, Exception):
616 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800617 test_pickle_dump_load(self.assertIs, Question.who)
618 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700619
Ethan Furmanca1b7942014-02-08 11:36:27 -0800620 def test_enum_function_with_qualname(self):
621 if isinstance(Theory, Exception):
622 raise Theory
623 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
624
625 def test_class_nested_enum_and_pickle_protocol_four(self):
626 # would normally just have this directly in the class namespace
627 class NestedEnum(Enum):
628 twigs = 'common'
629 shiny = 'rare'
630
631 self.__class__.NestedEnum = NestedEnum
632 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300633 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800634
Ethan Furman24e837f2015-03-18 17:27:57 -0700635 def test_pickle_by_name(self):
636 class ReplaceGlobalInt(IntEnum):
637 ONE = 1
638 TWO = 2
639 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
640 for proto in range(HIGHEST_PROTOCOL):
641 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
642
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700643 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800644 BadPickle = Enum(
645 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700646 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800647 # now break BadPickle to test exception raising
648 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800649 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
650 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700651
652 def test_string_enum(self):
653 class SkillLevel(str, Enum):
654 master = 'what is the sound of one hand clapping?'
655 journeyman = 'why did the chicken cross the road?'
656 apprentice = 'knock, knock!'
657 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
658
659 def test_getattr_getitem(self):
660 class Period(Enum):
661 morning = 1
662 noon = 2
663 evening = 3
664 night = 4
665 self.assertIs(Period(2), Period.noon)
666 self.assertIs(getattr(Period, 'night'), Period.night)
667 self.assertIs(Period['morning'], Period.morning)
668
669 def test_getattr_dunder(self):
670 Season = self.Season
671 self.assertTrue(getattr(Season, '__eq__'))
672
673 def test_iteration_order(self):
674 class Season(Enum):
675 SUMMER = 2
676 WINTER = 4
677 AUTUMN = 3
678 SPRING = 1
679 self.assertEqual(
680 list(Season),
681 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
682 )
683
Ethan Furman2131a4a2013-09-14 18:11:24 -0700684 def test_reversed_iteration_order(self):
685 self.assertEqual(
686 list(reversed(self.Season)),
687 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
688 self.Season.SPRING]
689 )
690
Martin Pantereb995702016-07-28 01:11:04 +0000691 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700692 SummerMonth = Enum('SummerMonth', 'june july august')
693 lst = list(SummerMonth)
694 self.assertEqual(len(lst), len(SummerMonth))
695 self.assertEqual(len(SummerMonth), 3, SummerMonth)
696 self.assertEqual(
697 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
698 lst,
699 )
700 for i, month in enumerate('june july august'.split(), 1):
701 e = SummerMonth(i)
702 self.assertEqual(int(e.value), i)
703 self.assertNotEqual(e, i)
704 self.assertEqual(e.name, month)
705 self.assertIn(e, SummerMonth)
706 self.assertIs(type(e), SummerMonth)
707
Martin Pantereb995702016-07-28 01:11:04 +0000708 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700709 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
710 lst = list(SummerMonth)
711 self.assertEqual(len(lst), len(SummerMonth))
712 self.assertEqual(len(SummerMonth), 3, SummerMonth)
713 self.assertEqual(
714 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
715 lst,
716 )
717 for i, month in enumerate('june july august'.split(), 10):
718 e = SummerMonth(i)
719 self.assertEqual(int(e.value), i)
720 self.assertNotEqual(e, i)
721 self.assertEqual(e.name, month)
722 self.assertIn(e, SummerMonth)
723 self.assertIs(type(e), SummerMonth)
724
Martin Pantereb995702016-07-28 01:11:04 +0000725 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700726 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
727 lst = list(SummerMonth)
728 self.assertEqual(len(lst), len(SummerMonth))
729 self.assertEqual(len(SummerMonth), 3, SummerMonth)
730 self.assertEqual(
731 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
732 lst,
733 )
734 for i, month in enumerate('june july august'.split(), 1):
735 e = SummerMonth(i)
736 self.assertEqual(int(e.value), i)
737 self.assertNotEqual(e, i)
738 self.assertEqual(e.name, month)
739 self.assertIn(e, SummerMonth)
740 self.assertIs(type(e), SummerMonth)
741
Martin Pantereb995702016-07-28 01:11:04 +0000742 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700743 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
744 lst = list(SummerMonth)
745 self.assertEqual(len(lst), len(SummerMonth))
746 self.assertEqual(len(SummerMonth), 3, SummerMonth)
747 self.assertEqual(
748 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
749 lst,
750 )
751 for i, month in enumerate('june july august'.split(), 20):
752 e = SummerMonth(i)
753 self.assertEqual(int(e.value), i)
754 self.assertNotEqual(e, i)
755 self.assertEqual(e.name, month)
756 self.assertIn(e, SummerMonth)
757 self.assertIs(type(e), SummerMonth)
758
Martin Pantereb995702016-07-28 01:11:04 +0000759 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700760 SummerMonth = Enum(
761 'SummerMonth',
762 (('june', 1), ('july', 2), ('august', 3))
763 )
764 lst = list(SummerMonth)
765 self.assertEqual(len(lst), len(SummerMonth))
766 self.assertEqual(len(SummerMonth), 3, SummerMonth)
767 self.assertEqual(
768 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
769 lst,
770 )
771 for i, month in enumerate('june july august'.split(), 1):
772 e = SummerMonth(i)
773 self.assertEqual(int(e.value), i)
774 self.assertNotEqual(e, i)
775 self.assertEqual(e.name, month)
776 self.assertIn(e, SummerMonth)
777 self.assertIs(type(e), SummerMonth)
778
Martin Pantereb995702016-07-28 01:11:04 +0000779 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700780 SummerMonth = Enum(
781 'SummerMonth',
782 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
783 )
784 lst = list(SummerMonth)
785 self.assertEqual(len(lst), len(SummerMonth))
786 self.assertEqual(len(SummerMonth), 3, SummerMonth)
787 self.assertEqual(
788 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
789 lst,
790 )
791 for i, month in enumerate('june july august'.split(), 1):
792 e = SummerMonth(i)
793 self.assertEqual(int(e.value), i)
794 self.assertNotEqual(e, i)
795 self.assertEqual(e.name, month)
796 self.assertIn(e, SummerMonth)
797 self.assertIs(type(e), SummerMonth)
798
Martin Pantereb995702016-07-28 01:11:04 +0000799 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700800 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
801 lst = list(SummerMonth)
802 self.assertEqual(len(lst), len(SummerMonth))
803 self.assertEqual(len(SummerMonth), 3, SummerMonth)
804 self.assertEqual(
805 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
806 lst,
807 )
808 for i, month in enumerate('june july august'.split(), 1):
809 e = SummerMonth(i)
810 self.assertEqual(e, i)
811 self.assertEqual(e.name, month)
812 self.assertIn(e, SummerMonth)
813 self.assertIs(type(e), SummerMonth)
814
Martin Pantereb995702016-07-28 01:11:04 +0000815 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700816 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
817 lst = list(SummerMonth)
818 self.assertEqual(len(lst), len(SummerMonth))
819 self.assertEqual(len(SummerMonth), 3, SummerMonth)
820 self.assertEqual(
821 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
822 lst,
823 )
824 for i, month in enumerate('june july august'.split(), 30):
825 e = SummerMonth(i)
826 self.assertEqual(e, i)
827 self.assertEqual(e.name, month)
828 self.assertIn(e, SummerMonth)
829 self.assertIs(type(e), SummerMonth)
830
Martin Pantereb995702016-07-28 01:11:04 +0000831 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700832 SummerMonth = IntEnum('SummerMonth', 'june july august')
833 lst = list(SummerMonth)
834 self.assertEqual(len(lst), len(SummerMonth))
835 self.assertEqual(len(SummerMonth), 3, SummerMonth)
836 self.assertEqual(
837 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
838 lst,
839 )
840 for i, month in enumerate('june july august'.split(), 1):
841 e = SummerMonth(i)
842 self.assertEqual(e, i)
843 self.assertEqual(e.name, month)
844 self.assertIn(e, SummerMonth)
845 self.assertIs(type(e), SummerMonth)
846
Martin Pantereb995702016-07-28 01:11:04 +0000847 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700848 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
849 lst = list(SummerMonth)
850 self.assertEqual(len(lst), len(SummerMonth))
851 self.assertEqual(len(SummerMonth), 3, SummerMonth)
852 self.assertEqual(
853 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
854 lst,
855 )
856 for i, month in enumerate('june july august'.split(), 40):
857 e = SummerMonth(i)
858 self.assertEqual(e, i)
859 self.assertEqual(e.name, month)
860 self.assertIn(e, SummerMonth)
861 self.assertIs(type(e), SummerMonth)
862
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700863 def test_subclassing(self):
864 if isinstance(Name, Exception):
865 raise Name
866 self.assertEqual(Name.BDFL, 'Guido van Rossum')
867 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
868 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800869 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700870
871 def test_extending(self):
872 class Color(Enum):
873 red = 1
874 green = 2
875 blue = 3
876 with self.assertRaises(TypeError):
877 class MoreColor(Color):
878 cyan = 4
879 magenta = 5
880 yellow = 6
881
882 def test_exclude_methods(self):
883 class whatever(Enum):
884 this = 'that'
885 these = 'those'
886 def really(self):
887 return 'no, not %s' % self.value
888 self.assertIsNot(type(whatever.really), whatever)
889 self.assertEqual(whatever.this.really(), 'no, not that')
890
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700891 def test_wrong_inheritance_order(self):
892 with self.assertRaises(TypeError):
893 class Wrong(Enum, str):
894 NotHere = 'error before this point'
895
896 def test_intenum_transitivity(self):
897 class number(IntEnum):
898 one = 1
899 two = 2
900 three = 3
901 class numero(IntEnum):
902 uno = 1
903 dos = 2
904 tres = 3
905 self.assertEqual(number.one, numero.uno)
906 self.assertEqual(number.two, numero.dos)
907 self.assertEqual(number.three, numero.tres)
908
909 def test_wrong_enum_in_call(self):
910 class Monochrome(Enum):
911 black = 0
912 white = 1
913 class Gender(Enum):
914 male = 0
915 female = 1
916 self.assertRaises(ValueError, Monochrome, Gender.male)
917
918 def test_wrong_enum_in_mixed_call(self):
919 class Monochrome(IntEnum):
920 black = 0
921 white = 1
922 class Gender(Enum):
923 male = 0
924 female = 1
925 self.assertRaises(ValueError, Monochrome, Gender.male)
926
927 def test_mixed_enum_in_call_1(self):
928 class Monochrome(IntEnum):
929 black = 0
930 white = 1
931 class Gender(IntEnum):
932 male = 0
933 female = 1
934 self.assertIs(Monochrome(Gender.female), Monochrome.white)
935
936 def test_mixed_enum_in_call_2(self):
937 class Monochrome(Enum):
938 black = 0
939 white = 1
940 class Gender(IntEnum):
941 male = 0
942 female = 1
943 self.assertIs(Monochrome(Gender.male), Monochrome.black)
944
945 def test_flufl_enum(self):
946 class Fluflnum(Enum):
947 def __int__(self):
948 return int(self.value)
949 class MailManOptions(Fluflnum):
950 option1 = 1
951 option2 = 2
952 option3 = 3
953 self.assertEqual(int(MailManOptions.option1), 1)
954
Ethan Furman5e5a8232013-08-04 08:42:23 -0700955 def test_introspection(self):
956 class Number(IntEnum):
957 one = 100
958 two = 200
959 self.assertIs(Number.one._member_type_, int)
960 self.assertIs(Number._member_type_, int)
961 class String(str, Enum):
962 yarn = 'soft'
963 rope = 'rough'
964 wire = 'hard'
965 self.assertIs(String.yarn._member_type_, str)
966 self.assertIs(String._member_type_, str)
967 class Plain(Enum):
968 vanilla = 'white'
969 one = 1
970 self.assertIs(Plain.vanilla._member_type_, object)
971 self.assertIs(Plain._member_type_, object)
972
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700973 def test_no_such_enum_member(self):
974 class Color(Enum):
975 red = 1
976 green = 2
977 blue = 3
978 with self.assertRaises(ValueError):
979 Color(4)
980 with self.assertRaises(KeyError):
981 Color['chartreuse']
982
983 def test_new_repr(self):
984 class Color(Enum):
985 red = 1
986 green = 2
987 blue = 3
988 def __repr__(self):
989 return "don't you just love shades of %s?" % self.name
990 self.assertEqual(
991 repr(Color.blue),
992 "don't you just love shades of blue?",
993 )
994
995 def test_inherited_repr(self):
996 class MyEnum(Enum):
997 def __repr__(self):
998 return "My name is %s." % self.name
999 class MyIntEnum(int, MyEnum):
1000 this = 1
1001 that = 2
1002 theother = 3
1003 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1004
1005 def test_multiple_mixin_mro(self):
1006 class auto_enum(type(Enum)):
1007 def __new__(metacls, cls, bases, classdict):
1008 temp = type(classdict)()
1009 names = set(classdict._member_names)
1010 i = 0
1011 for k in classdict._member_names:
1012 v = classdict[k]
1013 if v is Ellipsis:
1014 v = i
1015 else:
1016 i = v
1017 i += 1
1018 temp[k] = v
1019 for k, v in classdict.items():
1020 if k not in names:
1021 temp[k] = v
1022 return super(auto_enum, metacls).__new__(
1023 metacls, cls, bases, temp)
1024
1025 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1026 pass
1027
1028 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1029 pass
1030
1031 class TestAutoNumber(AutoNumberedEnum):
1032 a = ...
1033 b = 3
1034 c = ...
1035
1036 class TestAutoInt(AutoIntEnum):
1037 a = ...
1038 b = 3
1039 c = ...
1040
1041 def test_subclasses_with_getnewargs(self):
1042 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001043 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001044 def __new__(cls, *args):
1045 _args = args
1046 name, *args = args
1047 if len(args) == 0:
1048 raise TypeError("name and value must be specified")
1049 self = int.__new__(cls, *args)
1050 self._intname = name
1051 self._args = _args
1052 return self
1053 def __getnewargs__(self):
1054 return self._args
1055 @property
1056 def __name__(self):
1057 return self._intname
1058 def __repr__(self):
1059 # repr() is updated to include the name and type info
1060 return "{}({!r}, {})".format(type(self).__name__,
1061 self.__name__,
1062 int.__repr__(self))
1063 def __str__(self):
1064 # str() is unchanged, even if it relies on the repr() fallback
1065 base = int
1066 base_str = base.__str__
1067 if base_str.__objclass__ is object:
1068 return base.__repr__(self)
1069 return base_str(self)
1070 # for simplicity, we only define one operator that
1071 # propagates expressions
1072 def __add__(self, other):
1073 temp = int(self) + int( other)
1074 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1075 return NamedInt(
1076 '({0} + {1})'.format(self.__name__, other.__name__),
1077 temp )
1078 else:
1079 return temp
1080
1081 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001082 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001083 x = ('the-x', 1)
1084 y = ('the-y', 2)
1085
Ethan Furman2aa27322013-07-19 19:35:56 -07001086
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001087 self.assertIs(NEI.__new__, Enum.__new__)
1088 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1089 globals()['NamedInt'] = NamedInt
1090 globals()['NEI'] = NEI
1091 NI5 = NamedInt('test', 5)
1092 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001093 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001094 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001095 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001096 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001097
Ethan Furmanca1b7942014-02-08 11:36:27 -08001098 def test_subclasses_with_getnewargs_ex(self):
1099 class NamedInt(int):
1100 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1101 def __new__(cls, *args):
1102 _args = args
1103 name, *args = args
1104 if len(args) == 0:
1105 raise TypeError("name and value must be specified")
1106 self = int.__new__(cls, *args)
1107 self._intname = name
1108 self._args = _args
1109 return self
1110 def __getnewargs_ex__(self):
1111 return self._args, {}
1112 @property
1113 def __name__(self):
1114 return self._intname
1115 def __repr__(self):
1116 # repr() is updated to include the name and type info
1117 return "{}({!r}, {})".format(type(self).__name__,
1118 self.__name__,
1119 int.__repr__(self))
1120 def __str__(self):
1121 # str() is unchanged, even if it relies on the repr() fallback
1122 base = int
1123 base_str = base.__str__
1124 if base_str.__objclass__ is object:
1125 return base.__repr__(self)
1126 return base_str(self)
1127 # for simplicity, we only define one operator that
1128 # propagates expressions
1129 def __add__(self, other):
1130 temp = int(self) + int( other)
1131 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1132 return NamedInt(
1133 '({0} + {1})'.format(self.__name__, other.__name__),
1134 temp )
1135 else:
1136 return temp
1137
1138 class NEI(NamedInt, Enum):
1139 __qualname__ = 'NEI' # needed for pickle protocol 4
1140 x = ('the-x', 1)
1141 y = ('the-y', 2)
1142
1143
1144 self.assertIs(NEI.__new__, Enum.__new__)
1145 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1146 globals()['NamedInt'] = NamedInt
1147 globals()['NEI'] = NEI
1148 NI5 = NamedInt('test', 5)
1149 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001150 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001151 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001152 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001153 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001154
1155 def test_subclasses_with_reduce(self):
1156 class NamedInt(int):
1157 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1158 def __new__(cls, *args):
1159 _args = args
1160 name, *args = args
1161 if len(args) == 0:
1162 raise TypeError("name and value must be specified")
1163 self = int.__new__(cls, *args)
1164 self._intname = name
1165 self._args = _args
1166 return self
1167 def __reduce__(self):
1168 return self.__class__, self._args
1169 @property
1170 def __name__(self):
1171 return self._intname
1172 def __repr__(self):
1173 # repr() is updated to include the name and type info
1174 return "{}({!r}, {})".format(type(self).__name__,
1175 self.__name__,
1176 int.__repr__(self))
1177 def __str__(self):
1178 # str() is unchanged, even if it relies on the repr() fallback
1179 base = int
1180 base_str = base.__str__
1181 if base_str.__objclass__ is object:
1182 return base.__repr__(self)
1183 return base_str(self)
1184 # for simplicity, we only define one operator that
1185 # propagates expressions
1186 def __add__(self, other):
1187 temp = int(self) + int( other)
1188 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1189 return NamedInt(
1190 '({0} + {1})'.format(self.__name__, other.__name__),
1191 temp )
1192 else:
1193 return temp
1194
1195 class NEI(NamedInt, Enum):
1196 __qualname__ = 'NEI' # needed for pickle protocol 4
1197 x = ('the-x', 1)
1198 y = ('the-y', 2)
1199
1200
1201 self.assertIs(NEI.__new__, Enum.__new__)
1202 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1203 globals()['NamedInt'] = NamedInt
1204 globals()['NEI'] = NEI
1205 NI5 = NamedInt('test', 5)
1206 self.assertEqual(NI5, 5)
1207 test_pickle_dump_load(self.assertEqual, NI5, 5)
1208 self.assertEqual(NEI.y.value, 2)
1209 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001210 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001211
1212 def test_subclasses_with_reduce_ex(self):
1213 class NamedInt(int):
1214 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1215 def __new__(cls, *args):
1216 _args = args
1217 name, *args = args
1218 if len(args) == 0:
1219 raise TypeError("name and value must be specified")
1220 self = int.__new__(cls, *args)
1221 self._intname = name
1222 self._args = _args
1223 return self
1224 def __reduce_ex__(self, proto):
1225 return self.__class__, self._args
1226 @property
1227 def __name__(self):
1228 return self._intname
1229 def __repr__(self):
1230 # repr() is updated to include the name and type info
1231 return "{}({!r}, {})".format(type(self).__name__,
1232 self.__name__,
1233 int.__repr__(self))
1234 def __str__(self):
1235 # str() is unchanged, even if it relies on the repr() fallback
1236 base = int
1237 base_str = base.__str__
1238 if base_str.__objclass__ is object:
1239 return base.__repr__(self)
1240 return base_str(self)
1241 # for simplicity, we only define one operator that
1242 # propagates expressions
1243 def __add__(self, other):
1244 temp = int(self) + int( other)
1245 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1246 return NamedInt(
1247 '({0} + {1})'.format(self.__name__, other.__name__),
1248 temp )
1249 else:
1250 return temp
1251
1252 class NEI(NamedInt, Enum):
1253 __qualname__ = 'NEI' # needed for pickle protocol 4
1254 x = ('the-x', 1)
1255 y = ('the-y', 2)
1256
1257
1258 self.assertIs(NEI.__new__, Enum.__new__)
1259 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1260 globals()['NamedInt'] = NamedInt
1261 globals()['NEI'] = NEI
1262 NI5 = NamedInt('test', 5)
1263 self.assertEqual(NI5, 5)
1264 test_pickle_dump_load(self.assertEqual, NI5, 5)
1265 self.assertEqual(NEI.y.value, 2)
1266 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001267 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001268
Ethan Furmandc870522014-02-18 12:37:12 -08001269 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001270 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001271 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001272 def __new__(cls, *args):
1273 _args = args
1274 name, *args = args
1275 if len(args) == 0:
1276 raise TypeError("name and value must be specified")
1277 self = int.__new__(cls, *args)
1278 self._intname = name
1279 self._args = _args
1280 return self
1281 @property
1282 def __name__(self):
1283 return self._intname
1284 def __repr__(self):
1285 # repr() is updated to include the name and type info
1286 return "{}({!r}, {})".format(type(self).__name__,
1287 self.__name__,
1288 int.__repr__(self))
1289 def __str__(self):
1290 # str() is unchanged, even if it relies on the repr() fallback
1291 base = int
1292 base_str = base.__str__
1293 if base_str.__objclass__ is object:
1294 return base.__repr__(self)
1295 return base_str(self)
1296 # for simplicity, we only define one operator that
1297 # propagates expressions
1298 def __add__(self, other):
1299 temp = int(self) + int( other)
1300 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1301 return NamedInt(
1302 '({0} + {1})'.format(self.__name__, other.__name__),
1303 temp )
1304 else:
1305 return temp
1306
1307 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001308 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001309 x = ('the-x', 1)
1310 y = ('the-y', 2)
1311
1312 self.assertIs(NEI.__new__, Enum.__new__)
1313 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1314 globals()['NamedInt'] = NamedInt
1315 globals()['NEI'] = NEI
1316 NI5 = NamedInt('test', 5)
1317 self.assertEqual(NI5, 5)
1318 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001319 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1320 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001321
Ethan Furmandc870522014-02-18 12:37:12 -08001322 def test_subclasses_without_direct_pickle_support_using_name(self):
1323 class NamedInt(int):
1324 __qualname__ = 'NamedInt'
1325 def __new__(cls, *args):
1326 _args = args
1327 name, *args = args
1328 if len(args) == 0:
1329 raise TypeError("name and value must be specified")
1330 self = int.__new__(cls, *args)
1331 self._intname = name
1332 self._args = _args
1333 return self
1334 @property
1335 def __name__(self):
1336 return self._intname
1337 def __repr__(self):
1338 # repr() is updated to include the name and type info
1339 return "{}({!r}, {})".format(type(self).__name__,
1340 self.__name__,
1341 int.__repr__(self))
1342 def __str__(self):
1343 # str() is unchanged, even if it relies on the repr() fallback
1344 base = int
1345 base_str = base.__str__
1346 if base_str.__objclass__ is object:
1347 return base.__repr__(self)
1348 return base_str(self)
1349 # for simplicity, we only define one operator that
1350 # propagates expressions
1351 def __add__(self, other):
1352 temp = int(self) + int( other)
1353 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1354 return NamedInt(
1355 '({0} + {1})'.format(self.__name__, other.__name__),
1356 temp )
1357 else:
1358 return temp
1359
1360 class NEI(NamedInt, Enum):
1361 __qualname__ = 'NEI'
1362 x = ('the-x', 1)
1363 y = ('the-y', 2)
1364 def __reduce_ex__(self, proto):
1365 return getattr, (self.__class__, self._name_)
1366
1367 self.assertIs(NEI.__new__, Enum.__new__)
1368 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1369 globals()['NamedInt'] = NamedInt
1370 globals()['NEI'] = NEI
1371 NI5 = NamedInt('test', 5)
1372 self.assertEqual(NI5, 5)
1373 self.assertEqual(NEI.y.value, 2)
1374 test_pickle_dump_load(self.assertIs, NEI.y)
1375 test_pickle_dump_load(self.assertIs, NEI)
1376
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001377 def test_tuple_subclass(self):
1378 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001379 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001380 first = (1, 'for the money')
1381 second = (2, 'for the show')
1382 third = (3, 'for the music')
1383 self.assertIs(type(SomeTuple.first), SomeTuple)
1384 self.assertIsInstance(SomeTuple.second, tuple)
1385 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1386 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001387 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001388
1389 def test_duplicate_values_give_unique_enum_items(self):
1390 class AutoNumber(Enum):
1391 first = ()
1392 second = ()
1393 third = ()
1394 def __new__(cls):
1395 value = len(cls.__members__) + 1
1396 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001397 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001398 return obj
1399 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001400 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001401 self.assertEqual(
1402 list(AutoNumber),
1403 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1404 )
1405 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001406 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001407 self.assertIs(AutoNumber(1), AutoNumber.first)
1408
1409 def test_inherited_new_from_enhanced_enum(self):
1410 class AutoNumber(Enum):
1411 def __new__(cls):
1412 value = len(cls.__members__) + 1
1413 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001414 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001415 return obj
1416 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001417 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001418 class Color(AutoNumber):
1419 red = ()
1420 green = ()
1421 blue = ()
1422 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1423 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1424
1425 def test_inherited_new_from_mixed_enum(self):
1426 class AutoNumber(IntEnum):
1427 def __new__(cls):
1428 value = len(cls.__members__) + 1
1429 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001430 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001431 return obj
1432 class Color(AutoNumber):
1433 red = ()
1434 green = ()
1435 blue = ()
1436 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1437 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1438
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001439 def test_equality(self):
1440 class AlwaysEqual:
1441 def __eq__(self, other):
1442 return True
1443 class OrdinaryEnum(Enum):
1444 a = 1
1445 self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1446 self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1447
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001448 def test_ordered_mixin(self):
1449 class OrderedEnum(Enum):
1450 def __ge__(self, other):
1451 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001452 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001453 return NotImplemented
1454 def __gt__(self, other):
1455 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001456 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001457 return NotImplemented
1458 def __le__(self, other):
1459 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001460 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001461 return NotImplemented
1462 def __lt__(self, other):
1463 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001464 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001465 return NotImplemented
1466 class Grade(OrderedEnum):
1467 A = 5
1468 B = 4
1469 C = 3
1470 D = 2
1471 F = 1
1472 self.assertGreater(Grade.A, Grade.B)
1473 self.assertLessEqual(Grade.F, Grade.C)
1474 self.assertLess(Grade.D, Grade.A)
1475 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001476 self.assertEqual(Grade.B, Grade.B)
1477 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001478
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001479 def test_extending2(self):
1480 class Shade(Enum):
1481 def shade(self):
1482 print(self.name)
1483 class Color(Shade):
1484 red = 1
1485 green = 2
1486 blue = 3
1487 with self.assertRaises(TypeError):
1488 class MoreColor(Color):
1489 cyan = 4
1490 magenta = 5
1491 yellow = 6
1492
1493 def test_extending3(self):
1494 class Shade(Enum):
1495 def shade(self):
1496 return self.name
1497 class Color(Shade):
1498 def hex(self):
1499 return '%s hexlified!' % self.value
1500 class MoreColor(Color):
1501 cyan = 4
1502 magenta = 5
1503 yellow = 6
1504 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1505
1506
1507 def test_no_duplicates(self):
1508 class UniqueEnum(Enum):
1509 def __init__(self, *args):
1510 cls = self.__class__
1511 if any(self.value == e.value for e in cls):
1512 a = self.name
1513 e = cls(self.value).name
1514 raise ValueError(
1515 "aliases not allowed in UniqueEnum: %r --> %r"
1516 % (a, e)
1517 )
1518 class Color(UniqueEnum):
1519 red = 1
1520 green = 2
1521 blue = 3
1522 with self.assertRaises(ValueError):
1523 class Color(UniqueEnum):
1524 red = 1
1525 green = 2
1526 blue = 3
1527 grene = 2
1528
1529 def test_init(self):
1530 class Planet(Enum):
1531 MERCURY = (3.303e+23, 2.4397e6)
1532 VENUS = (4.869e+24, 6.0518e6)
1533 EARTH = (5.976e+24, 6.37814e6)
1534 MARS = (6.421e+23, 3.3972e6)
1535 JUPITER = (1.9e+27, 7.1492e7)
1536 SATURN = (5.688e+26, 6.0268e7)
1537 URANUS = (8.686e+25, 2.5559e7)
1538 NEPTUNE = (1.024e+26, 2.4746e7)
1539 def __init__(self, mass, radius):
1540 self.mass = mass # in kilograms
1541 self.radius = radius # in meters
1542 @property
1543 def surface_gravity(self):
1544 # universal gravitational constant (m3 kg-1 s-2)
1545 G = 6.67300E-11
1546 return G * self.mass / (self.radius * self.radius)
1547 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1548 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1549
Ethan Furman2aa27322013-07-19 19:35:56 -07001550 def test_nonhash_value(self):
1551 class AutoNumberInAList(Enum):
1552 def __new__(cls):
1553 value = [len(cls.__members__) + 1]
1554 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001555 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001556 return obj
1557 class ColorInAList(AutoNumberInAList):
1558 red = ()
1559 green = ()
1560 blue = ()
1561 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001562 for enum, value in zip(ColorInAList, range(3)):
1563 value += 1
1564 self.assertEqual(enum.value, [value])
1565 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001566
Ethan Furmanb41803e2013-07-25 13:50:45 -07001567 def test_conflicting_types_resolved_in_new(self):
1568 class LabelledIntEnum(int, Enum):
1569 def __new__(cls, *args):
1570 value, label = args
1571 obj = int.__new__(cls, value)
1572 obj.label = label
1573 obj._value_ = value
1574 return obj
1575
1576 class LabelledList(LabelledIntEnum):
1577 unprocessed = (1, "Unprocessed")
1578 payment_complete = (2, "Payment Complete")
1579
1580 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1581 self.assertEqual(LabelledList.unprocessed, 1)
1582 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001583
Ethan Furmanc16595e2016-09-10 23:36:59 -07001584 def test_auto_number(self):
1585 class Color(Enum):
1586 red = auto()
1587 blue = auto()
1588 green = auto()
1589
1590 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1591 self.assertEqual(Color.red.value, 1)
1592 self.assertEqual(Color.blue.value, 2)
1593 self.assertEqual(Color.green.value, 3)
1594
1595 def test_auto_name(self):
1596 class Color(Enum):
1597 def _generate_next_value_(name, start, count, last):
1598 return name
1599 red = auto()
1600 blue = auto()
1601 green = auto()
1602
1603 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1604 self.assertEqual(Color.red.value, 'red')
1605 self.assertEqual(Color.blue.value, 'blue')
1606 self.assertEqual(Color.green.value, 'green')
1607
1608 def test_auto_name_inherit(self):
1609 class AutoNameEnum(Enum):
1610 def _generate_next_value_(name, start, count, last):
1611 return name
1612 class Color(AutoNameEnum):
1613 red = auto()
1614 blue = auto()
1615 green = auto()
1616
1617 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1618 self.assertEqual(Color.red.value, 'red')
1619 self.assertEqual(Color.blue.value, 'blue')
1620 self.assertEqual(Color.green.value, 'green')
1621
1622 def test_auto_garbage(self):
1623 class Color(Enum):
1624 red = 'red'
1625 blue = auto()
1626 self.assertEqual(Color.blue.value, 1)
1627
1628 def test_auto_garbage_corrected(self):
1629 class Color(Enum):
1630 red = 'red'
1631 blue = 2
1632 green = auto()
1633
1634 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1635 self.assertEqual(Color.red.value, 'red')
1636 self.assertEqual(Color.blue.value, 2)
1637 self.assertEqual(Color.green.value, 3)
1638
Ethan Furman3515dcc2016-09-18 13:15:41 -07001639 def test_duplicate_auto(self):
1640 class Dupes(Enum):
1641 first = primero = auto()
1642 second = auto()
1643 third = auto()
1644 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1645
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001646
Ethan Furmane8e61272016-08-20 07:19:31 -07001647class TestOrder(unittest.TestCase):
1648
1649 def test_same_members(self):
1650 class Color(Enum):
1651 _order_ = 'red green blue'
1652 red = 1
1653 green = 2
1654 blue = 3
1655
1656 def test_same_members_with_aliases(self):
1657 class Color(Enum):
1658 _order_ = 'red green blue'
1659 red = 1
1660 green = 2
1661 blue = 3
1662 verde = green
1663
1664 def test_same_members_wrong_order(self):
1665 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1666 class Color(Enum):
1667 _order_ = 'red green blue'
1668 red = 1
1669 blue = 3
1670 green = 2
1671
1672 def test_order_has_extra_members(self):
1673 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1674 class Color(Enum):
1675 _order_ = 'red green blue purple'
1676 red = 1
1677 green = 2
1678 blue = 3
1679
1680 def test_order_has_extra_members_with_aliases(self):
1681 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1682 class Color(Enum):
1683 _order_ = 'red green blue purple'
1684 red = 1
1685 green = 2
1686 blue = 3
1687 verde = green
1688
1689 def test_enum_has_extra_members(self):
1690 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1691 class Color(Enum):
1692 _order_ = 'red green blue'
1693 red = 1
1694 green = 2
1695 blue = 3
1696 purple = 4
1697
1698 def test_enum_has_extra_members_with_aliases(self):
1699 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1700 class Color(Enum):
1701 _order_ = 'red green blue'
1702 red = 1
1703 green = 2
1704 blue = 3
1705 purple = 4
1706 verde = green
1707
1708
Ethan Furman65a5a472016-09-01 23:55:19 -07001709class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001710 """Tests of the Flags."""
1711
Ethan Furman65a5a472016-09-01 23:55:19 -07001712 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001713 R, W, X = 4, 2, 1
1714
Ethan Furman65a5a472016-09-01 23:55:19 -07001715 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001716 RO = 0
1717 WO = 1
1718 RW = 2
1719 AC = 3
1720 CE = 1<<19
1721
1722 def test_str(self):
1723 Perm = self.Perm
1724 self.assertEqual(str(Perm.R), 'Perm.R')
1725 self.assertEqual(str(Perm.W), 'Perm.W')
1726 self.assertEqual(str(Perm.X), 'Perm.X')
1727 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1728 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1729 self.assertEqual(str(Perm(0)), 'Perm.0')
1730 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1731 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1732 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1733 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1734 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1735 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1736
1737 Open = self.Open
1738 self.assertEqual(str(Open.RO), 'Open.RO')
1739 self.assertEqual(str(Open.WO), 'Open.WO')
1740 self.assertEqual(str(Open.AC), 'Open.AC')
1741 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1742 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001743 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001744 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1745 self.assertEqual(str(~Open.AC), 'Open.CE')
1746 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1747 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1748
1749 def test_repr(self):
1750 Perm = self.Perm
1751 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1752 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1753 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1754 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1755 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001756 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001757 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1758 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1759 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1760 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001761 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001762 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1763
1764 Open = self.Open
1765 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1766 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1767 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1768 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1769 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001770 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001771 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
1772 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
1773 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
1774 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
1775
1776 def test_or(self):
1777 Perm = self.Perm
1778 for i in Perm:
1779 for j in Perm:
1780 self.assertEqual((i | j), Perm(i.value | j.value))
1781 self.assertEqual((i | j).value, i.value | j.value)
1782 self.assertIs(type(i | j), Perm)
1783 for i in Perm:
1784 self.assertIs(i | i, i)
1785 Open = self.Open
1786 self.assertIs(Open.RO | Open.CE, Open.CE)
1787
1788 def test_and(self):
1789 Perm = self.Perm
1790 RW = Perm.R | Perm.W
1791 RX = Perm.R | Perm.X
1792 WX = Perm.W | Perm.X
1793 RWX = Perm.R | Perm.W | Perm.X
1794 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1795 for i in values:
1796 for j in values:
1797 self.assertEqual((i & j).value, i.value & j.value)
1798 self.assertIs(type(i & j), Perm)
1799 for i in Perm:
1800 self.assertIs(i & i, i)
1801 self.assertIs(i & RWX, i)
1802 self.assertIs(RWX & i, i)
1803 Open = self.Open
1804 self.assertIs(Open.RO & Open.CE, Open.RO)
1805
1806 def test_xor(self):
1807 Perm = self.Perm
1808 for i in Perm:
1809 for j in Perm:
1810 self.assertEqual((i ^ j).value, i.value ^ j.value)
1811 self.assertIs(type(i ^ j), Perm)
1812 for i in Perm:
1813 self.assertIs(i ^ Perm(0), i)
1814 self.assertIs(Perm(0) ^ i, i)
1815 Open = self.Open
1816 self.assertIs(Open.RO ^ Open.CE, Open.CE)
1817 self.assertIs(Open.CE ^ Open.CE, Open.RO)
1818
1819 def test_invert(self):
1820 Perm = self.Perm
1821 RW = Perm.R | Perm.W
1822 RX = Perm.R | Perm.X
1823 WX = Perm.W | Perm.X
1824 RWX = Perm.R | Perm.W | Perm.X
1825 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1826 for i in values:
1827 self.assertIs(type(~i), Perm)
1828 self.assertEqual(~~i, i)
1829 for i in Perm:
1830 self.assertIs(~~i, i)
1831 Open = self.Open
1832 self.assertIs(Open.WO & ~Open.WO, Open.RO)
1833 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
1834
Ethan Furman25d94bb2016-09-02 16:32:32 -07001835 def test_bool(self):
1836 Perm = self.Perm
1837 for f in Perm:
1838 self.assertTrue(f)
1839 Open = self.Open
1840 for f in Open:
1841 self.assertEqual(bool(f.value), bool(f))
1842
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001843 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001844 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001845 lst = list(Perm)
1846 self.assertEqual(len(lst), len(Perm))
1847 self.assertEqual(len(Perm), 3, Perm)
1848 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1849 for i, n in enumerate('R W X'.split()):
1850 v = 1<<i
1851 e = Perm(v)
1852 self.assertEqual(e.value, v)
1853 self.assertEqual(type(e.value), int)
1854 self.assertEqual(e.name, n)
1855 self.assertIn(e, Perm)
1856 self.assertIs(type(e), Perm)
1857
1858 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001859 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001860 lst = list(Perm)
1861 self.assertEqual(len(lst), len(Perm))
1862 self.assertEqual(len(Perm), 3, Perm)
1863 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1864 for i, n in enumerate('R W X'.split()):
1865 v = 8<<i
1866 e = Perm(v)
1867 self.assertEqual(e.value, v)
1868 self.assertEqual(type(e.value), int)
1869 self.assertEqual(e.name, n)
1870 self.assertIn(e, Perm)
1871 self.assertIs(type(e), Perm)
1872
1873 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001874 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001875 lst = list(Perm)
1876 self.assertEqual(len(lst), len(Perm))
1877 self.assertEqual(len(Perm), 3, Perm)
1878 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1879 for i, n in enumerate('R W X'.split()):
1880 v = 1<<i
1881 e = Perm(v)
1882 self.assertEqual(e.value, v)
1883 self.assertEqual(type(e.value), int)
1884 self.assertEqual(e.name, n)
1885 self.assertIn(e, Perm)
1886 self.assertIs(type(e), Perm)
1887
1888 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001889 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001890 lst = list(Perm)
1891 self.assertEqual(len(lst), len(Perm))
1892 self.assertEqual(len(Perm), 3, Perm)
1893 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1894 for i, n in enumerate('R W X'.split()):
1895 v = 1<<(2*i+1)
1896 e = Perm(v)
1897 self.assertEqual(e.value, v)
1898 self.assertEqual(type(e.value), int)
1899 self.assertEqual(e.name, n)
1900 self.assertIn(e, Perm)
1901 self.assertIs(type(e), Perm)
1902
1903 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001904 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001905 lst = list(Perm)
1906 self.assertEqual(len(lst), len(Perm))
1907 self.assertEqual(len(Perm), 3, Perm)
1908 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1909 for i, n in enumerate('R W X'.split()):
1910 v = 1<<(2*i+1)
1911 e = Perm(v)
1912 self.assertEqual(e.value, v)
1913 self.assertEqual(type(e.value), int)
1914 self.assertEqual(e.name, n)
1915 self.assertIn(e, Perm)
1916 self.assertIs(type(e), Perm)
1917
Ethan Furman65a5a472016-09-01 23:55:19 -07001918 def test_pickle(self):
1919 if isinstance(FlagStooges, Exception):
1920 raise FlagStooges
1921 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
1922 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001923
Ethan Furman65a5a472016-09-01 23:55:19 -07001924 def test_containment(self):
1925 Perm = self.Perm
1926 R, W, X = Perm
1927 RW = R | W
1928 RX = R | X
1929 WX = W | X
1930 RWX = R | W | X
1931 self.assertTrue(R in RW)
1932 self.assertTrue(R in RX)
1933 self.assertTrue(R in RWX)
1934 self.assertTrue(W in RW)
1935 self.assertTrue(W in WX)
1936 self.assertTrue(W in RWX)
1937 self.assertTrue(X in RX)
1938 self.assertTrue(X in WX)
1939 self.assertTrue(X in RWX)
1940 self.assertFalse(R in WX)
1941 self.assertFalse(W in RX)
1942 self.assertFalse(X in RW)
1943
Ethan Furmanc16595e2016-09-10 23:36:59 -07001944 def test_auto_number(self):
1945 class Color(Flag):
1946 red = auto()
1947 blue = auto()
1948 green = auto()
1949
1950 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1951 self.assertEqual(Color.red.value, 1)
1952 self.assertEqual(Color.blue.value, 2)
1953 self.assertEqual(Color.green.value, 4)
1954
1955 def test_auto_number_garbage(self):
1956 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
1957 class Color(Flag):
1958 red = 'not an int'
1959 blue = auto()
1960
Ethan Furman3515dcc2016-09-18 13:15:41 -07001961 def test_cascading_failure(self):
1962 class Bizarre(Flag):
1963 c = 3
1964 d = 4
1965 f = 6
1966 # Bizarre.c | Bizarre.d
1967 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
1968 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
1969 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
1970 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
1971 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
1972 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
1973
1974 def test_duplicate_auto(self):
1975 class Dupes(Enum):
1976 first = primero = auto()
1977 second = auto()
1978 third = auto()
1979 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1980
1981 def test_bizarre(self):
1982 class Bizarre(Flag):
1983 b = 3
1984 c = 4
1985 d = 6
1986 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
1987
Ethan Furman28cf6632017-01-24 12:12:06 -08001988 @support.reap_threads
1989 def test_unique_composite(self):
1990 # override __eq__ to be identity only
1991 class TestFlag(Flag):
1992 one = auto()
1993 two = auto()
1994 three = auto()
1995 four = auto()
1996 five = auto()
1997 six = auto()
1998 seven = auto()
1999 eight = auto()
2000 def __eq__(self, other):
2001 return self is other
2002 def __hash__(self):
2003 return hash(self._value_)
2004 # have multiple threads competing to complete the composite members
2005 seen = set()
2006 failed = False
2007 def cycle_enum():
2008 nonlocal failed
2009 try:
2010 for i in range(256):
2011 seen.add(TestFlag(i))
2012 except Exception:
2013 failed = True
2014 threads = [
2015 threading.Thread(target=cycle_enum)
2016 for _ in range(8)
2017 ]
2018 with support.start_threads(threads):
2019 pass
2020 # check that only 248 members were created
2021 self.assertFalse(
2022 failed,
2023 'at least one thread failed while creating composite members')
2024 self.assertEqual(256, len(seen), 'too many composite members created')
2025
Ethan Furmanc16595e2016-09-10 23:36:59 -07002026
Ethan Furman65a5a472016-09-01 23:55:19 -07002027class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002028 """Tests of the IntFlags."""
2029
Ethan Furman65a5a472016-09-01 23:55:19 -07002030 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002031 X = 1 << 0
2032 W = 1 << 1
2033 R = 1 << 2
2034
Ethan Furman65a5a472016-09-01 23:55:19 -07002035 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002036 RO = 0
2037 WO = 1
2038 RW = 2
2039 AC = 3
2040 CE = 1<<19
2041
Ethan Furman3515dcc2016-09-18 13:15:41 -07002042 def test_type(self):
2043 Perm = self.Perm
2044 Open = self.Open
2045 for f in Perm:
2046 self.assertTrue(isinstance(f, Perm))
2047 self.assertEqual(f, f.value)
2048 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2049 self.assertEqual(Perm.W | Perm.X, 3)
2050 for f in Open:
2051 self.assertTrue(isinstance(f, Open))
2052 self.assertEqual(f, f.value)
2053 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2054 self.assertEqual(Open.WO | Open.RW, 3)
2055
2056
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002057 def test_str(self):
2058 Perm = self.Perm
2059 self.assertEqual(str(Perm.R), 'Perm.R')
2060 self.assertEqual(str(Perm.W), 'Perm.W')
2061 self.assertEqual(str(Perm.X), 'Perm.X')
2062 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2063 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2064 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2065 self.assertEqual(str(Perm(0)), 'Perm.0')
2066 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002067 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2068 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2069 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2070 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002071 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002072 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2073 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2074 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002075
2076 Open = self.Open
2077 self.assertEqual(str(Open.RO), 'Open.RO')
2078 self.assertEqual(str(Open.WO), 'Open.WO')
2079 self.assertEqual(str(Open.AC), 'Open.AC')
2080 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2081 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2082 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002083 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2084 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2085 self.assertEqual(str(~Open.AC), 'Open.CE')
2086 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2087 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2088 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002089
2090 def test_repr(self):
2091 Perm = self.Perm
2092 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2093 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2094 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2095 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2096 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2097 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002098 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2099 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002100 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2101 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2102 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2103 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002104 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002105 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2106 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2107 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002108
2109 Open = self.Open
2110 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2111 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2112 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2113 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2114 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002115 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002116 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2117 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2118 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2119 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2120 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2121 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002122
2123 def test_or(self):
2124 Perm = self.Perm
2125 for i in Perm:
2126 for j in Perm:
2127 self.assertEqual(i | j, i.value | j.value)
2128 self.assertEqual((i | j).value, i.value | j.value)
2129 self.assertIs(type(i | j), Perm)
2130 for j in range(8):
2131 self.assertEqual(i | j, i.value | j)
2132 self.assertEqual((i | j).value, i.value | j)
2133 self.assertIs(type(i | j), Perm)
2134 self.assertEqual(j | i, j | i.value)
2135 self.assertEqual((j | i).value, j | i.value)
2136 self.assertIs(type(j | i), Perm)
2137 for i in Perm:
2138 self.assertIs(i | i, i)
2139 self.assertIs(i | 0, i)
2140 self.assertIs(0 | i, i)
2141 Open = self.Open
2142 self.assertIs(Open.RO | Open.CE, Open.CE)
2143
2144 def test_and(self):
2145 Perm = self.Perm
2146 RW = Perm.R | Perm.W
2147 RX = Perm.R | Perm.X
2148 WX = Perm.W | Perm.X
2149 RWX = Perm.R | Perm.W | Perm.X
2150 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2151 for i in values:
2152 for j in values:
2153 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2154 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2155 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2156 for j in range(8):
2157 self.assertEqual(i & j, i.value & j)
2158 self.assertEqual((i & j).value, i.value & j)
2159 self.assertIs(type(i & j), Perm)
2160 self.assertEqual(j & i, j & i.value)
2161 self.assertEqual((j & i).value, j & i.value)
2162 self.assertIs(type(j & i), Perm)
2163 for i in Perm:
2164 self.assertIs(i & i, i)
2165 self.assertIs(i & 7, i)
2166 self.assertIs(7 & i, i)
2167 Open = self.Open
2168 self.assertIs(Open.RO & Open.CE, Open.RO)
2169
2170 def test_xor(self):
2171 Perm = self.Perm
2172 for i in Perm:
2173 for j in Perm:
2174 self.assertEqual(i ^ j, i.value ^ j.value)
2175 self.assertEqual((i ^ j).value, i.value ^ j.value)
2176 self.assertIs(type(i ^ j), Perm)
2177 for j in range(8):
2178 self.assertEqual(i ^ j, i.value ^ j)
2179 self.assertEqual((i ^ j).value, i.value ^ j)
2180 self.assertIs(type(i ^ j), Perm)
2181 self.assertEqual(j ^ i, j ^ i.value)
2182 self.assertEqual((j ^ i).value, j ^ i.value)
2183 self.assertIs(type(j ^ i), Perm)
2184 for i in Perm:
2185 self.assertIs(i ^ 0, i)
2186 self.assertIs(0 ^ i, i)
2187 Open = self.Open
2188 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2189 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2190
2191 def test_invert(self):
2192 Perm = self.Perm
2193 RW = Perm.R | Perm.W
2194 RX = Perm.R | Perm.X
2195 WX = Perm.W | Perm.X
2196 RWX = Perm.R | Perm.W | Perm.X
2197 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2198 for i in values:
2199 self.assertEqual(~i, ~i.value)
2200 self.assertEqual((~i).value, ~i.value)
2201 self.assertIs(type(~i), Perm)
2202 self.assertEqual(~~i, i)
2203 for i in Perm:
2204 self.assertIs(~~i, i)
2205 Open = self.Open
2206 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2207 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2208
2209 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002210 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002211 lst = list(Perm)
2212 self.assertEqual(len(lst), len(Perm))
2213 self.assertEqual(len(Perm), 3, Perm)
2214 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2215 for i, n in enumerate('R W X'.split()):
2216 v = 1<<i
2217 e = Perm(v)
2218 self.assertEqual(e.value, v)
2219 self.assertEqual(type(e.value), int)
2220 self.assertEqual(e, v)
2221 self.assertEqual(e.name, n)
2222 self.assertIn(e, Perm)
2223 self.assertIs(type(e), Perm)
2224
2225 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002226 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002227 lst = list(Perm)
2228 self.assertEqual(len(lst), len(Perm))
2229 self.assertEqual(len(Perm), 3, Perm)
2230 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2231 for i, n in enumerate('R W X'.split()):
2232 v = 8<<i
2233 e = Perm(v)
2234 self.assertEqual(e.value, v)
2235 self.assertEqual(type(e.value), int)
2236 self.assertEqual(e, v)
2237 self.assertEqual(e.name, n)
2238 self.assertIn(e, Perm)
2239 self.assertIs(type(e), Perm)
2240
2241 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002242 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002243 lst = list(Perm)
2244 self.assertEqual(len(lst), len(Perm))
2245 self.assertEqual(len(Perm), 3, Perm)
2246 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2247 for i, n in enumerate('R W X'.split()):
2248 v = 1<<i
2249 e = Perm(v)
2250 self.assertEqual(e.value, v)
2251 self.assertEqual(type(e.value), int)
2252 self.assertEqual(e, v)
2253 self.assertEqual(e.name, n)
2254 self.assertIn(e, Perm)
2255 self.assertIs(type(e), Perm)
2256
2257 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002258 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002259 lst = list(Perm)
2260 self.assertEqual(len(lst), len(Perm))
2261 self.assertEqual(len(Perm), 3, Perm)
2262 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2263 for i, n in enumerate('R W X'.split()):
2264 v = 1<<(2*i+1)
2265 e = Perm(v)
2266 self.assertEqual(e.value, v)
2267 self.assertEqual(type(e.value), int)
2268 self.assertEqual(e, v)
2269 self.assertEqual(e.name, n)
2270 self.assertIn(e, Perm)
2271 self.assertIs(type(e), Perm)
2272
2273 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002274 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002275 lst = list(Perm)
2276 self.assertEqual(len(lst), len(Perm))
2277 self.assertEqual(len(Perm), 3, Perm)
2278 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2279 for i, n in enumerate('R W X'.split()):
2280 v = 1<<(2*i+1)
2281 e = Perm(v)
2282 self.assertEqual(e.value, v)
2283 self.assertEqual(type(e.value), int)
2284 self.assertEqual(e, v)
2285 self.assertEqual(e.name, n)
2286 self.assertIn(e, Perm)
2287 self.assertIs(type(e), Perm)
2288
2289
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002290 def test_programatic_function_from_empty_list(self):
2291 Perm = enum.IntFlag('Perm', [])
2292 lst = list(Perm)
2293 self.assertEqual(len(lst), len(Perm))
2294 self.assertEqual(len(Perm), 0, Perm)
2295 Thing = enum.Enum('Thing', [])
2296 lst = list(Thing)
2297 self.assertEqual(len(lst), len(Thing))
2298 self.assertEqual(len(Thing), 0, Thing)
2299
2300
2301 def test_programatic_function_from_empty_tuple(self):
2302 Perm = enum.IntFlag('Perm', ())
2303 lst = list(Perm)
2304 self.assertEqual(len(lst), len(Perm))
2305 self.assertEqual(len(Perm), 0, Perm)
2306 Thing = enum.Enum('Thing', ())
2307 self.assertEqual(len(lst), len(Thing))
2308 self.assertEqual(len(Thing), 0, Thing)
2309
Ethan Furman65a5a472016-09-01 23:55:19 -07002310 def test_containment(self):
2311 Perm = self.Perm
2312 R, W, X = Perm
2313 RW = R | W
2314 RX = R | X
2315 WX = W | X
2316 RWX = R | W | X
2317 self.assertTrue(R in RW)
2318 self.assertTrue(R in RX)
2319 self.assertTrue(R in RWX)
2320 self.assertTrue(W in RW)
2321 self.assertTrue(W in WX)
2322 self.assertTrue(W in RWX)
2323 self.assertTrue(X in RX)
2324 self.assertTrue(X in WX)
2325 self.assertTrue(X in RWX)
2326 self.assertFalse(R in WX)
2327 self.assertFalse(W in RX)
2328 self.assertFalse(X in RW)
2329
Ethan Furman25d94bb2016-09-02 16:32:32 -07002330 def test_bool(self):
2331 Perm = self.Perm
2332 for f in Perm:
2333 self.assertTrue(f)
2334 Open = self.Open
2335 for f in Open:
2336 self.assertEqual(bool(f.value), bool(f))
2337
Ethan Furman28cf6632017-01-24 12:12:06 -08002338 @support.reap_threads
2339 def test_unique_composite(self):
2340 # override __eq__ to be identity only
2341 class TestFlag(IntFlag):
2342 one = auto()
2343 two = auto()
2344 three = auto()
2345 four = auto()
2346 five = auto()
2347 six = auto()
2348 seven = auto()
2349 eight = auto()
2350 def __eq__(self, other):
2351 return self is other
2352 def __hash__(self):
2353 return hash(self._value_)
2354 # have multiple threads competing to complete the composite members
2355 seen = set()
2356 failed = False
2357 def cycle_enum():
2358 nonlocal failed
2359 try:
2360 for i in range(256):
2361 seen.add(TestFlag(i))
2362 except Exception:
2363 failed = True
2364 threads = [
2365 threading.Thread(target=cycle_enum)
2366 for _ in range(8)
2367 ]
2368 with support.start_threads(threads):
2369 pass
2370 # check that only 248 members were created
2371 self.assertFalse(
2372 failed,
2373 'at least one thread failed while creating composite members')
2374 self.assertEqual(256, len(seen), 'too many composite members created')
2375
2376
Ethan Furmanf24bb352013-07-18 17:05:39 -07002377class TestUnique(unittest.TestCase):
2378
2379 def test_unique_clean(self):
2380 @unique
2381 class Clean(Enum):
2382 one = 1
2383 two = 'dos'
2384 tres = 4.0
2385 @unique
2386 class Cleaner(IntEnum):
2387 single = 1
2388 double = 2
2389 triple = 3
2390
2391 def test_unique_dirty(self):
2392 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2393 @unique
2394 class Dirty(Enum):
2395 one = 1
2396 two = 'dos'
2397 tres = 1
2398 with self.assertRaisesRegex(
2399 ValueError,
2400 'double.*single.*turkey.*triple',
2401 ):
2402 @unique
2403 class Dirtier(IntEnum):
2404 single = 1
2405 double = 1
2406 triple = 3
2407 turkey = 3
2408
Ethan Furman3803ad42016-05-01 10:03:53 -07002409 def test_unique_with_name(self):
2410 @unique
2411 class Silly(Enum):
2412 one = 1
2413 two = 'dos'
2414 name = 3
2415 @unique
2416 class Sillier(IntEnum):
2417 single = 1
2418 name = 2
2419 triple = 3
2420 value = 4
2421
Ethan Furmanf24bb352013-07-18 17:05:39 -07002422
Ethan Furman3323da92015-04-11 09:39:59 -07002423expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002424Help on class Color in module %s:
2425
2426class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002427 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2428 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002429 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002430 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002431 | Method resolution order:
2432 | Color
2433 | enum.Enum
2434 | builtins.object
2435 |\x20\x20
2436 | Data and other attributes defined here:
2437 |\x20\x20
2438 | blue = <Color.blue: 3>
2439 |\x20\x20
2440 | green = <Color.green: 2>
2441 |\x20\x20
2442 | red = <Color.red: 1>
2443 |\x20\x20
2444 | ----------------------------------------------------------------------
2445 | Data descriptors inherited from enum.Enum:
2446 |\x20\x20
2447 | name
2448 | The name of the Enum member.
2449 |\x20\x20
2450 | value
2451 | The value of the Enum member.
2452 |\x20\x20
2453 | ----------------------------------------------------------------------
2454 | Data descriptors inherited from enum.EnumMeta:
2455 |\x20\x20
2456 | __members__
2457 | Returns a mapping of member name->value.
2458 |\x20\x20\x20\x20\x20\x20
2459 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002460 | is a read-only view of the internal mapping."""
2461
2462expected_help_output_without_docs = """\
2463Help on class Color in module %s:
2464
2465class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002466 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2467 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002468 | Method resolution order:
2469 | Color
2470 | enum.Enum
2471 | builtins.object
2472 |\x20\x20
2473 | Data and other attributes defined here:
2474 |\x20\x20
2475 | blue = <Color.blue: 3>
2476 |\x20\x20
2477 | green = <Color.green: 2>
2478 |\x20\x20
2479 | red = <Color.red: 1>
2480 |\x20\x20
2481 | ----------------------------------------------------------------------
2482 | Data descriptors inherited from enum.Enum:
2483 |\x20\x20
2484 | name
2485 |\x20\x20
2486 | value
2487 |\x20\x20
2488 | ----------------------------------------------------------------------
2489 | Data descriptors inherited from enum.EnumMeta:
2490 |\x20\x20
2491 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002492
2493class TestStdLib(unittest.TestCase):
2494
Ethan Furman48a724f2015-04-11 23:23:06 -07002495 maxDiff = None
2496
Ethan Furman5875d742013-10-21 20:45:55 -07002497 class Color(Enum):
2498 red = 1
2499 green = 2
2500 blue = 3
2501
2502 def test_pydoc(self):
2503 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002504 if StrEnum.__doc__ is None:
2505 expected_text = expected_help_output_without_docs % __name__
2506 else:
2507 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002508 output = StringIO()
2509 helper = pydoc.Helper(output=output)
2510 helper(self.Color)
2511 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002512 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002513
2514 def test_inspect_getmembers(self):
2515 values = dict((
2516 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002517 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002518 ('__members__', self.Color.__members__),
2519 ('__module__', __name__),
2520 ('blue', self.Color.blue),
2521 ('green', self.Color.green),
2522 ('name', Enum.__dict__['name']),
2523 ('red', self.Color.red),
2524 ('value', Enum.__dict__['value']),
2525 ))
2526 result = dict(inspect.getmembers(self.Color))
2527 self.assertEqual(values.keys(), result.keys())
2528 failed = False
2529 for k in values.keys():
2530 if result[k] != values[k]:
2531 print()
2532 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2533 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2534 failed = True
2535 if failed:
2536 self.fail("result does not equal expected, see print above")
2537
2538 def test_inspect_classify_class_attrs(self):
2539 # indirectly test __objclass__
2540 from inspect import Attribute
2541 values = [
2542 Attribute(name='__class__', kind='data',
2543 defining_class=object, object=EnumMeta),
2544 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002545 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002546 Attribute(name='__members__', kind='property',
2547 defining_class=EnumMeta, object=EnumMeta.__members__),
2548 Attribute(name='__module__', kind='data',
2549 defining_class=self.Color, object=__name__),
2550 Attribute(name='blue', kind='data',
2551 defining_class=self.Color, object=self.Color.blue),
2552 Attribute(name='green', kind='data',
2553 defining_class=self.Color, object=self.Color.green),
2554 Attribute(name='red', kind='data',
2555 defining_class=self.Color, object=self.Color.red),
2556 Attribute(name='name', kind='data',
2557 defining_class=Enum, object=Enum.__dict__['name']),
2558 Attribute(name='value', kind='data',
2559 defining_class=Enum, object=Enum.__dict__['value']),
2560 ]
2561 values.sort(key=lambda item: item.name)
2562 result = list(inspect.classify_class_attrs(self.Color))
2563 result.sort(key=lambda item: item.name)
2564 failed = False
2565 for v, r in zip(values, result):
2566 if r != v:
2567 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2568 failed = True
2569 if failed:
2570 self.fail("result does not equal expected, see print above")
2571
Martin Panter19e69c52015-11-14 12:46:42 +00002572
2573class MiscTestCase(unittest.TestCase):
2574 def test__all__(self):
2575 support.check__all__(self, enum)
2576
2577
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002578# These are unordered here on purpose to ensure that declaration order
2579# makes no difference.
2580CONVERT_TEST_NAME_D = 5
2581CONVERT_TEST_NAME_C = 5
2582CONVERT_TEST_NAME_B = 5
2583CONVERT_TEST_NAME_A = 5 # This one should sort first.
2584CONVERT_TEST_NAME_E = 5
2585CONVERT_TEST_NAME_F = 5
2586
2587class TestIntEnumConvert(unittest.TestCase):
2588 def test_convert_value_lookup_priority(self):
2589 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002590 'UnittestConvert',
2591 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002592 filter=lambda x: x.startswith('CONVERT_TEST_'))
2593 # We don't want the reverse lookup value to vary when there are
2594 # multiple possible names for a given value. It should always
2595 # report the first lexigraphical name in that case.
2596 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2597
2598 def test_convert(self):
2599 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002600 'UnittestConvert',
2601 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002602 filter=lambda x: x.startswith('CONVERT_TEST_'))
2603 # Ensure that test_type has all of the desired names and values.
2604 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2605 test_type.CONVERT_TEST_NAME_A)
2606 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2607 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2608 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2609 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2610 # Ensure that test_type only picked up names matching the filter.
2611 self.assertEqual([name for name in dir(test_type)
2612 if name[0:2] not in ('CO', '__')],
2613 [], msg='Names other than CONVERT_TEST_* found.')
2614
2615
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002616if __name__ == '__main__':
2617 unittest.main()