blob: 97559712b1dc2ccaa519bff9df7c49a2967b961d [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 Furmana4b1bb42018-01-22 07:56:37 -080011from datetime import timedelta
Ethan Furman28cf6632017-01-24 12:12:06 -080012
Ethan Furmana4b1bb42018-01-22 07:56:37 -080013try:
14 import threading
15except ImportError:
16 threading = None
Ethan Furman6b3d64a2013-06-14 16:55:46 -070017
18# for pickle tests
19try:
20 class Stooges(Enum):
21 LARRY = 1
22 CURLY = 2
23 MOE = 3
24except Exception as exc:
25 Stooges = exc
26
27try:
28 class IntStooges(int, Enum):
29 LARRY = 1
30 CURLY = 2
31 MOE = 3
32except Exception as exc:
33 IntStooges = exc
34
35try:
36 class FloatStooges(float, Enum):
37 LARRY = 1.39
38 CURLY = 2.72
39 MOE = 3.142596
40except Exception as exc:
41 FloatStooges = exc
42
Ethan Furman65a5a472016-09-01 23:55:19 -070043try:
44 class FlagStooges(Flag):
45 LARRY = 1
46 CURLY = 2
47 MOE = 3
48except Exception as exc:
49 FlagStooges = exc
50
Ethan Furman6b3d64a2013-06-14 16:55:46 -070051# for pickle test and subclass tests
52try:
53 class StrEnum(str, Enum):
54 'accepts only string values'
55 class Name(StrEnum):
56 BDFL = 'Guido van Rossum'
57 FLUFL = 'Barry Warsaw'
58except Exception as exc:
59 Name = exc
60
61try:
62 Question = Enum('Question', 'who what when where why', module=__name__)
63except Exception as exc:
64 Question = exc
65
66try:
67 Answer = Enum('Answer', 'him this then there because')
68except Exception as exc:
69 Answer = exc
70
Ethan Furmanca1b7942014-02-08 11:36:27 -080071try:
72 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
73except Exception as exc:
74 Theory = exc
75
Ethan Furman6b3d64a2013-06-14 16:55:46 -070076# for doctests
77try:
78 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080079 TOMATO = 1
80 BANANA = 2
81 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070082except Exception:
83 pass
84
Serhiy Storchakae50e7802015-03-31 16:56:49 +030085def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080086 if target is None:
87 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030088 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080089 assertion(loads(dumps(source, protocol=protocol)), target)
90
Serhiy Storchakae50e7802015-03-31 16:56:49 +030091def test_pickle_exception(assertion, exception, obj):
92 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080093 with assertion(exception):
94 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070095
96class TestHelpers(unittest.TestCase):
97 # _is_descriptor, _is_sunder, _is_dunder
98
99 def test_is_descriptor(self):
100 class foo:
101 pass
102 for attr in ('__get__','__set__','__delete__'):
103 obj = foo()
104 self.assertFalse(enum._is_descriptor(obj))
105 setattr(obj, attr, 1)
106 self.assertTrue(enum._is_descriptor(obj))
107
108 def test_is_sunder(self):
109 for s in ('_a_', '_aa_'):
110 self.assertTrue(enum._is_sunder(s))
111
112 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
113 '__', '___', '____', '_____',):
114 self.assertFalse(enum._is_sunder(s))
115
116 def test_is_dunder(self):
117 for s in ('__a__', '__aa__'):
118 self.assertTrue(enum._is_dunder(s))
119 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
120 '__', '___', '____', '_____',):
121 self.assertFalse(enum._is_dunder(s))
122
Ethan Furmanc16595e2016-09-10 23:36:59 -0700123# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700124
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700125class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800126
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700127 def setUp(self):
128 class Season(Enum):
129 SPRING = 1
130 SUMMER = 2
131 AUTUMN = 3
132 WINTER = 4
133 self.Season = Season
134
Ethan Furmanec15a822013-08-31 19:17:41 -0700135 class Konstants(float, Enum):
136 E = 2.7182818
137 PI = 3.1415926
138 TAU = 2 * PI
139 self.Konstants = Konstants
140
141 class Grades(IntEnum):
142 A = 5
143 B = 4
144 C = 3
145 D = 2
146 F = 0
147 self.Grades = Grades
148
149 class Directional(str, Enum):
150 EAST = 'east'
151 WEST = 'west'
152 NORTH = 'north'
153 SOUTH = 'south'
154 self.Directional = Directional
155
156 from datetime import date
157 class Holiday(date, Enum):
158 NEW_YEAR = 2013, 1, 1
159 IDES_OF_MARCH = 2013, 3, 15
160 self.Holiday = Holiday
161
Ethan Furman388a3922013-08-12 06:51:41 -0700162 def test_dir_on_class(self):
163 Season = self.Season
164 self.assertEqual(
165 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700166 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700167 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
168 )
169
170 def test_dir_on_item(self):
171 Season = self.Season
172 self.assertEqual(
173 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700174 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700175 )
176
Ethan Furmanc850f342013-09-15 16:59:35 -0700177 def test_dir_with_added_behavior(self):
178 class Test(Enum):
179 this = 'that'
180 these = 'those'
181 def wowser(self):
182 return ("Wowser! I'm %s!" % self.name)
183 self.assertEqual(
184 set(dir(Test)),
185 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
186 )
187 self.assertEqual(
188 set(dir(Test.this)),
189 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
190 )
191
Ethan Furman0ae550b2014-10-14 08:58:32 -0700192 def test_dir_on_sub_with_behavior_on_super(self):
193 # see issue22506
194 class SuperEnum(Enum):
195 def invisible(self):
196 return "did you see me?"
197 class SubEnum(SuperEnum):
198 sample = 5
199 self.assertEqual(
200 set(dir(SubEnum.sample)),
201 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
202 )
203
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700204 def test_enum_in_enum_out(self):
205 Season = self.Season
206 self.assertIs(Season(Season.WINTER), Season.WINTER)
207
208 def test_enum_value(self):
209 Season = self.Season
210 self.assertEqual(Season.SPRING.value, 1)
211
212 def test_intenum_value(self):
213 self.assertEqual(IntStooges.CURLY.value, 2)
214
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700215 def test_enum(self):
216 Season = self.Season
217 lst = list(Season)
218 self.assertEqual(len(lst), len(Season))
219 self.assertEqual(len(Season), 4, Season)
220 self.assertEqual(
221 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
222
223 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
224 e = Season(i)
225 self.assertEqual(e, getattr(Season, season))
226 self.assertEqual(e.value, i)
227 self.assertNotEqual(e, i)
228 self.assertEqual(e.name, season)
229 self.assertIn(e, Season)
230 self.assertIs(type(e), Season)
231 self.assertIsInstance(e, Season)
232 self.assertEqual(str(e), 'Season.' + season)
233 self.assertEqual(
234 repr(e),
235 '<Season.{0}: {1}>'.format(season, i),
236 )
237
238 def test_value_name(self):
239 Season = self.Season
240 self.assertEqual(Season.SPRING.name, 'SPRING')
241 self.assertEqual(Season.SPRING.value, 1)
242 with self.assertRaises(AttributeError):
243 Season.SPRING.name = 'invierno'
244 with self.assertRaises(AttributeError):
245 Season.SPRING.value = 2
246
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700247 def test_changing_member(self):
248 Season = self.Season
249 with self.assertRaises(AttributeError):
250 Season.WINTER = 'really cold'
251
Ethan Furman64a99722013-09-22 16:18:19 -0700252 def test_attribute_deletion(self):
253 class Season(Enum):
254 SPRING = 1
255 SUMMER = 2
256 AUTUMN = 3
257 WINTER = 4
258
259 def spam(cls):
260 pass
261
262 self.assertTrue(hasattr(Season, 'spam'))
263 del Season.spam
264 self.assertFalse(hasattr(Season, 'spam'))
265
266 with self.assertRaises(AttributeError):
267 del Season.SPRING
268 with self.assertRaises(AttributeError):
269 del Season.DRY
270 with self.assertRaises(AttributeError):
271 del Season.SPRING.name
272
Ethan Furman5de67b12016-04-13 23:52:09 -0700273 def test_bool_of_class(self):
274 class Empty(Enum):
275 pass
276 self.assertTrue(bool(Empty))
277
278 def test_bool_of_member(self):
279 class Count(Enum):
280 zero = 0
281 one = 1
282 two = 2
283 for member in Count:
284 self.assertTrue(bool(member))
285
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700286 def test_invalid_names(self):
287 with self.assertRaises(ValueError):
288 class Wrong(Enum):
289 mro = 9
290 with self.assertRaises(ValueError):
291 class Wrong(Enum):
292 _create_= 11
293 with self.assertRaises(ValueError):
294 class Wrong(Enum):
295 _get_mixins_ = 9
296 with self.assertRaises(ValueError):
297 class Wrong(Enum):
298 _find_new_ = 1
299 with self.assertRaises(ValueError):
300 class Wrong(Enum):
301 _any_name_ = 9
302
Ethan Furman6db1fd52015-09-17 21:49:12 -0700303 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800304 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700305 class Logic(Enum):
306 true = True
307 false = False
308 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800309 self.assertTrue(Logic.false)
310 # unless overridden
311 class RealLogic(Enum):
312 true = True
313 false = False
314 def __bool__(self):
315 return bool(self._value_)
316 self.assertTrue(RealLogic.true)
317 self.assertFalse(RealLogic.false)
318 # mixed Enums depend on mixed-in type
319 class IntLogic(int, Enum):
320 true = 1
321 false = 0
322 self.assertTrue(IntLogic.true)
323 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700324
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700325 def test_contains(self):
326 Season = self.Season
327 self.assertIn(Season.AUTUMN, Season)
328 self.assertNotIn(3, Season)
329
330 val = Season(3)
331 self.assertIn(val, Season)
332
333 class OtherEnum(Enum):
334 one = 1; two = 2
335 self.assertNotIn(OtherEnum.two, Season)
336
337 def test_comparisons(self):
338 Season = self.Season
339 with self.assertRaises(TypeError):
340 Season.SPRING < Season.WINTER
341 with self.assertRaises(TypeError):
342 Season.SPRING > 4
343
344 self.assertNotEqual(Season.SPRING, 1)
345
346 class Part(Enum):
347 SPRING = 1
348 CLIP = 2
349 BARREL = 3
350
351 self.assertNotEqual(Season.SPRING, Part.SPRING)
352 with self.assertRaises(TypeError):
353 Season.SPRING < Part.CLIP
354
355 def test_enum_duplicates(self):
356 class Season(Enum):
357 SPRING = 1
358 SUMMER = 2
359 AUTUMN = FALL = 3
360 WINTER = 4
361 ANOTHER_SPRING = 1
362 lst = list(Season)
363 self.assertEqual(
364 lst,
365 [Season.SPRING, Season.SUMMER,
366 Season.AUTUMN, Season.WINTER,
367 ])
368 self.assertIs(Season.FALL, Season.AUTUMN)
369 self.assertEqual(Season.FALL.value, 3)
370 self.assertEqual(Season.AUTUMN.value, 3)
371 self.assertIs(Season(3), Season.AUTUMN)
372 self.assertIs(Season(1), Season.SPRING)
373 self.assertEqual(Season.FALL.name, 'AUTUMN')
374 self.assertEqual(
375 [k for k,v in Season.__members__.items() if v.name != k],
376 ['FALL', 'ANOTHER_SPRING'],
377 )
378
Ethan Furman101e0742013-09-15 12:34:36 -0700379 def test_duplicate_name(self):
380 with self.assertRaises(TypeError):
381 class Color(Enum):
382 red = 1
383 green = 2
384 blue = 3
385 red = 4
386
387 with self.assertRaises(TypeError):
388 class Color(Enum):
389 red = 1
390 green = 2
391 blue = 3
392 def red(self):
393 return 'red'
394
395 with self.assertRaises(TypeError):
396 class Color(Enum):
397 @property
398 def red(self):
399 return 'redder'
400 red = 1
401 green = 2
402 blue = 3
403
404
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700405 def test_enum_with_value_name(self):
406 class Huh(Enum):
407 name = 1
408 value = 2
409 self.assertEqual(
410 list(Huh),
411 [Huh.name, Huh.value],
412 )
413 self.assertIs(type(Huh.name), Huh)
414 self.assertEqual(Huh.name.name, 'name')
415 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700416
417 def test_format_enum(self):
418 Season = self.Season
419 self.assertEqual('{}'.format(Season.SPRING),
420 '{}'.format(str(Season.SPRING)))
421 self.assertEqual( '{:}'.format(Season.SPRING),
422 '{:}'.format(str(Season.SPRING)))
423 self.assertEqual('{:20}'.format(Season.SPRING),
424 '{:20}'.format(str(Season.SPRING)))
425 self.assertEqual('{:^20}'.format(Season.SPRING),
426 '{:^20}'.format(str(Season.SPRING)))
427 self.assertEqual('{:>20}'.format(Season.SPRING),
428 '{:>20}'.format(str(Season.SPRING)))
429 self.assertEqual('{:<20}'.format(Season.SPRING),
430 '{:<20}'.format(str(Season.SPRING)))
431
432 def test_format_enum_custom(self):
433 class TestFloat(float, Enum):
434 one = 1.0
435 two = 2.0
436 def __format__(self, spec):
437 return 'TestFloat success!'
438 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
439
440 def assertFormatIsValue(self, spec, member):
441 self.assertEqual(spec.format(member), spec.format(member.value))
442
443 def test_format_enum_date(self):
444 Holiday = self.Holiday
445 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
446 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
447 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
448 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
449 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
450 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
451 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
452 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
453
454 def test_format_enum_float(self):
455 Konstants = self.Konstants
456 self.assertFormatIsValue('{}', Konstants.TAU)
457 self.assertFormatIsValue('{:}', Konstants.TAU)
458 self.assertFormatIsValue('{:20}', Konstants.TAU)
459 self.assertFormatIsValue('{:^20}', Konstants.TAU)
460 self.assertFormatIsValue('{:>20}', Konstants.TAU)
461 self.assertFormatIsValue('{:<20}', Konstants.TAU)
462 self.assertFormatIsValue('{:n}', Konstants.TAU)
463 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
464 self.assertFormatIsValue('{:f}', Konstants.TAU)
465
466 def test_format_enum_int(self):
467 Grades = self.Grades
468 self.assertFormatIsValue('{}', Grades.C)
469 self.assertFormatIsValue('{:}', Grades.C)
470 self.assertFormatIsValue('{:20}', Grades.C)
471 self.assertFormatIsValue('{:^20}', Grades.C)
472 self.assertFormatIsValue('{:>20}', Grades.C)
473 self.assertFormatIsValue('{:<20}', Grades.C)
474 self.assertFormatIsValue('{:+}', Grades.C)
475 self.assertFormatIsValue('{:08X}', Grades.C)
476 self.assertFormatIsValue('{:b}', Grades.C)
477
478 def test_format_enum_str(self):
479 Directional = self.Directional
480 self.assertFormatIsValue('{}', Directional.WEST)
481 self.assertFormatIsValue('{:}', Directional.WEST)
482 self.assertFormatIsValue('{:20}', Directional.WEST)
483 self.assertFormatIsValue('{:^20}', Directional.WEST)
484 self.assertFormatIsValue('{:>20}', Directional.WEST)
485 self.assertFormatIsValue('{:<20}', Directional.WEST)
486
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700487 def test_hash(self):
488 Season = self.Season
489 dates = {}
490 dates[Season.WINTER] = '1225'
491 dates[Season.SPRING] = '0315'
492 dates[Season.SUMMER] = '0704'
493 dates[Season.AUTUMN] = '1031'
494 self.assertEqual(dates[Season.AUTUMN], '1031')
495
496 def test_intenum_from_scratch(self):
497 class phy(int, Enum):
498 pi = 3
499 tau = 2 * pi
500 self.assertTrue(phy.pi < phy.tau)
501
502 def test_intenum_inherited(self):
503 class IntEnum(int, Enum):
504 pass
505 class phy(IntEnum):
506 pi = 3
507 tau = 2 * pi
508 self.assertTrue(phy.pi < phy.tau)
509
510 def test_floatenum_from_scratch(self):
511 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700512 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700513 tau = 2 * pi
514 self.assertTrue(phy.pi < phy.tau)
515
516 def test_floatenum_inherited(self):
517 class FloatEnum(float, Enum):
518 pass
519 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700520 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700521 tau = 2 * pi
522 self.assertTrue(phy.pi < phy.tau)
523
524 def test_strenum_from_scratch(self):
525 class phy(str, Enum):
526 pi = 'Pi'
527 tau = 'Tau'
528 self.assertTrue(phy.pi < phy.tau)
529
530 def test_strenum_inherited(self):
531 class StrEnum(str, Enum):
532 pass
533 class phy(StrEnum):
534 pi = 'Pi'
535 tau = 'Tau'
536 self.assertTrue(phy.pi < phy.tau)
537
538
539 def test_intenum(self):
540 class WeekDay(IntEnum):
541 SUNDAY = 1
542 MONDAY = 2
543 TUESDAY = 3
544 WEDNESDAY = 4
545 THURSDAY = 5
546 FRIDAY = 6
547 SATURDAY = 7
548
549 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
550 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
551
552 lst = list(WeekDay)
553 self.assertEqual(len(lst), len(WeekDay))
554 self.assertEqual(len(WeekDay), 7)
555 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
556 target = target.split()
557 for i, weekday in enumerate(target, 1):
558 e = WeekDay(i)
559 self.assertEqual(e, i)
560 self.assertEqual(int(e), i)
561 self.assertEqual(e.name, weekday)
562 self.assertIn(e, WeekDay)
563 self.assertEqual(lst.index(e)+1, i)
564 self.assertTrue(0 < e < 8)
565 self.assertIs(type(e), WeekDay)
566 self.assertIsInstance(e, int)
567 self.assertIsInstance(e, Enum)
568
569 def test_intenum_duplicates(self):
570 class WeekDay(IntEnum):
571 SUNDAY = 1
572 MONDAY = 2
573 TUESDAY = TEUSDAY = 3
574 WEDNESDAY = 4
575 THURSDAY = 5
576 FRIDAY = 6
577 SATURDAY = 7
578 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
579 self.assertEqual(WeekDay(3).name, 'TUESDAY')
580 self.assertEqual([k for k,v in WeekDay.__members__.items()
581 if v.name != k], ['TEUSDAY', ])
582
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300583 def test_intenum_from_bytes(self):
584 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
585 with self.assertRaises(ValueError):
586 IntStooges.from_bytes(b'\x00\x05', 'big')
587
588 def test_floatenum_fromhex(self):
589 h = float.hex(FloatStooges.MOE.value)
590 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
591 h = float.hex(FloatStooges.MOE.value + 0.01)
592 with self.assertRaises(ValueError):
593 FloatStooges.fromhex(h)
594
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700595 def test_pickle_enum(self):
596 if isinstance(Stooges, Exception):
597 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800598 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
599 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700600
601 def test_pickle_int(self):
602 if isinstance(IntStooges, Exception):
603 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800604 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
605 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700606
607 def test_pickle_float(self):
608 if isinstance(FloatStooges, Exception):
609 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800610 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
611 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700612
613 def test_pickle_enum_function(self):
614 if isinstance(Answer, Exception):
615 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800616 test_pickle_dump_load(self.assertIs, Answer.him)
617 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700618
619 def test_pickle_enum_function_with_module(self):
620 if isinstance(Question, Exception):
621 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800622 test_pickle_dump_load(self.assertIs, Question.who)
623 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700624
Ethan Furmanca1b7942014-02-08 11:36:27 -0800625 def test_enum_function_with_qualname(self):
626 if isinstance(Theory, Exception):
627 raise Theory
628 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
629
630 def test_class_nested_enum_and_pickle_protocol_four(self):
631 # would normally just have this directly in the class namespace
632 class NestedEnum(Enum):
633 twigs = 'common'
634 shiny = 'rare'
635
636 self.__class__.NestedEnum = NestedEnum
637 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300638 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800639
Ethan Furman24e837f2015-03-18 17:27:57 -0700640 def test_pickle_by_name(self):
641 class ReplaceGlobalInt(IntEnum):
642 ONE = 1
643 TWO = 2
644 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
645 for proto in range(HIGHEST_PROTOCOL):
646 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
647
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700648 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800649 BadPickle = Enum(
650 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700651 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800652 # now break BadPickle to test exception raising
653 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800654 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
655 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700656
657 def test_string_enum(self):
658 class SkillLevel(str, Enum):
659 master = 'what is the sound of one hand clapping?'
660 journeyman = 'why did the chicken cross the road?'
661 apprentice = 'knock, knock!'
662 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
663
664 def test_getattr_getitem(self):
665 class Period(Enum):
666 morning = 1
667 noon = 2
668 evening = 3
669 night = 4
670 self.assertIs(Period(2), Period.noon)
671 self.assertIs(getattr(Period, 'night'), Period.night)
672 self.assertIs(Period['morning'], Period.morning)
673
674 def test_getattr_dunder(self):
675 Season = self.Season
676 self.assertTrue(getattr(Season, '__eq__'))
677
678 def test_iteration_order(self):
679 class Season(Enum):
680 SUMMER = 2
681 WINTER = 4
682 AUTUMN = 3
683 SPRING = 1
684 self.assertEqual(
685 list(Season),
686 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
687 )
688
Ethan Furman2131a4a2013-09-14 18:11:24 -0700689 def test_reversed_iteration_order(self):
690 self.assertEqual(
691 list(reversed(self.Season)),
692 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
693 self.Season.SPRING]
694 )
695
Martin Pantereb995702016-07-28 01:11:04 +0000696 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700697 SummerMonth = Enum('SummerMonth', 'june july august')
698 lst = list(SummerMonth)
699 self.assertEqual(len(lst), len(SummerMonth))
700 self.assertEqual(len(SummerMonth), 3, SummerMonth)
701 self.assertEqual(
702 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
703 lst,
704 )
705 for i, month in enumerate('june july august'.split(), 1):
706 e = SummerMonth(i)
707 self.assertEqual(int(e.value), i)
708 self.assertNotEqual(e, i)
709 self.assertEqual(e.name, month)
710 self.assertIn(e, SummerMonth)
711 self.assertIs(type(e), SummerMonth)
712
Martin Pantereb995702016-07-28 01:11:04 +0000713 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700714 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
715 lst = list(SummerMonth)
716 self.assertEqual(len(lst), len(SummerMonth))
717 self.assertEqual(len(SummerMonth), 3, SummerMonth)
718 self.assertEqual(
719 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
720 lst,
721 )
722 for i, month in enumerate('june july august'.split(), 10):
723 e = SummerMonth(i)
724 self.assertEqual(int(e.value), i)
725 self.assertNotEqual(e, i)
726 self.assertEqual(e.name, month)
727 self.assertIn(e, SummerMonth)
728 self.assertIs(type(e), SummerMonth)
729
Martin Pantereb995702016-07-28 01:11:04 +0000730 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700731 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
732 lst = list(SummerMonth)
733 self.assertEqual(len(lst), len(SummerMonth))
734 self.assertEqual(len(SummerMonth), 3, SummerMonth)
735 self.assertEqual(
736 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
737 lst,
738 )
739 for i, month in enumerate('june july august'.split(), 1):
740 e = SummerMonth(i)
741 self.assertEqual(int(e.value), i)
742 self.assertNotEqual(e, i)
743 self.assertEqual(e.name, month)
744 self.assertIn(e, SummerMonth)
745 self.assertIs(type(e), SummerMonth)
746
Martin Pantereb995702016-07-28 01:11:04 +0000747 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700748 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
749 lst = list(SummerMonth)
750 self.assertEqual(len(lst), len(SummerMonth))
751 self.assertEqual(len(SummerMonth), 3, SummerMonth)
752 self.assertEqual(
753 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
754 lst,
755 )
756 for i, month in enumerate('june july august'.split(), 20):
757 e = SummerMonth(i)
758 self.assertEqual(int(e.value), i)
759 self.assertNotEqual(e, i)
760 self.assertEqual(e.name, month)
761 self.assertIn(e, SummerMonth)
762 self.assertIs(type(e), SummerMonth)
763
Martin Pantereb995702016-07-28 01:11:04 +0000764 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700765 SummerMonth = Enum(
766 'SummerMonth',
767 (('june', 1), ('july', 2), ('august', 3))
768 )
769 lst = list(SummerMonth)
770 self.assertEqual(len(lst), len(SummerMonth))
771 self.assertEqual(len(SummerMonth), 3, SummerMonth)
772 self.assertEqual(
773 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
774 lst,
775 )
776 for i, month in enumerate('june july august'.split(), 1):
777 e = SummerMonth(i)
778 self.assertEqual(int(e.value), i)
779 self.assertNotEqual(e, i)
780 self.assertEqual(e.name, month)
781 self.assertIn(e, SummerMonth)
782 self.assertIs(type(e), SummerMonth)
783
Martin Pantereb995702016-07-28 01:11:04 +0000784 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700785 SummerMonth = Enum(
786 'SummerMonth',
787 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
788 )
789 lst = list(SummerMonth)
790 self.assertEqual(len(lst), len(SummerMonth))
791 self.assertEqual(len(SummerMonth), 3, SummerMonth)
792 self.assertEqual(
793 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
794 lst,
795 )
796 for i, month in enumerate('june july august'.split(), 1):
797 e = SummerMonth(i)
798 self.assertEqual(int(e.value), i)
799 self.assertNotEqual(e, i)
800 self.assertEqual(e.name, month)
801 self.assertIn(e, SummerMonth)
802 self.assertIs(type(e), SummerMonth)
803
Martin Pantereb995702016-07-28 01:11:04 +0000804 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700805 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
806 lst = list(SummerMonth)
807 self.assertEqual(len(lst), len(SummerMonth))
808 self.assertEqual(len(SummerMonth), 3, SummerMonth)
809 self.assertEqual(
810 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
811 lst,
812 )
813 for i, month in enumerate('june july august'.split(), 1):
814 e = SummerMonth(i)
815 self.assertEqual(e, i)
816 self.assertEqual(e.name, month)
817 self.assertIn(e, SummerMonth)
818 self.assertIs(type(e), SummerMonth)
819
Martin Pantereb995702016-07-28 01:11:04 +0000820 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700821 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
822 lst = list(SummerMonth)
823 self.assertEqual(len(lst), len(SummerMonth))
824 self.assertEqual(len(SummerMonth), 3, SummerMonth)
825 self.assertEqual(
826 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
827 lst,
828 )
829 for i, month in enumerate('june july august'.split(), 30):
830 e = SummerMonth(i)
831 self.assertEqual(e, i)
832 self.assertEqual(e.name, month)
833 self.assertIn(e, SummerMonth)
834 self.assertIs(type(e), SummerMonth)
835
Martin Pantereb995702016-07-28 01:11:04 +0000836 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700837 SummerMonth = IntEnum('SummerMonth', 'june july august')
838 lst = list(SummerMonth)
839 self.assertEqual(len(lst), len(SummerMonth))
840 self.assertEqual(len(SummerMonth), 3, SummerMonth)
841 self.assertEqual(
842 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
843 lst,
844 )
845 for i, month in enumerate('june july august'.split(), 1):
846 e = SummerMonth(i)
847 self.assertEqual(e, i)
848 self.assertEqual(e.name, month)
849 self.assertIn(e, SummerMonth)
850 self.assertIs(type(e), SummerMonth)
851
Martin Pantereb995702016-07-28 01:11:04 +0000852 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700853 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
854 lst = list(SummerMonth)
855 self.assertEqual(len(lst), len(SummerMonth))
856 self.assertEqual(len(SummerMonth), 3, SummerMonth)
857 self.assertEqual(
858 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
859 lst,
860 )
861 for i, month in enumerate('june july august'.split(), 40):
862 e = SummerMonth(i)
863 self.assertEqual(e, i)
864 self.assertEqual(e.name, month)
865 self.assertIn(e, SummerMonth)
866 self.assertIs(type(e), SummerMonth)
867
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700868 def test_subclassing(self):
869 if isinstance(Name, Exception):
870 raise Name
871 self.assertEqual(Name.BDFL, 'Guido van Rossum')
872 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
873 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800874 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700875
876 def test_extending(self):
877 class Color(Enum):
878 red = 1
879 green = 2
880 blue = 3
881 with self.assertRaises(TypeError):
882 class MoreColor(Color):
883 cyan = 4
884 magenta = 5
885 yellow = 6
886
887 def test_exclude_methods(self):
888 class whatever(Enum):
889 this = 'that'
890 these = 'those'
891 def really(self):
892 return 'no, not %s' % self.value
893 self.assertIsNot(type(whatever.really), whatever)
894 self.assertEqual(whatever.this.really(), 'no, not that')
895
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700896 def test_wrong_inheritance_order(self):
897 with self.assertRaises(TypeError):
898 class Wrong(Enum, str):
899 NotHere = 'error before this point'
900
901 def test_intenum_transitivity(self):
902 class number(IntEnum):
903 one = 1
904 two = 2
905 three = 3
906 class numero(IntEnum):
907 uno = 1
908 dos = 2
909 tres = 3
910 self.assertEqual(number.one, numero.uno)
911 self.assertEqual(number.two, numero.dos)
912 self.assertEqual(number.three, numero.tres)
913
914 def test_wrong_enum_in_call(self):
915 class Monochrome(Enum):
916 black = 0
917 white = 1
918 class Gender(Enum):
919 male = 0
920 female = 1
921 self.assertRaises(ValueError, Monochrome, Gender.male)
922
923 def test_wrong_enum_in_mixed_call(self):
924 class Monochrome(IntEnum):
925 black = 0
926 white = 1
927 class Gender(Enum):
928 male = 0
929 female = 1
930 self.assertRaises(ValueError, Monochrome, Gender.male)
931
932 def test_mixed_enum_in_call_1(self):
933 class Monochrome(IntEnum):
934 black = 0
935 white = 1
936 class Gender(IntEnum):
937 male = 0
938 female = 1
939 self.assertIs(Monochrome(Gender.female), Monochrome.white)
940
941 def test_mixed_enum_in_call_2(self):
942 class Monochrome(Enum):
943 black = 0
944 white = 1
945 class Gender(IntEnum):
946 male = 0
947 female = 1
948 self.assertIs(Monochrome(Gender.male), Monochrome.black)
949
950 def test_flufl_enum(self):
951 class Fluflnum(Enum):
952 def __int__(self):
953 return int(self.value)
954 class MailManOptions(Fluflnum):
955 option1 = 1
956 option2 = 2
957 option3 = 3
958 self.assertEqual(int(MailManOptions.option1), 1)
959
Ethan Furman5e5a8232013-08-04 08:42:23 -0700960 def test_introspection(self):
961 class Number(IntEnum):
962 one = 100
963 two = 200
964 self.assertIs(Number.one._member_type_, int)
965 self.assertIs(Number._member_type_, int)
966 class String(str, Enum):
967 yarn = 'soft'
968 rope = 'rough'
969 wire = 'hard'
970 self.assertIs(String.yarn._member_type_, str)
971 self.assertIs(String._member_type_, str)
972 class Plain(Enum):
973 vanilla = 'white'
974 one = 1
975 self.assertIs(Plain.vanilla._member_type_, object)
976 self.assertIs(Plain._member_type_, object)
977
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700978 def test_no_such_enum_member(self):
979 class Color(Enum):
980 red = 1
981 green = 2
982 blue = 3
983 with self.assertRaises(ValueError):
984 Color(4)
985 with self.assertRaises(KeyError):
986 Color['chartreuse']
987
988 def test_new_repr(self):
989 class Color(Enum):
990 red = 1
991 green = 2
992 blue = 3
993 def __repr__(self):
994 return "don't you just love shades of %s?" % self.name
995 self.assertEqual(
996 repr(Color.blue),
997 "don't you just love shades of blue?",
998 )
999
1000 def test_inherited_repr(self):
1001 class MyEnum(Enum):
1002 def __repr__(self):
1003 return "My name is %s." % self.name
1004 class MyIntEnum(int, MyEnum):
1005 this = 1
1006 that = 2
1007 theother = 3
1008 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1009
1010 def test_multiple_mixin_mro(self):
1011 class auto_enum(type(Enum)):
1012 def __new__(metacls, cls, bases, classdict):
1013 temp = type(classdict)()
1014 names = set(classdict._member_names)
1015 i = 0
1016 for k in classdict._member_names:
1017 v = classdict[k]
1018 if v is Ellipsis:
1019 v = i
1020 else:
1021 i = v
1022 i += 1
1023 temp[k] = v
1024 for k, v in classdict.items():
1025 if k not in names:
1026 temp[k] = v
1027 return super(auto_enum, metacls).__new__(
1028 metacls, cls, bases, temp)
1029
1030 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1031 pass
1032
1033 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1034 pass
1035
1036 class TestAutoNumber(AutoNumberedEnum):
1037 a = ...
1038 b = 3
1039 c = ...
1040
1041 class TestAutoInt(AutoIntEnum):
1042 a = ...
1043 b = 3
1044 c = ...
1045
1046 def test_subclasses_with_getnewargs(self):
1047 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001048 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001049 def __new__(cls, *args):
1050 _args = args
1051 name, *args = args
1052 if len(args) == 0:
1053 raise TypeError("name and value must be specified")
1054 self = int.__new__(cls, *args)
1055 self._intname = name
1056 self._args = _args
1057 return self
1058 def __getnewargs__(self):
1059 return self._args
1060 @property
1061 def __name__(self):
1062 return self._intname
1063 def __repr__(self):
1064 # repr() is updated to include the name and type info
1065 return "{}({!r}, {})".format(type(self).__name__,
1066 self.__name__,
1067 int.__repr__(self))
1068 def __str__(self):
1069 # str() is unchanged, even if it relies on the repr() fallback
1070 base = int
1071 base_str = base.__str__
1072 if base_str.__objclass__ is object:
1073 return base.__repr__(self)
1074 return base_str(self)
1075 # for simplicity, we only define one operator that
1076 # propagates expressions
1077 def __add__(self, other):
1078 temp = int(self) + int( other)
1079 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1080 return NamedInt(
1081 '({0} + {1})'.format(self.__name__, other.__name__),
1082 temp )
1083 else:
1084 return temp
1085
1086 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001087 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001088 x = ('the-x', 1)
1089 y = ('the-y', 2)
1090
Ethan Furman2aa27322013-07-19 19:35:56 -07001091
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001092 self.assertIs(NEI.__new__, Enum.__new__)
1093 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1094 globals()['NamedInt'] = NamedInt
1095 globals()['NEI'] = NEI
1096 NI5 = NamedInt('test', 5)
1097 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001098 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001099 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001100 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001101 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001102
Ethan Furmanca1b7942014-02-08 11:36:27 -08001103 def test_subclasses_with_getnewargs_ex(self):
1104 class NamedInt(int):
1105 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1106 def __new__(cls, *args):
1107 _args = args
1108 name, *args = args
1109 if len(args) == 0:
1110 raise TypeError("name and value must be specified")
1111 self = int.__new__(cls, *args)
1112 self._intname = name
1113 self._args = _args
1114 return self
1115 def __getnewargs_ex__(self):
1116 return self._args, {}
1117 @property
1118 def __name__(self):
1119 return self._intname
1120 def __repr__(self):
1121 # repr() is updated to include the name and type info
1122 return "{}({!r}, {})".format(type(self).__name__,
1123 self.__name__,
1124 int.__repr__(self))
1125 def __str__(self):
1126 # str() is unchanged, even if it relies on the repr() fallback
1127 base = int
1128 base_str = base.__str__
1129 if base_str.__objclass__ is object:
1130 return base.__repr__(self)
1131 return base_str(self)
1132 # for simplicity, we only define one operator that
1133 # propagates expressions
1134 def __add__(self, other):
1135 temp = int(self) + int( other)
1136 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1137 return NamedInt(
1138 '({0} + {1})'.format(self.__name__, other.__name__),
1139 temp )
1140 else:
1141 return temp
1142
1143 class NEI(NamedInt, Enum):
1144 __qualname__ = 'NEI' # needed for pickle protocol 4
1145 x = ('the-x', 1)
1146 y = ('the-y', 2)
1147
1148
1149 self.assertIs(NEI.__new__, Enum.__new__)
1150 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1151 globals()['NamedInt'] = NamedInt
1152 globals()['NEI'] = NEI
1153 NI5 = NamedInt('test', 5)
1154 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001155 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001156 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001157 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001158 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001159
1160 def test_subclasses_with_reduce(self):
1161 class NamedInt(int):
1162 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1163 def __new__(cls, *args):
1164 _args = args
1165 name, *args = args
1166 if len(args) == 0:
1167 raise TypeError("name and value must be specified")
1168 self = int.__new__(cls, *args)
1169 self._intname = name
1170 self._args = _args
1171 return self
1172 def __reduce__(self):
1173 return self.__class__, self._args
1174 @property
1175 def __name__(self):
1176 return self._intname
1177 def __repr__(self):
1178 # repr() is updated to include the name and type info
1179 return "{}({!r}, {})".format(type(self).__name__,
1180 self.__name__,
1181 int.__repr__(self))
1182 def __str__(self):
1183 # str() is unchanged, even if it relies on the repr() fallback
1184 base = int
1185 base_str = base.__str__
1186 if base_str.__objclass__ is object:
1187 return base.__repr__(self)
1188 return base_str(self)
1189 # for simplicity, we only define one operator that
1190 # propagates expressions
1191 def __add__(self, other):
1192 temp = int(self) + int( other)
1193 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1194 return NamedInt(
1195 '({0} + {1})'.format(self.__name__, other.__name__),
1196 temp )
1197 else:
1198 return temp
1199
1200 class NEI(NamedInt, Enum):
1201 __qualname__ = 'NEI' # needed for pickle protocol 4
1202 x = ('the-x', 1)
1203 y = ('the-y', 2)
1204
1205
1206 self.assertIs(NEI.__new__, Enum.__new__)
1207 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1208 globals()['NamedInt'] = NamedInt
1209 globals()['NEI'] = NEI
1210 NI5 = NamedInt('test', 5)
1211 self.assertEqual(NI5, 5)
1212 test_pickle_dump_load(self.assertEqual, NI5, 5)
1213 self.assertEqual(NEI.y.value, 2)
1214 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001215 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001216
1217 def test_subclasses_with_reduce_ex(self):
1218 class NamedInt(int):
1219 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1220 def __new__(cls, *args):
1221 _args = args
1222 name, *args = args
1223 if len(args) == 0:
1224 raise TypeError("name and value must be specified")
1225 self = int.__new__(cls, *args)
1226 self._intname = name
1227 self._args = _args
1228 return self
1229 def __reduce_ex__(self, proto):
1230 return self.__class__, self._args
1231 @property
1232 def __name__(self):
1233 return self._intname
1234 def __repr__(self):
1235 # repr() is updated to include the name and type info
1236 return "{}({!r}, {})".format(type(self).__name__,
1237 self.__name__,
1238 int.__repr__(self))
1239 def __str__(self):
1240 # str() is unchanged, even if it relies on the repr() fallback
1241 base = int
1242 base_str = base.__str__
1243 if base_str.__objclass__ is object:
1244 return base.__repr__(self)
1245 return base_str(self)
1246 # for simplicity, we only define one operator that
1247 # propagates expressions
1248 def __add__(self, other):
1249 temp = int(self) + int( other)
1250 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1251 return NamedInt(
1252 '({0} + {1})'.format(self.__name__, other.__name__),
1253 temp )
1254 else:
1255 return temp
1256
1257 class NEI(NamedInt, Enum):
1258 __qualname__ = 'NEI' # needed for pickle protocol 4
1259 x = ('the-x', 1)
1260 y = ('the-y', 2)
1261
1262
1263 self.assertIs(NEI.__new__, Enum.__new__)
1264 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1265 globals()['NamedInt'] = NamedInt
1266 globals()['NEI'] = NEI
1267 NI5 = NamedInt('test', 5)
1268 self.assertEqual(NI5, 5)
1269 test_pickle_dump_load(self.assertEqual, NI5, 5)
1270 self.assertEqual(NEI.y.value, 2)
1271 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001272 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001273
Ethan Furmandc870522014-02-18 12:37:12 -08001274 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001275 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001276 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001277 def __new__(cls, *args):
1278 _args = args
1279 name, *args = args
1280 if len(args) == 0:
1281 raise TypeError("name and value must be specified")
1282 self = int.__new__(cls, *args)
1283 self._intname = name
1284 self._args = _args
1285 return self
1286 @property
1287 def __name__(self):
1288 return self._intname
1289 def __repr__(self):
1290 # repr() is updated to include the name and type info
1291 return "{}({!r}, {})".format(type(self).__name__,
1292 self.__name__,
1293 int.__repr__(self))
1294 def __str__(self):
1295 # str() is unchanged, even if it relies on the repr() fallback
1296 base = int
1297 base_str = base.__str__
1298 if base_str.__objclass__ is object:
1299 return base.__repr__(self)
1300 return base_str(self)
1301 # for simplicity, we only define one operator that
1302 # propagates expressions
1303 def __add__(self, other):
1304 temp = int(self) + int( other)
1305 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1306 return NamedInt(
1307 '({0} + {1})'.format(self.__name__, other.__name__),
1308 temp )
1309 else:
1310 return temp
1311
1312 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001313 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001314 x = ('the-x', 1)
1315 y = ('the-y', 2)
1316
1317 self.assertIs(NEI.__new__, Enum.__new__)
1318 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1319 globals()['NamedInt'] = NamedInt
1320 globals()['NEI'] = NEI
1321 NI5 = NamedInt('test', 5)
1322 self.assertEqual(NI5, 5)
1323 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001324 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1325 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001326
Ethan Furmandc870522014-02-18 12:37:12 -08001327 def test_subclasses_without_direct_pickle_support_using_name(self):
1328 class NamedInt(int):
1329 __qualname__ = 'NamedInt'
1330 def __new__(cls, *args):
1331 _args = args
1332 name, *args = args
1333 if len(args) == 0:
1334 raise TypeError("name and value must be specified")
1335 self = int.__new__(cls, *args)
1336 self._intname = name
1337 self._args = _args
1338 return self
1339 @property
1340 def __name__(self):
1341 return self._intname
1342 def __repr__(self):
1343 # repr() is updated to include the name and type info
1344 return "{}({!r}, {})".format(type(self).__name__,
1345 self.__name__,
1346 int.__repr__(self))
1347 def __str__(self):
1348 # str() is unchanged, even if it relies on the repr() fallback
1349 base = int
1350 base_str = base.__str__
1351 if base_str.__objclass__ is object:
1352 return base.__repr__(self)
1353 return base_str(self)
1354 # for simplicity, we only define one operator that
1355 # propagates expressions
1356 def __add__(self, other):
1357 temp = int(self) + int( other)
1358 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1359 return NamedInt(
1360 '({0} + {1})'.format(self.__name__, other.__name__),
1361 temp )
1362 else:
1363 return temp
1364
1365 class NEI(NamedInt, Enum):
1366 __qualname__ = 'NEI'
1367 x = ('the-x', 1)
1368 y = ('the-y', 2)
1369 def __reduce_ex__(self, proto):
1370 return getattr, (self.__class__, self._name_)
1371
1372 self.assertIs(NEI.__new__, Enum.__new__)
1373 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1374 globals()['NamedInt'] = NamedInt
1375 globals()['NEI'] = NEI
1376 NI5 = NamedInt('test', 5)
1377 self.assertEqual(NI5, 5)
1378 self.assertEqual(NEI.y.value, 2)
1379 test_pickle_dump_load(self.assertIs, NEI.y)
1380 test_pickle_dump_load(self.assertIs, NEI)
1381
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001382 def test_tuple_subclass(self):
1383 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001384 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001385 first = (1, 'for the money')
1386 second = (2, 'for the show')
1387 third = (3, 'for the music')
1388 self.assertIs(type(SomeTuple.first), SomeTuple)
1389 self.assertIsInstance(SomeTuple.second, tuple)
1390 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1391 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001392 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001393
1394 def test_duplicate_values_give_unique_enum_items(self):
1395 class AutoNumber(Enum):
1396 first = ()
1397 second = ()
1398 third = ()
1399 def __new__(cls):
1400 value = len(cls.__members__) + 1
1401 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001402 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001403 return obj
1404 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001405 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001406 self.assertEqual(
1407 list(AutoNumber),
1408 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1409 )
1410 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001411 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001412 self.assertIs(AutoNumber(1), AutoNumber.first)
1413
1414 def test_inherited_new_from_enhanced_enum(self):
1415 class AutoNumber(Enum):
1416 def __new__(cls):
1417 value = len(cls.__members__) + 1
1418 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001419 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001420 return obj
1421 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001422 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001423 class Color(AutoNumber):
1424 red = ()
1425 green = ()
1426 blue = ()
1427 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1428 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1429
1430 def test_inherited_new_from_mixed_enum(self):
1431 class AutoNumber(IntEnum):
1432 def __new__(cls):
1433 value = len(cls.__members__) + 1
1434 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001435 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001436 return obj
1437 class Color(AutoNumber):
1438 red = ()
1439 green = ()
1440 blue = ()
1441 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1442 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1443
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001444 def test_equality(self):
1445 class AlwaysEqual:
1446 def __eq__(self, other):
1447 return True
1448 class OrdinaryEnum(Enum):
1449 a = 1
1450 self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1451 self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1452
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001453 def test_ordered_mixin(self):
1454 class OrderedEnum(Enum):
1455 def __ge__(self, other):
1456 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001457 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001458 return NotImplemented
1459 def __gt__(self, other):
1460 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001461 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001462 return NotImplemented
1463 def __le__(self, other):
1464 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001465 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001466 return NotImplemented
1467 def __lt__(self, other):
1468 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001469 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001470 return NotImplemented
1471 class Grade(OrderedEnum):
1472 A = 5
1473 B = 4
1474 C = 3
1475 D = 2
1476 F = 1
1477 self.assertGreater(Grade.A, Grade.B)
1478 self.assertLessEqual(Grade.F, Grade.C)
1479 self.assertLess(Grade.D, Grade.A)
1480 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001481 self.assertEqual(Grade.B, Grade.B)
1482 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001483
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001484 def test_extending2(self):
1485 class Shade(Enum):
1486 def shade(self):
1487 print(self.name)
1488 class Color(Shade):
1489 red = 1
1490 green = 2
1491 blue = 3
1492 with self.assertRaises(TypeError):
1493 class MoreColor(Color):
1494 cyan = 4
1495 magenta = 5
1496 yellow = 6
1497
1498 def test_extending3(self):
1499 class Shade(Enum):
1500 def shade(self):
1501 return self.name
1502 class Color(Shade):
1503 def hex(self):
1504 return '%s hexlified!' % self.value
1505 class MoreColor(Color):
1506 cyan = 4
1507 magenta = 5
1508 yellow = 6
1509 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1510
1511
1512 def test_no_duplicates(self):
1513 class UniqueEnum(Enum):
1514 def __init__(self, *args):
1515 cls = self.__class__
1516 if any(self.value == e.value for e in cls):
1517 a = self.name
1518 e = cls(self.value).name
1519 raise ValueError(
1520 "aliases not allowed in UniqueEnum: %r --> %r"
1521 % (a, e)
1522 )
1523 class Color(UniqueEnum):
1524 red = 1
1525 green = 2
1526 blue = 3
1527 with self.assertRaises(ValueError):
1528 class Color(UniqueEnum):
1529 red = 1
1530 green = 2
1531 blue = 3
1532 grene = 2
1533
1534 def test_init(self):
1535 class Planet(Enum):
1536 MERCURY = (3.303e+23, 2.4397e6)
1537 VENUS = (4.869e+24, 6.0518e6)
1538 EARTH = (5.976e+24, 6.37814e6)
1539 MARS = (6.421e+23, 3.3972e6)
1540 JUPITER = (1.9e+27, 7.1492e7)
1541 SATURN = (5.688e+26, 6.0268e7)
1542 URANUS = (8.686e+25, 2.5559e7)
1543 NEPTUNE = (1.024e+26, 2.4746e7)
1544 def __init__(self, mass, radius):
1545 self.mass = mass # in kilograms
1546 self.radius = radius # in meters
1547 @property
1548 def surface_gravity(self):
1549 # universal gravitational constant (m3 kg-1 s-2)
1550 G = 6.67300E-11
1551 return G * self.mass / (self.radius * self.radius)
1552 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1553 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1554
Ethan Furmana4b1bb42018-01-22 07:56:37 -08001555 def test_ignore(self):
1556 class Period(timedelta, Enum):
1557 '''
1558 different lengths of time
1559 '''
1560 def __new__(cls, value, period):
1561 obj = timedelta.__new__(cls, value)
1562 obj._value_ = value
1563 obj.period = period
1564 return obj
1565 _ignore_ = 'Period i'
1566 Period = vars()
1567 for i in range(13):
1568 Period['month_%d' % i] = i*30, 'month'
1569 for i in range(53):
1570 Period['week_%d' % i] = i*7, 'week'
1571 for i in range(32):
1572 Period['day_%d' % i] = i, 'day'
1573 OneDay = day_1
1574 OneWeek = week_1
1575 OneMonth = month_1
1576 self.assertFalse(hasattr(Period, '_ignore_'))
1577 self.assertFalse(hasattr(Period, 'Period'))
1578 self.assertFalse(hasattr(Period, 'i'))
1579 self.assertTrue(isinstance(Period.day_1, timedelta))
1580 self.assertTrue(Period.month_1 is Period.day_30)
1581 self.assertTrue(Period.week_4 is Period.day_28)
1582
Ethan Furman2aa27322013-07-19 19:35:56 -07001583 def test_nonhash_value(self):
1584 class AutoNumberInAList(Enum):
1585 def __new__(cls):
1586 value = [len(cls.__members__) + 1]
1587 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001588 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001589 return obj
1590 class ColorInAList(AutoNumberInAList):
1591 red = ()
1592 green = ()
1593 blue = ()
1594 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001595 for enum, value in zip(ColorInAList, range(3)):
1596 value += 1
1597 self.assertEqual(enum.value, [value])
1598 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001599
Ethan Furmanb41803e2013-07-25 13:50:45 -07001600 def test_conflicting_types_resolved_in_new(self):
1601 class LabelledIntEnum(int, Enum):
1602 def __new__(cls, *args):
1603 value, label = args
1604 obj = int.__new__(cls, value)
1605 obj.label = label
1606 obj._value_ = value
1607 return obj
1608
1609 class LabelledList(LabelledIntEnum):
1610 unprocessed = (1, "Unprocessed")
1611 payment_complete = (2, "Payment Complete")
1612
1613 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1614 self.assertEqual(LabelledList.unprocessed, 1)
1615 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001616
Ethan Furmanc16595e2016-09-10 23:36:59 -07001617 def test_auto_number(self):
1618 class Color(Enum):
1619 red = auto()
1620 blue = auto()
1621 green = auto()
1622
1623 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1624 self.assertEqual(Color.red.value, 1)
1625 self.assertEqual(Color.blue.value, 2)
1626 self.assertEqual(Color.green.value, 3)
1627
1628 def test_auto_name(self):
1629 class Color(Enum):
1630 def _generate_next_value_(name, start, count, last):
1631 return name
1632 red = auto()
1633 blue = auto()
1634 green = auto()
1635
1636 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1637 self.assertEqual(Color.red.value, 'red')
1638 self.assertEqual(Color.blue.value, 'blue')
1639 self.assertEqual(Color.green.value, 'green')
1640
1641 def test_auto_name_inherit(self):
1642 class AutoNameEnum(Enum):
1643 def _generate_next_value_(name, start, count, last):
1644 return name
1645 class Color(AutoNameEnum):
1646 red = auto()
1647 blue = auto()
1648 green = auto()
1649
1650 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1651 self.assertEqual(Color.red.value, 'red')
1652 self.assertEqual(Color.blue.value, 'blue')
1653 self.assertEqual(Color.green.value, 'green')
1654
1655 def test_auto_garbage(self):
1656 class Color(Enum):
1657 red = 'red'
1658 blue = auto()
1659 self.assertEqual(Color.blue.value, 1)
1660
1661 def test_auto_garbage_corrected(self):
1662 class Color(Enum):
1663 red = 'red'
1664 blue = 2
1665 green = auto()
1666
1667 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1668 self.assertEqual(Color.red.value, 'red')
1669 self.assertEqual(Color.blue.value, 2)
1670 self.assertEqual(Color.green.value, 3)
1671
Ethan Furman3515dcc2016-09-18 13:15:41 -07001672 def test_duplicate_auto(self):
1673 class Dupes(Enum):
1674 first = primero = auto()
1675 second = auto()
1676 third = auto()
1677 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1678
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001679
Ethan Furmane8e61272016-08-20 07:19:31 -07001680class TestOrder(unittest.TestCase):
1681
1682 def test_same_members(self):
1683 class Color(Enum):
1684 _order_ = 'red green blue'
1685 red = 1
1686 green = 2
1687 blue = 3
1688
1689 def test_same_members_with_aliases(self):
1690 class Color(Enum):
1691 _order_ = 'red green blue'
1692 red = 1
1693 green = 2
1694 blue = 3
1695 verde = green
1696
1697 def test_same_members_wrong_order(self):
1698 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1699 class Color(Enum):
1700 _order_ = 'red green blue'
1701 red = 1
1702 blue = 3
1703 green = 2
1704
1705 def test_order_has_extra_members(self):
1706 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1707 class Color(Enum):
1708 _order_ = 'red green blue purple'
1709 red = 1
1710 green = 2
1711 blue = 3
1712
1713 def test_order_has_extra_members_with_aliases(self):
1714 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1715 class Color(Enum):
1716 _order_ = 'red green blue purple'
1717 red = 1
1718 green = 2
1719 blue = 3
1720 verde = green
1721
1722 def test_enum_has_extra_members(self):
1723 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1724 class Color(Enum):
1725 _order_ = 'red green blue'
1726 red = 1
1727 green = 2
1728 blue = 3
1729 purple = 4
1730
1731 def test_enum_has_extra_members_with_aliases(self):
1732 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1733 class Color(Enum):
1734 _order_ = 'red green blue'
1735 red = 1
1736 green = 2
1737 blue = 3
1738 purple = 4
1739 verde = green
1740
1741
Ethan Furman65a5a472016-09-01 23:55:19 -07001742class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001743 """Tests of the Flags."""
1744
Ethan Furman65a5a472016-09-01 23:55:19 -07001745 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001746 R, W, X = 4, 2, 1
1747
Ethan Furman65a5a472016-09-01 23:55:19 -07001748 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001749 RO = 0
1750 WO = 1
1751 RW = 2
1752 AC = 3
1753 CE = 1<<19
1754
1755 def test_str(self):
1756 Perm = self.Perm
1757 self.assertEqual(str(Perm.R), 'Perm.R')
1758 self.assertEqual(str(Perm.W), 'Perm.W')
1759 self.assertEqual(str(Perm.X), 'Perm.X')
1760 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1761 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1762 self.assertEqual(str(Perm(0)), 'Perm.0')
1763 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1764 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1765 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1766 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1767 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1768 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1769
1770 Open = self.Open
1771 self.assertEqual(str(Open.RO), 'Open.RO')
1772 self.assertEqual(str(Open.WO), 'Open.WO')
1773 self.assertEqual(str(Open.AC), 'Open.AC')
1774 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1775 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001776 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001777 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1778 self.assertEqual(str(~Open.AC), 'Open.CE')
1779 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1780 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1781
1782 def test_repr(self):
1783 Perm = self.Perm
1784 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1785 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1786 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1787 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1788 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001789 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001790 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1791 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1792 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1793 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001794 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001795 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1796
1797 Open = self.Open
1798 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1799 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1800 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1801 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1802 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001803 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001804 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
1805 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
1806 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
1807 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
1808
1809 def test_or(self):
1810 Perm = self.Perm
1811 for i in Perm:
1812 for j in Perm:
1813 self.assertEqual((i | j), Perm(i.value | j.value))
1814 self.assertEqual((i | j).value, i.value | j.value)
1815 self.assertIs(type(i | j), Perm)
1816 for i in Perm:
1817 self.assertIs(i | i, i)
1818 Open = self.Open
1819 self.assertIs(Open.RO | Open.CE, Open.CE)
1820
1821 def test_and(self):
1822 Perm = self.Perm
1823 RW = Perm.R | Perm.W
1824 RX = Perm.R | Perm.X
1825 WX = Perm.W | Perm.X
1826 RWX = Perm.R | Perm.W | Perm.X
1827 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1828 for i in values:
1829 for j in values:
1830 self.assertEqual((i & j).value, i.value & j.value)
1831 self.assertIs(type(i & j), Perm)
1832 for i in Perm:
1833 self.assertIs(i & i, i)
1834 self.assertIs(i & RWX, i)
1835 self.assertIs(RWX & i, i)
1836 Open = self.Open
1837 self.assertIs(Open.RO & Open.CE, Open.RO)
1838
1839 def test_xor(self):
1840 Perm = self.Perm
1841 for i in Perm:
1842 for j in Perm:
1843 self.assertEqual((i ^ j).value, i.value ^ j.value)
1844 self.assertIs(type(i ^ j), Perm)
1845 for i in Perm:
1846 self.assertIs(i ^ Perm(0), i)
1847 self.assertIs(Perm(0) ^ i, i)
1848 Open = self.Open
1849 self.assertIs(Open.RO ^ Open.CE, Open.CE)
1850 self.assertIs(Open.CE ^ Open.CE, Open.RO)
1851
1852 def test_invert(self):
1853 Perm = self.Perm
1854 RW = Perm.R | Perm.W
1855 RX = Perm.R | Perm.X
1856 WX = Perm.W | Perm.X
1857 RWX = Perm.R | Perm.W | Perm.X
1858 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1859 for i in values:
1860 self.assertIs(type(~i), Perm)
1861 self.assertEqual(~~i, i)
1862 for i in Perm:
1863 self.assertIs(~~i, i)
1864 Open = self.Open
1865 self.assertIs(Open.WO & ~Open.WO, Open.RO)
1866 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
1867
Ethan Furman25d94bb2016-09-02 16:32:32 -07001868 def test_bool(self):
1869 Perm = self.Perm
1870 for f in Perm:
1871 self.assertTrue(f)
1872 Open = self.Open
1873 for f in Open:
1874 self.assertEqual(bool(f.value), bool(f))
1875
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001876 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001877 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001878 lst = list(Perm)
1879 self.assertEqual(len(lst), len(Perm))
1880 self.assertEqual(len(Perm), 3, Perm)
1881 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1882 for i, n in enumerate('R W X'.split()):
1883 v = 1<<i
1884 e = Perm(v)
1885 self.assertEqual(e.value, v)
1886 self.assertEqual(type(e.value), int)
1887 self.assertEqual(e.name, n)
1888 self.assertIn(e, Perm)
1889 self.assertIs(type(e), Perm)
1890
1891 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001892 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001893 lst = list(Perm)
1894 self.assertEqual(len(lst), len(Perm))
1895 self.assertEqual(len(Perm), 3, Perm)
1896 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1897 for i, n in enumerate('R W X'.split()):
1898 v = 8<<i
1899 e = Perm(v)
1900 self.assertEqual(e.value, v)
1901 self.assertEqual(type(e.value), int)
1902 self.assertEqual(e.name, n)
1903 self.assertIn(e, Perm)
1904 self.assertIs(type(e), Perm)
1905
1906 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001907 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001908 lst = list(Perm)
1909 self.assertEqual(len(lst), len(Perm))
1910 self.assertEqual(len(Perm), 3, Perm)
1911 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1912 for i, n in enumerate('R W X'.split()):
1913 v = 1<<i
1914 e = Perm(v)
1915 self.assertEqual(e.value, v)
1916 self.assertEqual(type(e.value), int)
1917 self.assertEqual(e.name, n)
1918 self.assertIn(e, Perm)
1919 self.assertIs(type(e), Perm)
1920
1921 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001922 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001923 lst = list(Perm)
1924 self.assertEqual(len(lst), len(Perm))
1925 self.assertEqual(len(Perm), 3, Perm)
1926 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1927 for i, n in enumerate('R W X'.split()):
1928 v = 1<<(2*i+1)
1929 e = Perm(v)
1930 self.assertEqual(e.value, v)
1931 self.assertEqual(type(e.value), int)
1932 self.assertEqual(e.name, n)
1933 self.assertIn(e, Perm)
1934 self.assertIs(type(e), Perm)
1935
1936 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001937 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001938 lst = list(Perm)
1939 self.assertEqual(len(lst), len(Perm))
1940 self.assertEqual(len(Perm), 3, Perm)
1941 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1942 for i, n in enumerate('R W X'.split()):
1943 v = 1<<(2*i+1)
1944 e = Perm(v)
1945 self.assertEqual(e.value, v)
1946 self.assertEqual(type(e.value), int)
1947 self.assertEqual(e.name, n)
1948 self.assertIn(e, Perm)
1949 self.assertIs(type(e), Perm)
1950
Ethan Furman65a5a472016-09-01 23:55:19 -07001951 def test_pickle(self):
1952 if isinstance(FlagStooges, Exception):
1953 raise FlagStooges
1954 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
1955 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001956
Ethan Furman65a5a472016-09-01 23:55:19 -07001957 def test_containment(self):
1958 Perm = self.Perm
1959 R, W, X = Perm
1960 RW = R | W
1961 RX = R | X
1962 WX = W | X
1963 RWX = R | W | X
1964 self.assertTrue(R in RW)
1965 self.assertTrue(R in RX)
1966 self.assertTrue(R in RWX)
1967 self.assertTrue(W in RW)
1968 self.assertTrue(W in WX)
1969 self.assertTrue(W in RWX)
1970 self.assertTrue(X in RX)
1971 self.assertTrue(X in WX)
1972 self.assertTrue(X in RWX)
1973 self.assertFalse(R in WX)
1974 self.assertFalse(W in RX)
1975 self.assertFalse(X in RW)
1976
Ethan Furmanc16595e2016-09-10 23:36:59 -07001977 def test_auto_number(self):
1978 class Color(Flag):
1979 red = auto()
1980 blue = auto()
1981 green = auto()
1982
1983 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1984 self.assertEqual(Color.red.value, 1)
1985 self.assertEqual(Color.blue.value, 2)
1986 self.assertEqual(Color.green.value, 4)
1987
1988 def test_auto_number_garbage(self):
1989 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
1990 class Color(Flag):
1991 red = 'not an int'
1992 blue = auto()
1993
Ethan Furman3515dcc2016-09-18 13:15:41 -07001994 def test_cascading_failure(self):
1995 class Bizarre(Flag):
1996 c = 3
1997 d = 4
1998 f = 6
1999 # Bizarre.c | Bizarre.d
2000 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2001 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
2002 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2003 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
2004 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2005 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
2006
2007 def test_duplicate_auto(self):
2008 class Dupes(Enum):
2009 first = primero = auto()
2010 second = auto()
2011 third = auto()
2012 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
2013
2014 def test_bizarre(self):
2015 class Bizarre(Flag):
2016 b = 3
2017 c = 4
2018 d = 6
2019 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
2020
Ethan Furman28cf6632017-01-24 12:12:06 -08002021 @support.reap_threads
2022 def test_unique_composite(self):
2023 # override __eq__ to be identity only
2024 class TestFlag(Flag):
2025 one = auto()
2026 two = auto()
2027 three = auto()
2028 four = auto()
2029 five = auto()
2030 six = auto()
2031 seven = auto()
2032 eight = auto()
2033 def __eq__(self, other):
2034 return self is other
2035 def __hash__(self):
2036 return hash(self._value_)
2037 # have multiple threads competing to complete the composite members
2038 seen = set()
2039 failed = False
2040 def cycle_enum():
2041 nonlocal failed
2042 try:
2043 for i in range(256):
2044 seen.add(TestFlag(i))
2045 except Exception:
2046 failed = True
2047 threads = [
2048 threading.Thread(target=cycle_enum)
2049 for _ in range(8)
2050 ]
2051 with support.start_threads(threads):
2052 pass
2053 # check that only 248 members were created
2054 self.assertFalse(
2055 failed,
2056 'at least one thread failed while creating composite members')
2057 self.assertEqual(256, len(seen), 'too many composite members created')
2058
Ethan Furmanc16595e2016-09-10 23:36:59 -07002059
Ethan Furman65a5a472016-09-01 23:55:19 -07002060class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002061 """Tests of the IntFlags."""
2062
Ethan Furman65a5a472016-09-01 23:55:19 -07002063 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002064 X = 1 << 0
2065 W = 1 << 1
2066 R = 1 << 2
2067
Ethan Furman65a5a472016-09-01 23:55:19 -07002068 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002069 RO = 0
2070 WO = 1
2071 RW = 2
2072 AC = 3
2073 CE = 1<<19
2074
Ethan Furman3515dcc2016-09-18 13:15:41 -07002075 def test_type(self):
2076 Perm = self.Perm
2077 Open = self.Open
2078 for f in Perm:
2079 self.assertTrue(isinstance(f, Perm))
2080 self.assertEqual(f, f.value)
2081 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2082 self.assertEqual(Perm.W | Perm.X, 3)
2083 for f in Open:
2084 self.assertTrue(isinstance(f, Open))
2085 self.assertEqual(f, f.value)
2086 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2087 self.assertEqual(Open.WO | Open.RW, 3)
2088
2089
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002090 def test_str(self):
2091 Perm = self.Perm
2092 self.assertEqual(str(Perm.R), 'Perm.R')
2093 self.assertEqual(str(Perm.W), 'Perm.W')
2094 self.assertEqual(str(Perm.X), 'Perm.X')
2095 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2096 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2097 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2098 self.assertEqual(str(Perm(0)), 'Perm.0')
2099 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002100 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2101 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2102 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2103 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002104 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002105 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2106 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2107 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002108
2109 Open = self.Open
2110 self.assertEqual(str(Open.RO), 'Open.RO')
2111 self.assertEqual(str(Open.WO), 'Open.WO')
2112 self.assertEqual(str(Open.AC), 'Open.AC')
2113 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2114 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2115 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002116 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2117 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2118 self.assertEqual(str(~Open.AC), 'Open.CE')
2119 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2120 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2121 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002122
2123 def test_repr(self):
2124 Perm = self.Perm
2125 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2126 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2127 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2128 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2129 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2130 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002131 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2132 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002133 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2134 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2135 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2136 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002137 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002138 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2139 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2140 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002141
2142 Open = self.Open
2143 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2144 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2145 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2146 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2147 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002148 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002149 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2150 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2151 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2152 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2153 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2154 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002155
2156 def test_or(self):
2157 Perm = self.Perm
2158 for i in Perm:
2159 for j in Perm:
2160 self.assertEqual(i | j, i.value | j.value)
2161 self.assertEqual((i | j).value, i.value | j.value)
2162 self.assertIs(type(i | j), Perm)
2163 for j in range(8):
2164 self.assertEqual(i | j, i.value | j)
2165 self.assertEqual((i | j).value, i.value | j)
2166 self.assertIs(type(i | j), Perm)
2167 self.assertEqual(j | i, j | i.value)
2168 self.assertEqual((j | i).value, j | i.value)
2169 self.assertIs(type(j | i), Perm)
2170 for i in Perm:
2171 self.assertIs(i | i, i)
2172 self.assertIs(i | 0, i)
2173 self.assertIs(0 | i, i)
2174 Open = self.Open
2175 self.assertIs(Open.RO | Open.CE, Open.CE)
2176
2177 def test_and(self):
2178 Perm = self.Perm
2179 RW = Perm.R | Perm.W
2180 RX = Perm.R | Perm.X
2181 WX = Perm.W | Perm.X
2182 RWX = Perm.R | Perm.W | Perm.X
2183 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2184 for i in values:
2185 for j in values:
2186 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2187 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2188 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2189 for j in range(8):
2190 self.assertEqual(i & j, i.value & j)
2191 self.assertEqual((i & j).value, i.value & j)
2192 self.assertIs(type(i & j), Perm)
2193 self.assertEqual(j & i, j & i.value)
2194 self.assertEqual((j & i).value, j & i.value)
2195 self.assertIs(type(j & i), Perm)
2196 for i in Perm:
2197 self.assertIs(i & i, i)
2198 self.assertIs(i & 7, i)
2199 self.assertIs(7 & i, i)
2200 Open = self.Open
2201 self.assertIs(Open.RO & Open.CE, Open.RO)
2202
2203 def test_xor(self):
2204 Perm = self.Perm
2205 for i in Perm:
2206 for j in Perm:
2207 self.assertEqual(i ^ j, i.value ^ j.value)
2208 self.assertEqual((i ^ j).value, i.value ^ j.value)
2209 self.assertIs(type(i ^ j), Perm)
2210 for j in range(8):
2211 self.assertEqual(i ^ j, i.value ^ j)
2212 self.assertEqual((i ^ j).value, i.value ^ j)
2213 self.assertIs(type(i ^ j), Perm)
2214 self.assertEqual(j ^ i, j ^ i.value)
2215 self.assertEqual((j ^ i).value, j ^ i.value)
2216 self.assertIs(type(j ^ i), Perm)
2217 for i in Perm:
2218 self.assertIs(i ^ 0, i)
2219 self.assertIs(0 ^ i, i)
2220 Open = self.Open
2221 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2222 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2223
2224 def test_invert(self):
2225 Perm = self.Perm
2226 RW = Perm.R | Perm.W
2227 RX = Perm.R | Perm.X
2228 WX = Perm.W | Perm.X
2229 RWX = Perm.R | Perm.W | Perm.X
2230 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2231 for i in values:
2232 self.assertEqual(~i, ~i.value)
2233 self.assertEqual((~i).value, ~i.value)
2234 self.assertIs(type(~i), Perm)
2235 self.assertEqual(~~i, i)
2236 for i in Perm:
2237 self.assertIs(~~i, i)
2238 Open = self.Open
2239 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2240 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2241
2242 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002243 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002244 lst = list(Perm)
2245 self.assertEqual(len(lst), len(Perm))
2246 self.assertEqual(len(Perm), 3, Perm)
2247 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2248 for i, n in enumerate('R W X'.split()):
2249 v = 1<<i
2250 e = Perm(v)
2251 self.assertEqual(e.value, v)
2252 self.assertEqual(type(e.value), int)
2253 self.assertEqual(e, v)
2254 self.assertEqual(e.name, n)
2255 self.assertIn(e, Perm)
2256 self.assertIs(type(e), Perm)
2257
2258 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002259 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002260 lst = list(Perm)
2261 self.assertEqual(len(lst), len(Perm))
2262 self.assertEqual(len(Perm), 3, Perm)
2263 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2264 for i, n in enumerate('R W X'.split()):
2265 v = 8<<i
2266 e = Perm(v)
2267 self.assertEqual(e.value, v)
2268 self.assertEqual(type(e.value), int)
2269 self.assertEqual(e, v)
2270 self.assertEqual(e.name, n)
2271 self.assertIn(e, Perm)
2272 self.assertIs(type(e), Perm)
2273
2274 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002275 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002276 lst = list(Perm)
2277 self.assertEqual(len(lst), len(Perm))
2278 self.assertEqual(len(Perm), 3, Perm)
2279 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2280 for i, n in enumerate('R W X'.split()):
2281 v = 1<<i
2282 e = Perm(v)
2283 self.assertEqual(e.value, v)
2284 self.assertEqual(type(e.value), int)
2285 self.assertEqual(e, v)
2286 self.assertEqual(e.name, n)
2287 self.assertIn(e, Perm)
2288 self.assertIs(type(e), Perm)
2289
2290 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002291 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002292 lst = list(Perm)
2293 self.assertEqual(len(lst), len(Perm))
2294 self.assertEqual(len(Perm), 3, Perm)
2295 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2296 for i, n in enumerate('R W X'.split()):
2297 v = 1<<(2*i+1)
2298 e = Perm(v)
2299 self.assertEqual(e.value, v)
2300 self.assertEqual(type(e.value), int)
2301 self.assertEqual(e, v)
2302 self.assertEqual(e.name, n)
2303 self.assertIn(e, Perm)
2304 self.assertIs(type(e), Perm)
2305
2306 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002307 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002308 lst = list(Perm)
2309 self.assertEqual(len(lst), len(Perm))
2310 self.assertEqual(len(Perm), 3, Perm)
2311 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2312 for i, n in enumerate('R W X'.split()):
2313 v = 1<<(2*i+1)
2314 e = Perm(v)
2315 self.assertEqual(e.value, v)
2316 self.assertEqual(type(e.value), int)
2317 self.assertEqual(e, v)
2318 self.assertEqual(e.name, n)
2319 self.assertIn(e, Perm)
2320 self.assertIs(type(e), Perm)
2321
2322
Dong-hee Nadcc8ce42017-06-22 01:52:32 +09002323 def test_programatic_function_from_empty_list(self):
2324 Perm = enum.IntFlag('Perm', [])
2325 lst = list(Perm)
2326 self.assertEqual(len(lst), len(Perm))
2327 self.assertEqual(len(Perm), 0, Perm)
2328 Thing = enum.Enum('Thing', [])
2329 lst = list(Thing)
2330 self.assertEqual(len(lst), len(Thing))
2331 self.assertEqual(len(Thing), 0, Thing)
2332
2333
2334 def test_programatic_function_from_empty_tuple(self):
2335 Perm = enum.IntFlag('Perm', ())
2336 lst = list(Perm)
2337 self.assertEqual(len(lst), len(Perm))
2338 self.assertEqual(len(Perm), 0, Perm)
2339 Thing = enum.Enum('Thing', ())
2340 self.assertEqual(len(lst), len(Thing))
2341 self.assertEqual(len(Thing), 0, Thing)
2342
Ethan Furman65a5a472016-09-01 23:55:19 -07002343 def test_containment(self):
2344 Perm = self.Perm
2345 R, W, X = Perm
2346 RW = R | W
2347 RX = R | X
2348 WX = W | X
2349 RWX = R | W | X
2350 self.assertTrue(R in RW)
2351 self.assertTrue(R in RX)
2352 self.assertTrue(R in RWX)
2353 self.assertTrue(W in RW)
2354 self.assertTrue(W in WX)
2355 self.assertTrue(W in RWX)
2356 self.assertTrue(X in RX)
2357 self.assertTrue(X in WX)
2358 self.assertTrue(X in RWX)
2359 self.assertFalse(R in WX)
2360 self.assertFalse(W in RX)
2361 self.assertFalse(X in RW)
2362
Ethan Furman25d94bb2016-09-02 16:32:32 -07002363 def test_bool(self):
2364 Perm = self.Perm
2365 for f in Perm:
2366 self.assertTrue(f)
2367 Open = self.Open
2368 for f in Open:
2369 self.assertEqual(bool(f.value), bool(f))
2370
Ethan Furman28cf6632017-01-24 12:12:06 -08002371 @support.reap_threads
2372 def test_unique_composite(self):
2373 # override __eq__ to be identity only
2374 class TestFlag(IntFlag):
2375 one = auto()
2376 two = auto()
2377 three = auto()
2378 four = auto()
2379 five = auto()
2380 six = auto()
2381 seven = auto()
2382 eight = auto()
2383 def __eq__(self, other):
2384 return self is other
2385 def __hash__(self):
2386 return hash(self._value_)
2387 # have multiple threads competing to complete the composite members
2388 seen = set()
2389 failed = False
2390 def cycle_enum():
2391 nonlocal failed
2392 try:
2393 for i in range(256):
2394 seen.add(TestFlag(i))
2395 except Exception:
2396 failed = True
2397 threads = [
2398 threading.Thread(target=cycle_enum)
2399 for _ in range(8)
2400 ]
2401 with support.start_threads(threads):
2402 pass
2403 # check that only 248 members were created
2404 self.assertFalse(
2405 failed,
2406 'at least one thread failed while creating composite members')
2407 self.assertEqual(256, len(seen), 'too many composite members created')
2408
2409
Ethan Furmanf24bb352013-07-18 17:05:39 -07002410class TestUnique(unittest.TestCase):
2411
2412 def test_unique_clean(self):
2413 @unique
2414 class Clean(Enum):
2415 one = 1
2416 two = 'dos'
2417 tres = 4.0
2418 @unique
2419 class Cleaner(IntEnum):
2420 single = 1
2421 double = 2
2422 triple = 3
2423
2424 def test_unique_dirty(self):
2425 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2426 @unique
2427 class Dirty(Enum):
2428 one = 1
2429 two = 'dos'
2430 tres = 1
2431 with self.assertRaisesRegex(
2432 ValueError,
2433 'double.*single.*turkey.*triple',
2434 ):
2435 @unique
2436 class Dirtier(IntEnum):
2437 single = 1
2438 double = 1
2439 triple = 3
2440 turkey = 3
2441
Ethan Furman3803ad42016-05-01 10:03:53 -07002442 def test_unique_with_name(self):
2443 @unique
2444 class Silly(Enum):
2445 one = 1
2446 two = 'dos'
2447 name = 3
2448 @unique
2449 class Sillier(IntEnum):
2450 single = 1
2451 name = 2
2452 triple = 3
2453 value = 4
2454
Ethan Furmanf24bb352013-07-18 17:05:39 -07002455
Ethan Furman3323da92015-04-11 09:39:59 -07002456expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002457Help on class Color in module %s:
2458
2459class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002460 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2461 |\x20\x20
Ethan Furman48a724f2015-04-11 23:23:06 -07002462 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002463 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002464 | Method resolution order:
2465 | Color
2466 | enum.Enum
2467 | builtins.object
2468 |\x20\x20
2469 | Data and other attributes defined here:
2470 |\x20\x20
2471 | blue = <Color.blue: 3>
2472 |\x20\x20
2473 | green = <Color.green: 2>
2474 |\x20\x20
2475 | red = <Color.red: 1>
2476 |\x20\x20
2477 | ----------------------------------------------------------------------
2478 | Data descriptors inherited from enum.Enum:
2479 |\x20\x20
2480 | name
2481 | The name of the Enum member.
2482 |\x20\x20
2483 | value
2484 | The value of the Enum member.
2485 |\x20\x20
2486 | ----------------------------------------------------------------------
2487 | Data descriptors inherited from enum.EnumMeta:
2488 |\x20\x20
2489 | __members__
2490 | Returns a mapping of member name->value.
2491 |\x20\x20\x20\x20\x20\x20
2492 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002493 | is a read-only view of the internal mapping."""
2494
2495expected_help_output_without_docs = """\
2496Help on class Color in module %s:
2497
2498class Color(enum.Enum)
Serhiy Storchaka90f63322017-01-24 09:06:22 +02002499 | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
2500 |\x20\x20
Ethan Furman3323da92015-04-11 09:39:59 -07002501 | Method resolution order:
2502 | Color
2503 | enum.Enum
2504 | builtins.object
2505 |\x20\x20
2506 | Data and other attributes defined here:
2507 |\x20\x20
2508 | blue = <Color.blue: 3>
2509 |\x20\x20
2510 | green = <Color.green: 2>
2511 |\x20\x20
2512 | red = <Color.red: 1>
2513 |\x20\x20
2514 | ----------------------------------------------------------------------
2515 | Data descriptors inherited from enum.Enum:
2516 |\x20\x20
2517 | name
2518 |\x20\x20
2519 | value
2520 |\x20\x20
2521 | ----------------------------------------------------------------------
2522 | Data descriptors inherited from enum.EnumMeta:
2523 |\x20\x20
2524 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002525
2526class TestStdLib(unittest.TestCase):
2527
Ethan Furman48a724f2015-04-11 23:23:06 -07002528 maxDiff = None
2529
Ethan Furman5875d742013-10-21 20:45:55 -07002530 class Color(Enum):
2531 red = 1
2532 green = 2
2533 blue = 3
2534
2535 def test_pydoc(self):
2536 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002537 if StrEnum.__doc__ is None:
2538 expected_text = expected_help_output_without_docs % __name__
2539 else:
2540 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002541 output = StringIO()
2542 helper = pydoc.Helper(output=output)
2543 helper(self.Color)
2544 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002545 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002546
2547 def test_inspect_getmembers(self):
2548 values = dict((
2549 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002550 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002551 ('__members__', self.Color.__members__),
2552 ('__module__', __name__),
2553 ('blue', self.Color.blue),
2554 ('green', self.Color.green),
2555 ('name', Enum.__dict__['name']),
2556 ('red', self.Color.red),
2557 ('value', Enum.__dict__['value']),
2558 ))
2559 result = dict(inspect.getmembers(self.Color))
2560 self.assertEqual(values.keys(), result.keys())
2561 failed = False
2562 for k in values.keys():
2563 if result[k] != values[k]:
2564 print()
2565 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2566 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2567 failed = True
2568 if failed:
2569 self.fail("result does not equal expected, see print above")
2570
2571 def test_inspect_classify_class_attrs(self):
2572 # indirectly test __objclass__
2573 from inspect import Attribute
2574 values = [
2575 Attribute(name='__class__', kind='data',
2576 defining_class=object, object=EnumMeta),
2577 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002578 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002579 Attribute(name='__members__', kind='property',
2580 defining_class=EnumMeta, object=EnumMeta.__members__),
2581 Attribute(name='__module__', kind='data',
2582 defining_class=self.Color, object=__name__),
2583 Attribute(name='blue', kind='data',
2584 defining_class=self.Color, object=self.Color.blue),
2585 Attribute(name='green', kind='data',
2586 defining_class=self.Color, object=self.Color.green),
2587 Attribute(name='red', kind='data',
2588 defining_class=self.Color, object=self.Color.red),
2589 Attribute(name='name', kind='data',
2590 defining_class=Enum, object=Enum.__dict__['name']),
2591 Attribute(name='value', kind='data',
2592 defining_class=Enum, object=Enum.__dict__['value']),
2593 ]
2594 values.sort(key=lambda item: item.name)
2595 result = list(inspect.classify_class_attrs(self.Color))
2596 result.sort(key=lambda item: item.name)
2597 failed = False
2598 for v, r in zip(values, result):
2599 if r != v:
2600 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2601 failed = True
2602 if failed:
2603 self.fail("result does not equal expected, see print above")
2604
Martin Panter19e69c52015-11-14 12:46:42 +00002605
2606class MiscTestCase(unittest.TestCase):
2607 def test__all__(self):
2608 support.check__all__(self, enum)
2609
2610
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002611# These are unordered here on purpose to ensure that declaration order
2612# makes no difference.
2613CONVERT_TEST_NAME_D = 5
2614CONVERT_TEST_NAME_C = 5
2615CONVERT_TEST_NAME_B = 5
2616CONVERT_TEST_NAME_A = 5 # This one should sort first.
2617CONVERT_TEST_NAME_E = 5
2618CONVERT_TEST_NAME_F = 5
2619
2620class TestIntEnumConvert(unittest.TestCase):
2621 def test_convert_value_lookup_priority(self):
2622 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002623 'UnittestConvert',
2624 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002625 filter=lambda x: x.startswith('CONVERT_TEST_'))
2626 # We don't want the reverse lookup value to vary when there are
2627 # multiple possible names for a given value. It should always
2628 # report the first lexigraphical name in that case.
2629 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2630
2631 def test_convert(self):
2632 test_type = enum.IntEnum._convert(
Ethan Furman28cf6632017-01-24 12:12:06 -08002633 'UnittestConvert',
2634 ('test.test_enum', '__main__')[__name__=='__main__'],
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002635 filter=lambda x: x.startswith('CONVERT_TEST_'))
2636 # Ensure that test_type has all of the desired names and values.
2637 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2638 test_type.CONVERT_TEST_NAME_A)
2639 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2640 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2641 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2642 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2643 # Ensure that test_type only picked up names matching the filter.
2644 self.assertEqual([name for name in dir(test_type)
2645 if name[0:2] not in ('CO', '__')],
2646 [], msg='Names other than CONVERT_TEST_* found.')
2647
2648
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002649if __name__ == '__main__':
2650 unittest.main()