blob: e97ef947b1d8f2bcd821f5e2bcf86513d02619ca [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import enum
Ethan Furman5875d742013-10-21 20:45:55 -07002import inspect
3import pydoc
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004import unittest
5from collections import OrderedDict
Ethan Furmanc16595e2016-09-10 23:36:59 -07006from enum import Enum, IntEnum, EnumMeta, Flag, IntFlag, unique, auto
Ethan Furman5875d742013-10-21 20:45:55 -07007from io import StringIO
Ethan Furman2ddb39a2014-02-06 17:28:50 -08008from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
Martin Panter19e69c52015-11-14 12:46:42 +00009from test import support
Ethan Furman6b3d64a2013-06-14 16:55:46 -070010
11# for pickle tests
12try:
13 class Stooges(Enum):
14 LARRY = 1
15 CURLY = 2
16 MOE = 3
17except Exception as exc:
18 Stooges = exc
19
20try:
21 class IntStooges(int, Enum):
22 LARRY = 1
23 CURLY = 2
24 MOE = 3
25except Exception as exc:
26 IntStooges = exc
27
28try:
29 class FloatStooges(float, Enum):
30 LARRY = 1.39
31 CURLY = 2.72
32 MOE = 3.142596
33except Exception as exc:
34 FloatStooges = exc
35
Ethan Furman65a5a472016-09-01 23:55:19 -070036try:
37 class FlagStooges(Flag):
38 LARRY = 1
39 CURLY = 2
40 MOE = 3
41except Exception as exc:
42 FlagStooges = exc
43
Ethan Furman6b3d64a2013-06-14 16:55:46 -070044# for pickle test and subclass tests
45try:
46 class StrEnum(str, Enum):
47 'accepts only string values'
48 class Name(StrEnum):
49 BDFL = 'Guido van Rossum'
50 FLUFL = 'Barry Warsaw'
51except Exception as exc:
52 Name = exc
53
54try:
55 Question = Enum('Question', 'who what when where why', module=__name__)
56except Exception as exc:
57 Question = exc
58
59try:
60 Answer = Enum('Answer', 'him this then there because')
61except Exception as exc:
62 Answer = exc
63
Ethan Furmanca1b7942014-02-08 11:36:27 -080064try:
65 Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
66except Exception as exc:
67 Theory = exc
68
Ethan Furman6b3d64a2013-06-14 16:55:46 -070069# for doctests
70try:
71 class Fruit(Enum):
Ethan Furman23bb6f42016-11-21 09:22:05 -080072 TOMATO = 1
73 BANANA = 2
74 CHERRY = 3
Ethan Furman6b3d64a2013-06-14 16:55:46 -070075except Exception:
76 pass
77
Serhiy Storchakae50e7802015-03-31 16:56:49 +030078def test_pickle_dump_load(assertion, source, target=None):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080079 if target is None:
80 target = source
Serhiy Storchakae50e7802015-03-31 16:56:49 +030081 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080082 assertion(loads(dumps(source, protocol=protocol)), target)
83
Serhiy Storchakae50e7802015-03-31 16:56:49 +030084def test_pickle_exception(assertion, exception, obj):
85 for protocol in range(HIGHEST_PROTOCOL + 1):
Ethan Furman2ddb39a2014-02-06 17:28:50 -080086 with assertion(exception):
87 dumps(obj, protocol=protocol)
Ethan Furman648f8602013-10-06 17:19:54 -070088
89class TestHelpers(unittest.TestCase):
90 # _is_descriptor, _is_sunder, _is_dunder
91
92 def test_is_descriptor(self):
93 class foo:
94 pass
95 for attr in ('__get__','__set__','__delete__'):
96 obj = foo()
97 self.assertFalse(enum._is_descriptor(obj))
98 setattr(obj, attr, 1)
99 self.assertTrue(enum._is_descriptor(obj))
100
101 def test_is_sunder(self):
102 for s in ('_a_', '_aa_'):
103 self.assertTrue(enum._is_sunder(s))
104
105 for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
106 '__', '___', '____', '_____',):
107 self.assertFalse(enum._is_sunder(s))
108
109 def test_is_dunder(self):
110 for s in ('__a__', '__aa__'):
111 self.assertTrue(enum._is_dunder(s))
112 for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
113 '__', '___', '____', '_____',):
114 self.assertFalse(enum._is_dunder(s))
115
Ethan Furmanc16595e2016-09-10 23:36:59 -0700116# tests
Ethan Furman648f8602013-10-06 17:19:54 -0700117
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700118class TestEnum(unittest.TestCase):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800119
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700120 def setUp(self):
121 class Season(Enum):
122 SPRING = 1
123 SUMMER = 2
124 AUTUMN = 3
125 WINTER = 4
126 self.Season = Season
127
Ethan Furmanec15a822013-08-31 19:17:41 -0700128 class Konstants(float, Enum):
129 E = 2.7182818
130 PI = 3.1415926
131 TAU = 2 * PI
132 self.Konstants = Konstants
133
134 class Grades(IntEnum):
135 A = 5
136 B = 4
137 C = 3
138 D = 2
139 F = 0
140 self.Grades = Grades
141
142 class Directional(str, Enum):
143 EAST = 'east'
144 WEST = 'west'
145 NORTH = 'north'
146 SOUTH = 'south'
147 self.Directional = Directional
148
149 from datetime import date
150 class Holiday(date, Enum):
151 NEW_YEAR = 2013, 1, 1
152 IDES_OF_MARCH = 2013, 3, 15
153 self.Holiday = Holiday
154
Ethan Furman388a3922013-08-12 06:51:41 -0700155 def test_dir_on_class(self):
156 Season = self.Season
157 self.assertEqual(
158 set(dir(Season)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700159 set(['__class__', '__doc__', '__members__', '__module__',
Ethan Furman388a3922013-08-12 06:51:41 -0700160 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER']),
161 )
162
163 def test_dir_on_item(self):
164 Season = self.Season
165 self.assertEqual(
166 set(dir(Season.WINTER)),
Ethan Furmanc850f342013-09-15 16:59:35 -0700167 set(['__class__', '__doc__', '__module__', 'name', 'value']),
Ethan Furman388a3922013-08-12 06:51:41 -0700168 )
169
Ethan Furmanc850f342013-09-15 16:59:35 -0700170 def test_dir_with_added_behavior(self):
171 class Test(Enum):
172 this = 'that'
173 these = 'those'
174 def wowser(self):
175 return ("Wowser! I'm %s!" % self.name)
176 self.assertEqual(
177 set(dir(Test)),
178 set(['__class__', '__doc__', '__members__', '__module__', 'this', 'these']),
179 )
180 self.assertEqual(
181 set(dir(Test.this)),
182 set(['__class__', '__doc__', '__module__', 'name', 'value', 'wowser']),
183 )
184
Ethan Furman0ae550b2014-10-14 08:58:32 -0700185 def test_dir_on_sub_with_behavior_on_super(self):
186 # see issue22506
187 class SuperEnum(Enum):
188 def invisible(self):
189 return "did you see me?"
190 class SubEnum(SuperEnum):
191 sample = 5
192 self.assertEqual(
193 set(dir(SubEnum.sample)),
194 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
195 )
196
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700197 def test_enum_in_enum_out(self):
198 Season = self.Season
199 self.assertIs(Season(Season.WINTER), Season.WINTER)
200
201 def test_enum_value(self):
202 Season = self.Season
203 self.assertEqual(Season.SPRING.value, 1)
204
205 def test_intenum_value(self):
206 self.assertEqual(IntStooges.CURLY.value, 2)
207
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700208 def test_enum(self):
209 Season = self.Season
210 lst = list(Season)
211 self.assertEqual(len(lst), len(Season))
212 self.assertEqual(len(Season), 4, Season)
213 self.assertEqual(
214 [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
215
216 for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 1):
217 e = Season(i)
218 self.assertEqual(e, getattr(Season, season))
219 self.assertEqual(e.value, i)
220 self.assertNotEqual(e, i)
221 self.assertEqual(e.name, season)
222 self.assertIn(e, Season)
223 self.assertIs(type(e), Season)
224 self.assertIsInstance(e, Season)
225 self.assertEqual(str(e), 'Season.' + season)
226 self.assertEqual(
227 repr(e),
228 '<Season.{0}: {1}>'.format(season, i),
229 )
230
231 def test_value_name(self):
232 Season = self.Season
233 self.assertEqual(Season.SPRING.name, 'SPRING')
234 self.assertEqual(Season.SPRING.value, 1)
235 with self.assertRaises(AttributeError):
236 Season.SPRING.name = 'invierno'
237 with self.assertRaises(AttributeError):
238 Season.SPRING.value = 2
239
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700240 def test_changing_member(self):
241 Season = self.Season
242 with self.assertRaises(AttributeError):
243 Season.WINTER = 'really cold'
244
Ethan Furman64a99722013-09-22 16:18:19 -0700245 def test_attribute_deletion(self):
246 class Season(Enum):
247 SPRING = 1
248 SUMMER = 2
249 AUTUMN = 3
250 WINTER = 4
251
252 def spam(cls):
253 pass
254
255 self.assertTrue(hasattr(Season, 'spam'))
256 del Season.spam
257 self.assertFalse(hasattr(Season, 'spam'))
258
259 with self.assertRaises(AttributeError):
260 del Season.SPRING
261 with self.assertRaises(AttributeError):
262 del Season.DRY
263 with self.assertRaises(AttributeError):
264 del Season.SPRING.name
265
Ethan Furman5de67b12016-04-13 23:52:09 -0700266 def test_bool_of_class(self):
267 class Empty(Enum):
268 pass
269 self.assertTrue(bool(Empty))
270
271 def test_bool_of_member(self):
272 class Count(Enum):
273 zero = 0
274 one = 1
275 two = 2
276 for member in Count:
277 self.assertTrue(bool(member))
278
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700279 def test_invalid_names(self):
280 with self.assertRaises(ValueError):
281 class Wrong(Enum):
282 mro = 9
283 with self.assertRaises(ValueError):
284 class Wrong(Enum):
285 _create_= 11
286 with self.assertRaises(ValueError):
287 class Wrong(Enum):
288 _get_mixins_ = 9
289 with self.assertRaises(ValueError):
290 class Wrong(Enum):
291 _find_new_ = 1
292 with self.assertRaises(ValueError):
293 class Wrong(Enum):
294 _any_name_ = 9
295
Ethan Furman6db1fd52015-09-17 21:49:12 -0700296 def test_bool(self):
Ethan Furman60255b62016-01-15 15:01:33 -0800297 # plain Enum members are always True
Ethan Furman6db1fd52015-09-17 21:49:12 -0700298 class Logic(Enum):
299 true = True
300 false = False
301 self.assertTrue(Logic.true)
Ethan Furman60255b62016-01-15 15:01:33 -0800302 self.assertTrue(Logic.false)
303 # unless overridden
304 class RealLogic(Enum):
305 true = True
306 false = False
307 def __bool__(self):
308 return bool(self._value_)
309 self.assertTrue(RealLogic.true)
310 self.assertFalse(RealLogic.false)
311 # mixed Enums depend on mixed-in type
312 class IntLogic(int, Enum):
313 true = 1
314 false = 0
315 self.assertTrue(IntLogic.true)
316 self.assertFalse(IntLogic.false)
Ethan Furman6db1fd52015-09-17 21:49:12 -0700317
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700318 def test_contains(self):
319 Season = self.Season
320 self.assertIn(Season.AUTUMN, Season)
321 self.assertNotIn(3, Season)
322
323 val = Season(3)
324 self.assertIn(val, Season)
325
326 class OtherEnum(Enum):
327 one = 1; two = 2
328 self.assertNotIn(OtherEnum.two, Season)
329
330 def test_comparisons(self):
331 Season = self.Season
332 with self.assertRaises(TypeError):
333 Season.SPRING < Season.WINTER
334 with self.assertRaises(TypeError):
335 Season.SPRING > 4
336
337 self.assertNotEqual(Season.SPRING, 1)
338
339 class Part(Enum):
340 SPRING = 1
341 CLIP = 2
342 BARREL = 3
343
344 self.assertNotEqual(Season.SPRING, Part.SPRING)
345 with self.assertRaises(TypeError):
346 Season.SPRING < Part.CLIP
347
348 def test_enum_duplicates(self):
349 class Season(Enum):
350 SPRING = 1
351 SUMMER = 2
352 AUTUMN = FALL = 3
353 WINTER = 4
354 ANOTHER_SPRING = 1
355 lst = list(Season)
356 self.assertEqual(
357 lst,
358 [Season.SPRING, Season.SUMMER,
359 Season.AUTUMN, Season.WINTER,
360 ])
361 self.assertIs(Season.FALL, Season.AUTUMN)
362 self.assertEqual(Season.FALL.value, 3)
363 self.assertEqual(Season.AUTUMN.value, 3)
364 self.assertIs(Season(3), Season.AUTUMN)
365 self.assertIs(Season(1), Season.SPRING)
366 self.assertEqual(Season.FALL.name, 'AUTUMN')
367 self.assertEqual(
368 [k for k,v in Season.__members__.items() if v.name != k],
369 ['FALL', 'ANOTHER_SPRING'],
370 )
371
Ethan Furman101e0742013-09-15 12:34:36 -0700372 def test_duplicate_name(self):
373 with self.assertRaises(TypeError):
374 class Color(Enum):
375 red = 1
376 green = 2
377 blue = 3
378 red = 4
379
380 with self.assertRaises(TypeError):
381 class Color(Enum):
382 red = 1
383 green = 2
384 blue = 3
385 def red(self):
386 return 'red'
387
388 with self.assertRaises(TypeError):
389 class Color(Enum):
390 @property
391 def red(self):
392 return 'redder'
393 red = 1
394 green = 2
395 blue = 3
396
397
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700398 def test_enum_with_value_name(self):
399 class Huh(Enum):
400 name = 1
401 value = 2
402 self.assertEqual(
403 list(Huh),
404 [Huh.name, Huh.value],
405 )
406 self.assertIs(type(Huh.name), Huh)
407 self.assertEqual(Huh.name.name, 'name')
408 self.assertEqual(Huh.name.value, 1)
Ethan Furmanec15a822013-08-31 19:17:41 -0700409
410 def test_format_enum(self):
411 Season = self.Season
412 self.assertEqual('{}'.format(Season.SPRING),
413 '{}'.format(str(Season.SPRING)))
414 self.assertEqual( '{:}'.format(Season.SPRING),
415 '{:}'.format(str(Season.SPRING)))
416 self.assertEqual('{:20}'.format(Season.SPRING),
417 '{:20}'.format(str(Season.SPRING)))
418 self.assertEqual('{:^20}'.format(Season.SPRING),
419 '{:^20}'.format(str(Season.SPRING)))
420 self.assertEqual('{:>20}'.format(Season.SPRING),
421 '{:>20}'.format(str(Season.SPRING)))
422 self.assertEqual('{:<20}'.format(Season.SPRING),
423 '{:<20}'.format(str(Season.SPRING)))
424
425 def test_format_enum_custom(self):
426 class TestFloat(float, Enum):
427 one = 1.0
428 two = 2.0
429 def __format__(self, spec):
430 return 'TestFloat success!'
431 self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
432
433 def assertFormatIsValue(self, spec, member):
434 self.assertEqual(spec.format(member), spec.format(member.value))
435
436 def test_format_enum_date(self):
437 Holiday = self.Holiday
438 self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
439 self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
440 self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
441 self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
442 self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
443 self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
444 self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
445 self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
446
447 def test_format_enum_float(self):
448 Konstants = self.Konstants
449 self.assertFormatIsValue('{}', Konstants.TAU)
450 self.assertFormatIsValue('{:}', Konstants.TAU)
451 self.assertFormatIsValue('{:20}', Konstants.TAU)
452 self.assertFormatIsValue('{:^20}', Konstants.TAU)
453 self.assertFormatIsValue('{:>20}', Konstants.TAU)
454 self.assertFormatIsValue('{:<20}', Konstants.TAU)
455 self.assertFormatIsValue('{:n}', Konstants.TAU)
456 self.assertFormatIsValue('{:5.2}', Konstants.TAU)
457 self.assertFormatIsValue('{:f}', Konstants.TAU)
458
459 def test_format_enum_int(self):
460 Grades = self.Grades
461 self.assertFormatIsValue('{}', Grades.C)
462 self.assertFormatIsValue('{:}', Grades.C)
463 self.assertFormatIsValue('{:20}', Grades.C)
464 self.assertFormatIsValue('{:^20}', Grades.C)
465 self.assertFormatIsValue('{:>20}', Grades.C)
466 self.assertFormatIsValue('{:<20}', Grades.C)
467 self.assertFormatIsValue('{:+}', Grades.C)
468 self.assertFormatIsValue('{:08X}', Grades.C)
469 self.assertFormatIsValue('{:b}', Grades.C)
470
471 def test_format_enum_str(self):
472 Directional = self.Directional
473 self.assertFormatIsValue('{}', Directional.WEST)
474 self.assertFormatIsValue('{:}', Directional.WEST)
475 self.assertFormatIsValue('{:20}', Directional.WEST)
476 self.assertFormatIsValue('{:^20}', Directional.WEST)
477 self.assertFormatIsValue('{:>20}', Directional.WEST)
478 self.assertFormatIsValue('{:<20}', Directional.WEST)
479
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700480 def test_hash(self):
481 Season = self.Season
482 dates = {}
483 dates[Season.WINTER] = '1225'
484 dates[Season.SPRING] = '0315'
485 dates[Season.SUMMER] = '0704'
486 dates[Season.AUTUMN] = '1031'
487 self.assertEqual(dates[Season.AUTUMN], '1031')
488
489 def test_intenum_from_scratch(self):
490 class phy(int, Enum):
491 pi = 3
492 tau = 2 * pi
493 self.assertTrue(phy.pi < phy.tau)
494
495 def test_intenum_inherited(self):
496 class IntEnum(int, Enum):
497 pass
498 class phy(IntEnum):
499 pi = 3
500 tau = 2 * pi
501 self.assertTrue(phy.pi < phy.tau)
502
503 def test_floatenum_from_scratch(self):
504 class phy(float, Enum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700505 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700506 tau = 2 * pi
507 self.assertTrue(phy.pi < phy.tau)
508
509 def test_floatenum_inherited(self):
510 class FloatEnum(float, Enum):
511 pass
512 class phy(FloatEnum):
Ethan Furmanec15a822013-08-31 19:17:41 -0700513 pi = 3.1415926
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700514 tau = 2 * pi
515 self.assertTrue(phy.pi < phy.tau)
516
517 def test_strenum_from_scratch(self):
518 class phy(str, Enum):
519 pi = 'Pi'
520 tau = 'Tau'
521 self.assertTrue(phy.pi < phy.tau)
522
523 def test_strenum_inherited(self):
524 class StrEnum(str, Enum):
525 pass
526 class phy(StrEnum):
527 pi = 'Pi'
528 tau = 'Tau'
529 self.assertTrue(phy.pi < phy.tau)
530
531
532 def test_intenum(self):
533 class WeekDay(IntEnum):
534 SUNDAY = 1
535 MONDAY = 2
536 TUESDAY = 3
537 WEDNESDAY = 4
538 THURSDAY = 5
539 FRIDAY = 6
540 SATURDAY = 7
541
542 self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c')
543 self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2])
544
545 lst = list(WeekDay)
546 self.assertEqual(len(lst), len(WeekDay))
547 self.assertEqual(len(WeekDay), 7)
548 target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'
549 target = target.split()
550 for i, weekday in enumerate(target, 1):
551 e = WeekDay(i)
552 self.assertEqual(e, i)
553 self.assertEqual(int(e), i)
554 self.assertEqual(e.name, weekday)
555 self.assertIn(e, WeekDay)
556 self.assertEqual(lst.index(e)+1, i)
557 self.assertTrue(0 < e < 8)
558 self.assertIs(type(e), WeekDay)
559 self.assertIsInstance(e, int)
560 self.assertIsInstance(e, Enum)
561
562 def test_intenum_duplicates(self):
563 class WeekDay(IntEnum):
564 SUNDAY = 1
565 MONDAY = 2
566 TUESDAY = TEUSDAY = 3
567 WEDNESDAY = 4
568 THURSDAY = 5
569 FRIDAY = 6
570 SATURDAY = 7
571 self.assertIs(WeekDay.TEUSDAY, WeekDay.TUESDAY)
572 self.assertEqual(WeekDay(3).name, 'TUESDAY')
573 self.assertEqual([k for k,v in WeekDay.__members__.items()
574 if v.name != k], ['TEUSDAY', ])
575
Serhiy Storchakaea36c942016-05-12 10:37:58 +0300576 def test_intenum_from_bytes(self):
577 self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
578 with self.assertRaises(ValueError):
579 IntStooges.from_bytes(b'\x00\x05', 'big')
580
581 def test_floatenum_fromhex(self):
582 h = float.hex(FloatStooges.MOE.value)
583 self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
584 h = float.hex(FloatStooges.MOE.value + 0.01)
585 with self.assertRaises(ValueError):
586 FloatStooges.fromhex(h)
587
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700588 def test_pickle_enum(self):
589 if isinstance(Stooges, Exception):
590 raise Stooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800591 test_pickle_dump_load(self.assertIs, Stooges.CURLY)
592 test_pickle_dump_load(self.assertIs, Stooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700593
594 def test_pickle_int(self):
595 if isinstance(IntStooges, Exception):
596 raise IntStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800597 test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
598 test_pickle_dump_load(self.assertIs, IntStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700599
600 def test_pickle_float(self):
601 if isinstance(FloatStooges, Exception):
602 raise FloatStooges
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800603 test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
604 test_pickle_dump_load(self.assertIs, FloatStooges)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700605
606 def test_pickle_enum_function(self):
607 if isinstance(Answer, Exception):
608 raise Answer
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800609 test_pickle_dump_load(self.assertIs, Answer.him)
610 test_pickle_dump_load(self.assertIs, Answer)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700611
612 def test_pickle_enum_function_with_module(self):
613 if isinstance(Question, Exception):
614 raise Question
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800615 test_pickle_dump_load(self.assertIs, Question.who)
616 test_pickle_dump_load(self.assertIs, Question)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700617
Ethan Furmanca1b7942014-02-08 11:36:27 -0800618 def test_enum_function_with_qualname(self):
619 if isinstance(Theory, Exception):
620 raise Theory
621 self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
622
623 def test_class_nested_enum_and_pickle_protocol_four(self):
624 # would normally just have this directly in the class namespace
625 class NestedEnum(Enum):
626 twigs = 'common'
627 shiny = 'rare'
628
629 self.__class__.NestedEnum = NestedEnum
630 self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
Serhiy Storchakae50e7802015-03-31 16:56:49 +0300631 test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
Ethan Furmanca1b7942014-02-08 11:36:27 -0800632
Ethan Furman24e837f2015-03-18 17:27:57 -0700633 def test_pickle_by_name(self):
634 class ReplaceGlobalInt(IntEnum):
635 ONE = 1
636 TWO = 2
637 ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_name
638 for proto in range(HIGHEST_PROTOCOL):
639 self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
640
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700641 def test_exploding_pickle(self):
Ethan Furmanca1b7942014-02-08 11:36:27 -0800642 BadPickle = Enum(
643 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700644 globals()['BadPickle'] = BadPickle
Ethan Furmanca1b7942014-02-08 11:36:27 -0800645 # now break BadPickle to test exception raising
646 enum._make_class_unpicklable(BadPickle)
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800647 test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
648 test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700649
650 def test_string_enum(self):
651 class SkillLevel(str, Enum):
652 master = 'what is the sound of one hand clapping?'
653 journeyman = 'why did the chicken cross the road?'
654 apprentice = 'knock, knock!'
655 self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
656
657 def test_getattr_getitem(self):
658 class Period(Enum):
659 morning = 1
660 noon = 2
661 evening = 3
662 night = 4
663 self.assertIs(Period(2), Period.noon)
664 self.assertIs(getattr(Period, 'night'), Period.night)
665 self.assertIs(Period['morning'], Period.morning)
666
667 def test_getattr_dunder(self):
668 Season = self.Season
669 self.assertTrue(getattr(Season, '__eq__'))
670
671 def test_iteration_order(self):
672 class Season(Enum):
673 SUMMER = 2
674 WINTER = 4
675 AUTUMN = 3
676 SPRING = 1
677 self.assertEqual(
678 list(Season),
679 [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
680 )
681
Ethan Furman2131a4a2013-09-14 18:11:24 -0700682 def test_reversed_iteration_order(self):
683 self.assertEqual(
684 list(reversed(self.Season)),
685 [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
686 self.Season.SPRING]
687 )
688
Martin Pantereb995702016-07-28 01:11:04 +0000689 def test_programmatic_function_string(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700690 SummerMonth = Enum('SummerMonth', 'june july august')
691 lst = list(SummerMonth)
692 self.assertEqual(len(lst), len(SummerMonth))
693 self.assertEqual(len(SummerMonth), 3, SummerMonth)
694 self.assertEqual(
695 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
696 lst,
697 )
698 for i, month in enumerate('june july august'.split(), 1):
699 e = SummerMonth(i)
700 self.assertEqual(int(e.value), i)
701 self.assertNotEqual(e, i)
702 self.assertEqual(e.name, month)
703 self.assertIn(e, SummerMonth)
704 self.assertIs(type(e), SummerMonth)
705
Martin Pantereb995702016-07-28 01:11:04 +0000706 def test_programmatic_function_string_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700707 SummerMonth = Enum('SummerMonth', 'june july august', start=10)
708 lst = list(SummerMonth)
709 self.assertEqual(len(lst), len(SummerMonth))
710 self.assertEqual(len(SummerMonth), 3, SummerMonth)
711 self.assertEqual(
712 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
713 lst,
714 )
715 for i, month in enumerate('june july august'.split(), 10):
716 e = SummerMonth(i)
717 self.assertEqual(int(e.value), i)
718 self.assertNotEqual(e, i)
719 self.assertEqual(e.name, month)
720 self.assertIn(e, SummerMonth)
721 self.assertIs(type(e), SummerMonth)
722
Martin Pantereb995702016-07-28 01:11:04 +0000723 def test_programmatic_function_string_list(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700724 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'])
725 lst = list(SummerMonth)
726 self.assertEqual(len(lst), len(SummerMonth))
727 self.assertEqual(len(SummerMonth), 3, SummerMonth)
728 self.assertEqual(
729 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
730 lst,
731 )
732 for i, month in enumerate('june july august'.split(), 1):
733 e = SummerMonth(i)
734 self.assertEqual(int(e.value), i)
735 self.assertNotEqual(e, i)
736 self.assertEqual(e.name, month)
737 self.assertIn(e, SummerMonth)
738 self.assertIs(type(e), SummerMonth)
739
Martin Pantereb995702016-07-28 01:11:04 +0000740 def test_programmatic_function_string_list_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700741 SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20)
742 lst = list(SummerMonth)
743 self.assertEqual(len(lst), len(SummerMonth))
744 self.assertEqual(len(SummerMonth), 3, SummerMonth)
745 self.assertEqual(
746 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
747 lst,
748 )
749 for i, month in enumerate('june july august'.split(), 20):
750 e = SummerMonth(i)
751 self.assertEqual(int(e.value), i)
752 self.assertNotEqual(e, i)
753 self.assertEqual(e.name, month)
754 self.assertIn(e, SummerMonth)
755 self.assertIs(type(e), SummerMonth)
756
Martin Pantereb995702016-07-28 01:11:04 +0000757 def test_programmatic_function_iterable(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700758 SummerMonth = Enum(
759 'SummerMonth',
760 (('june', 1), ('july', 2), ('august', 3))
761 )
762 lst = list(SummerMonth)
763 self.assertEqual(len(lst), len(SummerMonth))
764 self.assertEqual(len(SummerMonth), 3, SummerMonth)
765 self.assertEqual(
766 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
767 lst,
768 )
769 for i, month in enumerate('june july august'.split(), 1):
770 e = SummerMonth(i)
771 self.assertEqual(int(e.value), i)
772 self.assertNotEqual(e, i)
773 self.assertEqual(e.name, month)
774 self.assertIn(e, SummerMonth)
775 self.assertIs(type(e), SummerMonth)
776
Martin Pantereb995702016-07-28 01:11:04 +0000777 def test_programmatic_function_from_dict(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700778 SummerMonth = Enum(
779 'SummerMonth',
780 OrderedDict((('june', 1), ('july', 2), ('august', 3)))
781 )
782 lst = list(SummerMonth)
783 self.assertEqual(len(lst), len(SummerMonth))
784 self.assertEqual(len(SummerMonth), 3, SummerMonth)
785 self.assertEqual(
786 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
787 lst,
788 )
789 for i, month in enumerate('june july august'.split(), 1):
790 e = SummerMonth(i)
791 self.assertEqual(int(e.value), i)
792 self.assertNotEqual(e, i)
793 self.assertEqual(e.name, month)
794 self.assertIn(e, SummerMonth)
795 self.assertIs(type(e), SummerMonth)
796
Martin Pantereb995702016-07-28 01:11:04 +0000797 def test_programmatic_function_type(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700798 SummerMonth = Enum('SummerMonth', 'june july august', type=int)
799 lst = list(SummerMonth)
800 self.assertEqual(len(lst), len(SummerMonth))
801 self.assertEqual(len(SummerMonth), 3, SummerMonth)
802 self.assertEqual(
803 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
804 lst,
805 )
806 for i, month in enumerate('june july august'.split(), 1):
807 e = SummerMonth(i)
808 self.assertEqual(e, i)
809 self.assertEqual(e.name, month)
810 self.assertIn(e, SummerMonth)
811 self.assertIs(type(e), SummerMonth)
812
Martin Pantereb995702016-07-28 01:11:04 +0000813 def test_programmatic_function_type_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700814 SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30)
815 lst = list(SummerMonth)
816 self.assertEqual(len(lst), len(SummerMonth))
817 self.assertEqual(len(SummerMonth), 3, SummerMonth)
818 self.assertEqual(
819 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
820 lst,
821 )
822 for i, month in enumerate('june july august'.split(), 30):
823 e = SummerMonth(i)
824 self.assertEqual(e, i)
825 self.assertEqual(e.name, month)
826 self.assertIn(e, SummerMonth)
827 self.assertIs(type(e), SummerMonth)
828
Martin Pantereb995702016-07-28 01:11:04 +0000829 def test_programmatic_function_type_from_subclass(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700830 SummerMonth = IntEnum('SummerMonth', 'june july august')
831 lst = list(SummerMonth)
832 self.assertEqual(len(lst), len(SummerMonth))
833 self.assertEqual(len(SummerMonth), 3, SummerMonth)
834 self.assertEqual(
835 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
836 lst,
837 )
838 for i, month in enumerate('june july august'.split(), 1):
839 e = SummerMonth(i)
840 self.assertEqual(e, i)
841 self.assertEqual(e.name, month)
842 self.assertIn(e, SummerMonth)
843 self.assertIs(type(e), SummerMonth)
844
Martin Pantereb995702016-07-28 01:11:04 +0000845 def test_programmatic_function_type_from_subclass_with_start(self):
Ethan Furmand9925a12014-09-16 20:35:55 -0700846 SummerMonth = IntEnum('SummerMonth', 'june july august', start=40)
847 lst = list(SummerMonth)
848 self.assertEqual(len(lst), len(SummerMonth))
849 self.assertEqual(len(SummerMonth), 3, SummerMonth)
850 self.assertEqual(
851 [SummerMonth.june, SummerMonth.july, SummerMonth.august],
852 lst,
853 )
854 for i, month in enumerate('june july august'.split(), 40):
855 e = SummerMonth(i)
856 self.assertEqual(e, i)
857 self.assertEqual(e.name, month)
858 self.assertIn(e, SummerMonth)
859 self.assertIs(type(e), SummerMonth)
860
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700861 def test_subclassing(self):
862 if isinstance(Name, Exception):
863 raise Name
864 self.assertEqual(Name.BDFL, 'Guido van Rossum')
865 self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
866 self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
Ethan Furman2ddb39a2014-02-06 17:28:50 -0800867 test_pickle_dump_load(self.assertIs, Name.BDFL)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700868
869 def test_extending(self):
870 class Color(Enum):
871 red = 1
872 green = 2
873 blue = 3
874 with self.assertRaises(TypeError):
875 class MoreColor(Color):
876 cyan = 4
877 magenta = 5
878 yellow = 6
879
880 def test_exclude_methods(self):
881 class whatever(Enum):
882 this = 'that'
883 these = 'those'
884 def really(self):
885 return 'no, not %s' % self.value
886 self.assertIsNot(type(whatever.really), whatever)
887 self.assertEqual(whatever.this.really(), 'no, not that')
888
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700889 def test_wrong_inheritance_order(self):
890 with self.assertRaises(TypeError):
891 class Wrong(Enum, str):
892 NotHere = 'error before this point'
893
894 def test_intenum_transitivity(self):
895 class number(IntEnum):
896 one = 1
897 two = 2
898 three = 3
899 class numero(IntEnum):
900 uno = 1
901 dos = 2
902 tres = 3
903 self.assertEqual(number.one, numero.uno)
904 self.assertEqual(number.two, numero.dos)
905 self.assertEqual(number.three, numero.tres)
906
907 def test_wrong_enum_in_call(self):
908 class Monochrome(Enum):
909 black = 0
910 white = 1
911 class Gender(Enum):
912 male = 0
913 female = 1
914 self.assertRaises(ValueError, Monochrome, Gender.male)
915
916 def test_wrong_enum_in_mixed_call(self):
917 class Monochrome(IntEnum):
918 black = 0
919 white = 1
920 class Gender(Enum):
921 male = 0
922 female = 1
923 self.assertRaises(ValueError, Monochrome, Gender.male)
924
925 def test_mixed_enum_in_call_1(self):
926 class Monochrome(IntEnum):
927 black = 0
928 white = 1
929 class Gender(IntEnum):
930 male = 0
931 female = 1
932 self.assertIs(Monochrome(Gender.female), Monochrome.white)
933
934 def test_mixed_enum_in_call_2(self):
935 class Monochrome(Enum):
936 black = 0
937 white = 1
938 class Gender(IntEnum):
939 male = 0
940 female = 1
941 self.assertIs(Monochrome(Gender.male), Monochrome.black)
942
943 def test_flufl_enum(self):
944 class Fluflnum(Enum):
945 def __int__(self):
946 return int(self.value)
947 class MailManOptions(Fluflnum):
948 option1 = 1
949 option2 = 2
950 option3 = 3
951 self.assertEqual(int(MailManOptions.option1), 1)
952
Ethan Furman5e5a8232013-08-04 08:42:23 -0700953 def test_introspection(self):
954 class Number(IntEnum):
955 one = 100
956 two = 200
957 self.assertIs(Number.one._member_type_, int)
958 self.assertIs(Number._member_type_, int)
959 class String(str, Enum):
960 yarn = 'soft'
961 rope = 'rough'
962 wire = 'hard'
963 self.assertIs(String.yarn._member_type_, str)
964 self.assertIs(String._member_type_, str)
965 class Plain(Enum):
966 vanilla = 'white'
967 one = 1
968 self.assertIs(Plain.vanilla._member_type_, object)
969 self.assertIs(Plain._member_type_, object)
970
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700971 def test_no_such_enum_member(self):
972 class Color(Enum):
973 red = 1
974 green = 2
975 blue = 3
976 with self.assertRaises(ValueError):
977 Color(4)
978 with self.assertRaises(KeyError):
979 Color['chartreuse']
980
981 def test_new_repr(self):
982 class Color(Enum):
983 red = 1
984 green = 2
985 blue = 3
986 def __repr__(self):
987 return "don't you just love shades of %s?" % self.name
988 self.assertEqual(
989 repr(Color.blue),
990 "don't you just love shades of blue?",
991 )
992
993 def test_inherited_repr(self):
994 class MyEnum(Enum):
995 def __repr__(self):
996 return "My name is %s." % self.name
997 class MyIntEnum(int, MyEnum):
998 this = 1
999 that = 2
1000 theother = 3
1001 self.assertEqual(repr(MyIntEnum.that), "My name is that.")
1002
1003 def test_multiple_mixin_mro(self):
1004 class auto_enum(type(Enum)):
1005 def __new__(metacls, cls, bases, classdict):
1006 temp = type(classdict)()
1007 names = set(classdict._member_names)
1008 i = 0
1009 for k in classdict._member_names:
1010 v = classdict[k]
1011 if v is Ellipsis:
1012 v = i
1013 else:
1014 i = v
1015 i += 1
1016 temp[k] = v
1017 for k, v in classdict.items():
1018 if k not in names:
1019 temp[k] = v
1020 return super(auto_enum, metacls).__new__(
1021 metacls, cls, bases, temp)
1022
1023 class AutoNumberedEnum(Enum, metaclass=auto_enum):
1024 pass
1025
1026 class AutoIntEnum(IntEnum, metaclass=auto_enum):
1027 pass
1028
1029 class TestAutoNumber(AutoNumberedEnum):
1030 a = ...
1031 b = 3
1032 c = ...
1033
1034 class TestAutoInt(AutoIntEnum):
1035 a = ...
1036 b = 3
1037 c = ...
1038
1039 def test_subclasses_with_getnewargs(self):
1040 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001041 __qualname__ = 'NamedInt' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001042 def __new__(cls, *args):
1043 _args = args
1044 name, *args = args
1045 if len(args) == 0:
1046 raise TypeError("name and value must be specified")
1047 self = int.__new__(cls, *args)
1048 self._intname = name
1049 self._args = _args
1050 return self
1051 def __getnewargs__(self):
1052 return self._args
1053 @property
1054 def __name__(self):
1055 return self._intname
1056 def __repr__(self):
1057 # repr() is updated to include the name and type info
1058 return "{}({!r}, {})".format(type(self).__name__,
1059 self.__name__,
1060 int.__repr__(self))
1061 def __str__(self):
1062 # str() is unchanged, even if it relies on the repr() fallback
1063 base = int
1064 base_str = base.__str__
1065 if base_str.__objclass__ is object:
1066 return base.__repr__(self)
1067 return base_str(self)
1068 # for simplicity, we only define one operator that
1069 # propagates expressions
1070 def __add__(self, other):
1071 temp = int(self) + int( other)
1072 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1073 return NamedInt(
1074 '({0} + {1})'.format(self.__name__, other.__name__),
1075 temp )
1076 else:
1077 return temp
1078
1079 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001080 __qualname__ = 'NEI' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001081 x = ('the-x', 1)
1082 y = ('the-y', 2)
1083
Ethan Furman2aa27322013-07-19 19:35:56 -07001084
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001085 self.assertIs(NEI.__new__, Enum.__new__)
1086 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1087 globals()['NamedInt'] = NamedInt
1088 globals()['NEI'] = NEI
1089 NI5 = NamedInt('test', 5)
1090 self.assertEqual(NI5, 5)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001091 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001092 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001093 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001094 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001095
Ethan Furmanca1b7942014-02-08 11:36:27 -08001096 def test_subclasses_with_getnewargs_ex(self):
1097 class NamedInt(int):
1098 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1099 def __new__(cls, *args):
1100 _args = args
1101 name, *args = args
1102 if len(args) == 0:
1103 raise TypeError("name and value must be specified")
1104 self = int.__new__(cls, *args)
1105 self._intname = name
1106 self._args = _args
1107 return self
1108 def __getnewargs_ex__(self):
1109 return self._args, {}
1110 @property
1111 def __name__(self):
1112 return self._intname
1113 def __repr__(self):
1114 # repr() is updated to include the name and type info
1115 return "{}({!r}, {})".format(type(self).__name__,
1116 self.__name__,
1117 int.__repr__(self))
1118 def __str__(self):
1119 # str() is unchanged, even if it relies on the repr() fallback
1120 base = int
1121 base_str = base.__str__
1122 if base_str.__objclass__ is object:
1123 return base.__repr__(self)
1124 return base_str(self)
1125 # for simplicity, we only define one operator that
1126 # propagates expressions
1127 def __add__(self, other):
1128 temp = int(self) + int( other)
1129 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1130 return NamedInt(
1131 '({0} + {1})'.format(self.__name__, other.__name__),
1132 temp )
1133 else:
1134 return temp
1135
1136 class NEI(NamedInt, Enum):
1137 __qualname__ = 'NEI' # needed for pickle protocol 4
1138 x = ('the-x', 1)
1139 y = ('the-y', 2)
1140
1141
1142 self.assertIs(NEI.__new__, Enum.__new__)
1143 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1144 globals()['NamedInt'] = NamedInt
1145 globals()['NEI'] = NEI
1146 NI5 = NamedInt('test', 5)
1147 self.assertEqual(NI5, 5)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001148 test_pickle_dump_load(self.assertEqual, NI5, 5)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001149 self.assertEqual(NEI.y.value, 2)
Serhiy Storchakae50e7802015-03-31 16:56:49 +03001150 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001151 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001152
1153 def test_subclasses_with_reduce(self):
1154 class NamedInt(int):
1155 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1156 def __new__(cls, *args):
1157 _args = args
1158 name, *args = args
1159 if len(args) == 0:
1160 raise TypeError("name and value must be specified")
1161 self = int.__new__(cls, *args)
1162 self._intname = name
1163 self._args = _args
1164 return self
1165 def __reduce__(self):
1166 return self.__class__, self._args
1167 @property
1168 def __name__(self):
1169 return self._intname
1170 def __repr__(self):
1171 # repr() is updated to include the name and type info
1172 return "{}({!r}, {})".format(type(self).__name__,
1173 self.__name__,
1174 int.__repr__(self))
1175 def __str__(self):
1176 # str() is unchanged, even if it relies on the repr() fallback
1177 base = int
1178 base_str = base.__str__
1179 if base_str.__objclass__ is object:
1180 return base.__repr__(self)
1181 return base_str(self)
1182 # for simplicity, we only define one operator that
1183 # propagates expressions
1184 def __add__(self, other):
1185 temp = int(self) + int( other)
1186 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1187 return NamedInt(
1188 '({0} + {1})'.format(self.__name__, other.__name__),
1189 temp )
1190 else:
1191 return temp
1192
1193 class NEI(NamedInt, Enum):
1194 __qualname__ = 'NEI' # needed for pickle protocol 4
1195 x = ('the-x', 1)
1196 y = ('the-y', 2)
1197
1198
1199 self.assertIs(NEI.__new__, Enum.__new__)
1200 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1201 globals()['NamedInt'] = NamedInt
1202 globals()['NEI'] = NEI
1203 NI5 = NamedInt('test', 5)
1204 self.assertEqual(NI5, 5)
1205 test_pickle_dump_load(self.assertEqual, NI5, 5)
1206 self.assertEqual(NEI.y.value, 2)
1207 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001208 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001209
1210 def test_subclasses_with_reduce_ex(self):
1211 class NamedInt(int):
1212 __qualname__ = 'NamedInt' # needed for pickle protocol 4
1213 def __new__(cls, *args):
1214 _args = args
1215 name, *args = args
1216 if len(args) == 0:
1217 raise TypeError("name and value must be specified")
1218 self = int.__new__(cls, *args)
1219 self._intname = name
1220 self._args = _args
1221 return self
1222 def __reduce_ex__(self, proto):
1223 return self.__class__, self._args
1224 @property
1225 def __name__(self):
1226 return self._intname
1227 def __repr__(self):
1228 # repr() is updated to include the name and type info
1229 return "{}({!r}, {})".format(type(self).__name__,
1230 self.__name__,
1231 int.__repr__(self))
1232 def __str__(self):
1233 # str() is unchanged, even if it relies on the repr() fallback
1234 base = int
1235 base_str = base.__str__
1236 if base_str.__objclass__ is object:
1237 return base.__repr__(self)
1238 return base_str(self)
1239 # for simplicity, we only define one operator that
1240 # propagates expressions
1241 def __add__(self, other):
1242 temp = int(self) + int( other)
1243 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1244 return NamedInt(
1245 '({0} + {1})'.format(self.__name__, other.__name__),
1246 temp )
1247 else:
1248 return temp
1249
1250 class NEI(NamedInt, Enum):
1251 __qualname__ = 'NEI' # needed for pickle protocol 4
1252 x = ('the-x', 1)
1253 y = ('the-y', 2)
1254
1255
1256 self.assertIs(NEI.__new__, Enum.__new__)
1257 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1258 globals()['NamedInt'] = NamedInt
1259 globals()['NEI'] = NEI
1260 NI5 = NamedInt('test', 5)
1261 self.assertEqual(NI5, 5)
1262 test_pickle_dump_load(self.assertEqual, NI5, 5)
1263 self.assertEqual(NEI.y.value, 2)
1264 test_pickle_dump_load(self.assertIs, NEI.y)
Ethan Furmandc870522014-02-18 12:37:12 -08001265 test_pickle_dump_load(self.assertIs, NEI)
Ethan Furmanca1b7942014-02-08 11:36:27 -08001266
Ethan Furmandc870522014-02-18 12:37:12 -08001267 def test_subclasses_without_direct_pickle_support(self):
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001268 class NamedInt(int):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001269 __qualname__ = 'NamedInt'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001270 def __new__(cls, *args):
1271 _args = args
1272 name, *args = args
1273 if len(args) == 0:
1274 raise TypeError("name and value must be specified")
1275 self = int.__new__(cls, *args)
1276 self._intname = name
1277 self._args = _args
1278 return self
1279 @property
1280 def __name__(self):
1281 return self._intname
1282 def __repr__(self):
1283 # repr() is updated to include the name and type info
1284 return "{}({!r}, {})".format(type(self).__name__,
1285 self.__name__,
1286 int.__repr__(self))
1287 def __str__(self):
1288 # str() is unchanged, even if it relies on the repr() fallback
1289 base = int
1290 base_str = base.__str__
1291 if base_str.__objclass__ is object:
1292 return base.__repr__(self)
1293 return base_str(self)
1294 # for simplicity, we only define one operator that
1295 # propagates expressions
1296 def __add__(self, other):
1297 temp = int(self) + int( other)
1298 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1299 return NamedInt(
1300 '({0} + {1})'.format(self.__name__, other.__name__),
1301 temp )
1302 else:
1303 return temp
1304
1305 class NEI(NamedInt, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001306 __qualname__ = 'NEI'
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001307 x = ('the-x', 1)
1308 y = ('the-y', 2)
1309
1310 self.assertIs(NEI.__new__, Enum.__new__)
1311 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1312 globals()['NamedInt'] = NamedInt
1313 globals()['NEI'] = NEI
1314 NI5 = NamedInt('test', 5)
1315 self.assertEqual(NI5, 5)
1316 self.assertEqual(NEI.y.value, 2)
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001317 test_pickle_exception(self.assertRaises, TypeError, NEI.x)
1318 test_pickle_exception(self.assertRaises, PicklingError, NEI)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001319
Ethan Furmandc870522014-02-18 12:37:12 -08001320 def test_subclasses_without_direct_pickle_support_using_name(self):
1321 class NamedInt(int):
1322 __qualname__ = 'NamedInt'
1323 def __new__(cls, *args):
1324 _args = args
1325 name, *args = args
1326 if len(args) == 0:
1327 raise TypeError("name and value must be specified")
1328 self = int.__new__(cls, *args)
1329 self._intname = name
1330 self._args = _args
1331 return self
1332 @property
1333 def __name__(self):
1334 return self._intname
1335 def __repr__(self):
1336 # repr() is updated to include the name and type info
1337 return "{}({!r}, {})".format(type(self).__name__,
1338 self.__name__,
1339 int.__repr__(self))
1340 def __str__(self):
1341 # str() is unchanged, even if it relies on the repr() fallback
1342 base = int
1343 base_str = base.__str__
1344 if base_str.__objclass__ is object:
1345 return base.__repr__(self)
1346 return base_str(self)
1347 # for simplicity, we only define one operator that
1348 # propagates expressions
1349 def __add__(self, other):
1350 temp = int(self) + int( other)
1351 if isinstance(self, NamedInt) and isinstance(other, NamedInt):
1352 return NamedInt(
1353 '({0} + {1})'.format(self.__name__, other.__name__),
1354 temp )
1355 else:
1356 return temp
1357
1358 class NEI(NamedInt, Enum):
1359 __qualname__ = 'NEI'
1360 x = ('the-x', 1)
1361 y = ('the-y', 2)
1362 def __reduce_ex__(self, proto):
1363 return getattr, (self.__class__, self._name_)
1364
1365 self.assertIs(NEI.__new__, Enum.__new__)
1366 self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
1367 globals()['NamedInt'] = NamedInt
1368 globals()['NEI'] = NEI
1369 NI5 = NamedInt('test', 5)
1370 self.assertEqual(NI5, 5)
1371 self.assertEqual(NEI.y.value, 2)
1372 test_pickle_dump_load(self.assertIs, NEI.y)
1373 test_pickle_dump_load(self.assertIs, NEI)
1374
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001375 def test_tuple_subclass(self):
1376 class SomeTuple(tuple, Enum):
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001377 __qualname__ = 'SomeTuple' # needed for pickle protocol 4
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001378 first = (1, 'for the money')
1379 second = (2, 'for the show')
1380 third = (3, 'for the music')
1381 self.assertIs(type(SomeTuple.first), SomeTuple)
1382 self.assertIsInstance(SomeTuple.second, tuple)
1383 self.assertEqual(SomeTuple.third, (3, 'for the music'))
1384 globals()['SomeTuple'] = SomeTuple
Ethan Furman2ddb39a2014-02-06 17:28:50 -08001385 test_pickle_dump_load(self.assertIs, SomeTuple.first)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001386
1387 def test_duplicate_values_give_unique_enum_items(self):
1388 class AutoNumber(Enum):
1389 first = ()
1390 second = ()
1391 third = ()
1392 def __new__(cls):
1393 value = len(cls.__members__) + 1
1394 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001395 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001396 return obj
1397 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001398 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001399 self.assertEqual(
1400 list(AutoNumber),
1401 [AutoNumber.first, AutoNumber.second, AutoNumber.third],
1402 )
1403 self.assertEqual(int(AutoNumber.second), 2)
Ethan Furman2aa27322013-07-19 19:35:56 -07001404 self.assertEqual(AutoNumber.third.value, 3)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001405 self.assertIs(AutoNumber(1), AutoNumber.first)
1406
1407 def test_inherited_new_from_enhanced_enum(self):
1408 class AutoNumber(Enum):
1409 def __new__(cls):
1410 value = len(cls.__members__) + 1
1411 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001412 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001413 return obj
1414 def __int__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001415 return int(self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001416 class Color(AutoNumber):
1417 red = ()
1418 green = ()
1419 blue = ()
1420 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1421 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1422
1423 def test_inherited_new_from_mixed_enum(self):
1424 class AutoNumber(IntEnum):
1425 def __new__(cls):
1426 value = len(cls.__members__) + 1
1427 obj = int.__new__(cls, value)
Ethan Furman520ad572013-07-19 19:47:21 -07001428 obj._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001429 return obj
1430 class Color(AutoNumber):
1431 red = ()
1432 green = ()
1433 blue = ()
1434 self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
1435 self.assertEqual(list(map(int, Color)), [1, 2, 3])
1436
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001437 def test_equality(self):
1438 class AlwaysEqual:
1439 def __eq__(self, other):
1440 return True
1441 class OrdinaryEnum(Enum):
1442 a = 1
1443 self.assertEqual(AlwaysEqual(), OrdinaryEnum.a)
1444 self.assertEqual(OrdinaryEnum.a, AlwaysEqual())
1445
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001446 def test_ordered_mixin(self):
1447 class OrderedEnum(Enum):
1448 def __ge__(self, other):
1449 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001450 return self._value_ >= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001451 return NotImplemented
1452 def __gt__(self, other):
1453 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001454 return self._value_ > other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001455 return NotImplemented
1456 def __le__(self, other):
1457 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001458 return self._value_ <= other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001459 return NotImplemented
1460 def __lt__(self, other):
1461 if self.__class__ is other.__class__:
Ethan Furman520ad572013-07-19 19:47:21 -07001462 return self._value_ < other._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001463 return NotImplemented
1464 class Grade(OrderedEnum):
1465 A = 5
1466 B = 4
1467 C = 3
1468 D = 2
1469 F = 1
1470 self.assertGreater(Grade.A, Grade.B)
1471 self.assertLessEqual(Grade.F, Grade.C)
1472 self.assertLess(Grade.D, Grade.A)
1473 self.assertGreaterEqual(Grade.B, Grade.B)
Ethan Furmanbe3c2fe2013-11-13 14:25:45 -08001474 self.assertEqual(Grade.B, Grade.B)
1475 self.assertNotEqual(Grade.C, Grade.D)
Ethan Furman520ad572013-07-19 19:47:21 -07001476
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001477 def test_extending2(self):
1478 class Shade(Enum):
1479 def shade(self):
1480 print(self.name)
1481 class Color(Shade):
1482 red = 1
1483 green = 2
1484 blue = 3
1485 with self.assertRaises(TypeError):
1486 class MoreColor(Color):
1487 cyan = 4
1488 magenta = 5
1489 yellow = 6
1490
1491 def test_extending3(self):
1492 class Shade(Enum):
1493 def shade(self):
1494 return self.name
1495 class Color(Shade):
1496 def hex(self):
1497 return '%s hexlified!' % self.value
1498 class MoreColor(Color):
1499 cyan = 4
1500 magenta = 5
1501 yellow = 6
1502 self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
1503
1504
1505 def test_no_duplicates(self):
1506 class UniqueEnum(Enum):
1507 def __init__(self, *args):
1508 cls = self.__class__
1509 if any(self.value == e.value for e in cls):
1510 a = self.name
1511 e = cls(self.value).name
1512 raise ValueError(
1513 "aliases not allowed in UniqueEnum: %r --> %r"
1514 % (a, e)
1515 )
1516 class Color(UniqueEnum):
1517 red = 1
1518 green = 2
1519 blue = 3
1520 with self.assertRaises(ValueError):
1521 class Color(UniqueEnum):
1522 red = 1
1523 green = 2
1524 blue = 3
1525 grene = 2
1526
1527 def test_init(self):
1528 class Planet(Enum):
1529 MERCURY = (3.303e+23, 2.4397e6)
1530 VENUS = (4.869e+24, 6.0518e6)
1531 EARTH = (5.976e+24, 6.37814e6)
1532 MARS = (6.421e+23, 3.3972e6)
1533 JUPITER = (1.9e+27, 7.1492e7)
1534 SATURN = (5.688e+26, 6.0268e7)
1535 URANUS = (8.686e+25, 2.5559e7)
1536 NEPTUNE = (1.024e+26, 2.4746e7)
1537 def __init__(self, mass, radius):
1538 self.mass = mass # in kilograms
1539 self.radius = radius # in meters
1540 @property
1541 def surface_gravity(self):
1542 # universal gravitational constant (m3 kg-1 s-2)
1543 G = 6.67300E-11
1544 return G * self.mass / (self.radius * self.radius)
1545 self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
1546 self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
1547
Ethan Furman2aa27322013-07-19 19:35:56 -07001548 def test_nonhash_value(self):
1549 class AutoNumberInAList(Enum):
1550 def __new__(cls):
1551 value = [len(cls.__members__) + 1]
1552 obj = object.__new__(cls)
Ethan Furman520ad572013-07-19 19:47:21 -07001553 obj._value_ = value
Ethan Furman2aa27322013-07-19 19:35:56 -07001554 return obj
1555 class ColorInAList(AutoNumberInAList):
1556 red = ()
1557 green = ()
1558 blue = ()
1559 self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
Ethan Furman1a162882013-10-16 19:09:31 -07001560 for enum, value in zip(ColorInAList, range(3)):
1561 value += 1
1562 self.assertEqual(enum.value, [value])
1563 self.assertIs(ColorInAList([value]), enum)
Ethan Furman2aa27322013-07-19 19:35:56 -07001564
Ethan Furmanb41803e2013-07-25 13:50:45 -07001565 def test_conflicting_types_resolved_in_new(self):
1566 class LabelledIntEnum(int, Enum):
1567 def __new__(cls, *args):
1568 value, label = args
1569 obj = int.__new__(cls, value)
1570 obj.label = label
1571 obj._value_ = value
1572 return obj
1573
1574 class LabelledList(LabelledIntEnum):
1575 unprocessed = (1, "Unprocessed")
1576 payment_complete = (2, "Payment Complete")
1577
1578 self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
1579 self.assertEqual(LabelledList.unprocessed, 1)
1580 self.assertEqual(LabelledList(1), LabelledList.unprocessed)
Ethan Furman2aa27322013-07-19 19:35:56 -07001581
Ethan Furmanc16595e2016-09-10 23:36:59 -07001582 def test_auto_number(self):
1583 class Color(Enum):
1584 red = auto()
1585 blue = auto()
1586 green = auto()
1587
1588 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1589 self.assertEqual(Color.red.value, 1)
1590 self.assertEqual(Color.blue.value, 2)
1591 self.assertEqual(Color.green.value, 3)
1592
1593 def test_auto_name(self):
1594 class Color(Enum):
1595 def _generate_next_value_(name, start, count, last):
1596 return name
1597 red = auto()
1598 blue = auto()
1599 green = auto()
1600
1601 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1602 self.assertEqual(Color.red.value, 'red')
1603 self.assertEqual(Color.blue.value, 'blue')
1604 self.assertEqual(Color.green.value, 'green')
1605
1606 def test_auto_name_inherit(self):
1607 class AutoNameEnum(Enum):
1608 def _generate_next_value_(name, start, count, last):
1609 return name
1610 class Color(AutoNameEnum):
1611 red = auto()
1612 blue = auto()
1613 green = auto()
1614
1615 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1616 self.assertEqual(Color.red.value, 'red')
1617 self.assertEqual(Color.blue.value, 'blue')
1618 self.assertEqual(Color.green.value, 'green')
1619
1620 def test_auto_garbage(self):
1621 class Color(Enum):
1622 red = 'red'
1623 blue = auto()
1624 self.assertEqual(Color.blue.value, 1)
1625
1626 def test_auto_garbage_corrected(self):
1627 class Color(Enum):
1628 red = 'red'
1629 blue = 2
1630 green = auto()
1631
1632 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1633 self.assertEqual(Color.red.value, 'red')
1634 self.assertEqual(Color.blue.value, 2)
1635 self.assertEqual(Color.green.value, 3)
1636
Ethan Furman3515dcc2016-09-18 13:15:41 -07001637 def test_duplicate_auto(self):
1638 class Dupes(Enum):
1639 first = primero = auto()
1640 second = auto()
1641 third = auto()
1642 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1643
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001644
Ethan Furmane8e61272016-08-20 07:19:31 -07001645class TestOrder(unittest.TestCase):
1646
1647 def test_same_members(self):
1648 class Color(Enum):
1649 _order_ = 'red green blue'
1650 red = 1
1651 green = 2
1652 blue = 3
1653
1654 def test_same_members_with_aliases(self):
1655 class Color(Enum):
1656 _order_ = 'red green blue'
1657 red = 1
1658 green = 2
1659 blue = 3
1660 verde = green
1661
1662 def test_same_members_wrong_order(self):
1663 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1664 class Color(Enum):
1665 _order_ = 'red green blue'
1666 red = 1
1667 blue = 3
1668 green = 2
1669
1670 def test_order_has_extra_members(self):
1671 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1672 class Color(Enum):
1673 _order_ = 'red green blue purple'
1674 red = 1
1675 green = 2
1676 blue = 3
1677
1678 def test_order_has_extra_members_with_aliases(self):
1679 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1680 class Color(Enum):
1681 _order_ = 'red green blue purple'
1682 red = 1
1683 green = 2
1684 blue = 3
1685 verde = green
1686
1687 def test_enum_has_extra_members(self):
1688 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1689 class Color(Enum):
1690 _order_ = 'red green blue'
1691 red = 1
1692 green = 2
1693 blue = 3
1694 purple = 4
1695
1696 def test_enum_has_extra_members_with_aliases(self):
1697 with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
1698 class Color(Enum):
1699 _order_ = 'red green blue'
1700 red = 1
1701 green = 2
1702 blue = 3
1703 purple = 4
1704 verde = green
1705
1706
Ethan Furman65a5a472016-09-01 23:55:19 -07001707class TestFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001708 """Tests of the Flags."""
1709
Ethan Furman65a5a472016-09-01 23:55:19 -07001710 class Perm(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001711 R, W, X = 4, 2, 1
1712
Ethan Furman65a5a472016-09-01 23:55:19 -07001713 class Open(Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001714 RO = 0
1715 WO = 1
1716 RW = 2
1717 AC = 3
1718 CE = 1<<19
1719
1720 def test_str(self):
1721 Perm = self.Perm
1722 self.assertEqual(str(Perm.R), 'Perm.R')
1723 self.assertEqual(str(Perm.W), 'Perm.W')
1724 self.assertEqual(str(Perm.X), 'Perm.X')
1725 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
1726 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
1727 self.assertEqual(str(Perm(0)), 'Perm.0')
1728 self.assertEqual(str(~Perm.R), 'Perm.W|X')
1729 self.assertEqual(str(~Perm.W), 'Perm.R|X')
1730 self.assertEqual(str(~Perm.X), 'Perm.R|W')
1731 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
1732 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
1733 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
1734
1735 Open = self.Open
1736 self.assertEqual(str(Open.RO), 'Open.RO')
1737 self.assertEqual(str(Open.WO), 'Open.WO')
1738 self.assertEqual(str(Open.AC), 'Open.AC')
1739 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
1740 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001741 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001742 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
1743 self.assertEqual(str(~Open.AC), 'Open.CE')
1744 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
1745 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
1746
1747 def test_repr(self):
1748 Perm = self.Perm
1749 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
1750 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
1751 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
1752 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
1753 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
Ethan Furman27682d22016-09-04 11:39:01 -07001754 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001755 self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
1756 self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
1757 self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
1758 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
Ethan Furman27682d22016-09-04 11:39:01 -07001759 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.0: 0>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001760 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
1761
1762 Open = self.Open
1763 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
1764 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
1765 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
1766 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
1767 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07001768 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: 524291>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001769 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
1770 self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
1771 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
1772 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
1773
1774 def test_or(self):
1775 Perm = self.Perm
1776 for i in Perm:
1777 for j in Perm:
1778 self.assertEqual((i | j), Perm(i.value | j.value))
1779 self.assertEqual((i | j).value, i.value | j.value)
1780 self.assertIs(type(i | j), Perm)
1781 for i in Perm:
1782 self.assertIs(i | i, i)
1783 Open = self.Open
1784 self.assertIs(Open.RO | Open.CE, Open.CE)
1785
1786 def test_and(self):
1787 Perm = self.Perm
1788 RW = Perm.R | Perm.W
1789 RX = Perm.R | Perm.X
1790 WX = Perm.W | Perm.X
1791 RWX = Perm.R | Perm.W | Perm.X
1792 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1793 for i in values:
1794 for j in values:
1795 self.assertEqual((i & j).value, i.value & j.value)
1796 self.assertIs(type(i & j), Perm)
1797 for i in Perm:
1798 self.assertIs(i & i, i)
1799 self.assertIs(i & RWX, i)
1800 self.assertIs(RWX & i, i)
1801 Open = self.Open
1802 self.assertIs(Open.RO & Open.CE, Open.RO)
1803
1804 def test_xor(self):
1805 Perm = self.Perm
1806 for i in Perm:
1807 for j in Perm:
1808 self.assertEqual((i ^ j).value, i.value ^ j.value)
1809 self.assertIs(type(i ^ j), Perm)
1810 for i in Perm:
1811 self.assertIs(i ^ Perm(0), i)
1812 self.assertIs(Perm(0) ^ i, i)
1813 Open = self.Open
1814 self.assertIs(Open.RO ^ Open.CE, Open.CE)
1815 self.assertIs(Open.CE ^ Open.CE, Open.RO)
1816
1817 def test_invert(self):
1818 Perm = self.Perm
1819 RW = Perm.R | Perm.W
1820 RX = Perm.R | Perm.X
1821 WX = Perm.W | Perm.X
1822 RWX = Perm.R | Perm.W | Perm.X
1823 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
1824 for i in values:
1825 self.assertIs(type(~i), Perm)
1826 self.assertEqual(~~i, i)
1827 for i in Perm:
1828 self.assertIs(~~i, i)
1829 Open = self.Open
1830 self.assertIs(Open.WO & ~Open.WO, Open.RO)
1831 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
1832
Ethan Furman25d94bb2016-09-02 16:32:32 -07001833 def test_bool(self):
1834 Perm = self.Perm
1835 for f in Perm:
1836 self.assertTrue(f)
1837 Open = self.Open
1838 for f in Open:
1839 self.assertEqual(bool(f.value), bool(f))
1840
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001841 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001842 Perm = Flag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001843 lst = list(Perm)
1844 self.assertEqual(len(lst), len(Perm))
1845 self.assertEqual(len(Perm), 3, Perm)
1846 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1847 for i, n in enumerate('R W X'.split()):
1848 v = 1<<i
1849 e = Perm(v)
1850 self.assertEqual(e.value, v)
1851 self.assertEqual(type(e.value), int)
1852 self.assertEqual(e.name, n)
1853 self.assertIn(e, Perm)
1854 self.assertIs(type(e), Perm)
1855
1856 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001857 Perm = Flag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001858 lst = list(Perm)
1859 self.assertEqual(len(lst), len(Perm))
1860 self.assertEqual(len(Perm), 3, Perm)
1861 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1862 for i, n in enumerate('R W X'.split()):
1863 v = 8<<i
1864 e = Perm(v)
1865 self.assertEqual(e.value, v)
1866 self.assertEqual(type(e.value), int)
1867 self.assertEqual(e.name, n)
1868 self.assertIn(e, Perm)
1869 self.assertIs(type(e), Perm)
1870
1871 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001872 Perm = Flag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001873 lst = list(Perm)
1874 self.assertEqual(len(lst), len(Perm))
1875 self.assertEqual(len(Perm), 3, Perm)
1876 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1877 for i, n in enumerate('R W X'.split()):
1878 v = 1<<i
1879 e = Perm(v)
1880 self.assertEqual(e.value, v)
1881 self.assertEqual(type(e.value), int)
1882 self.assertEqual(e.name, n)
1883 self.assertIn(e, Perm)
1884 self.assertIs(type(e), Perm)
1885
1886 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001887 Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001888 lst = list(Perm)
1889 self.assertEqual(len(lst), len(Perm))
1890 self.assertEqual(len(Perm), 3, Perm)
1891 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1892 for i, n in enumerate('R W X'.split()):
1893 v = 1<<(2*i+1)
1894 e = Perm(v)
1895 self.assertEqual(e.value, v)
1896 self.assertEqual(type(e.value), int)
1897 self.assertEqual(e.name, n)
1898 self.assertIn(e, Perm)
1899 self.assertIs(type(e), Perm)
1900
1901 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07001902 Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001903 lst = list(Perm)
1904 self.assertEqual(len(lst), len(Perm))
1905 self.assertEqual(len(Perm), 3, Perm)
1906 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
1907 for i, n in enumerate('R W X'.split()):
1908 v = 1<<(2*i+1)
1909 e = Perm(v)
1910 self.assertEqual(e.value, v)
1911 self.assertEqual(type(e.value), int)
1912 self.assertEqual(e.name, n)
1913 self.assertIn(e, Perm)
1914 self.assertIs(type(e), Perm)
1915
Ethan Furman65a5a472016-09-01 23:55:19 -07001916 def test_pickle(self):
1917 if isinstance(FlagStooges, Exception):
1918 raise FlagStooges
1919 test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE)
1920 test_pickle_dump_load(self.assertIs, FlagStooges)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001921
Ethan Furman65a5a472016-09-01 23:55:19 -07001922 def test_containment(self):
1923 Perm = self.Perm
1924 R, W, X = Perm
1925 RW = R | W
1926 RX = R | X
1927 WX = W | X
1928 RWX = R | W | X
1929 self.assertTrue(R in RW)
1930 self.assertTrue(R in RX)
1931 self.assertTrue(R in RWX)
1932 self.assertTrue(W in RW)
1933 self.assertTrue(W in WX)
1934 self.assertTrue(W in RWX)
1935 self.assertTrue(X in RX)
1936 self.assertTrue(X in WX)
1937 self.assertTrue(X in RWX)
1938 self.assertFalse(R in WX)
1939 self.assertFalse(W in RX)
1940 self.assertFalse(X in RW)
1941
Ethan Furmanc16595e2016-09-10 23:36:59 -07001942 def test_auto_number(self):
1943 class Color(Flag):
1944 red = auto()
1945 blue = auto()
1946 green = auto()
1947
1948 self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
1949 self.assertEqual(Color.red.value, 1)
1950 self.assertEqual(Color.blue.value, 2)
1951 self.assertEqual(Color.green.value, 4)
1952
1953 def test_auto_number_garbage(self):
1954 with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
1955 class Color(Flag):
1956 red = 'not an int'
1957 blue = auto()
1958
Ethan Furman3515dcc2016-09-18 13:15:41 -07001959 def test_cascading_failure(self):
1960 class Bizarre(Flag):
1961 c = 3
1962 d = 4
1963 f = 6
1964 # Bizarre.c | Bizarre.d
1965 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
1966 self.assertRaisesRegex(ValueError, "5 is not a valid Bizarre", Bizarre, 5)
1967 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
1968 self.assertRaisesRegex(ValueError, "2 is not a valid Bizarre", Bizarre, 2)
1969 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
1970 self.assertRaisesRegex(ValueError, "1 is not a valid Bizarre", Bizarre, 1)
1971
1972 def test_duplicate_auto(self):
1973 class Dupes(Enum):
1974 first = primero = auto()
1975 second = auto()
1976 third = auto()
1977 self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
1978
1979 def test_bizarre(self):
1980 class Bizarre(Flag):
1981 b = 3
1982 c = 4
1983 d = 6
1984 self.assertEqual(repr(Bizarre(7)), '<Bizarre.d|c|b: 7>')
1985
Ethan Furmanc16595e2016-09-10 23:36:59 -07001986
Ethan Furman65a5a472016-09-01 23:55:19 -07001987class TestIntFlag(unittest.TestCase):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001988 """Tests of the IntFlags."""
1989
Ethan Furman65a5a472016-09-01 23:55:19 -07001990 class Perm(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001991 X = 1 << 0
1992 W = 1 << 1
1993 R = 1 << 2
1994
Ethan Furman65a5a472016-09-01 23:55:19 -07001995 class Open(IntFlag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001996 RO = 0
1997 WO = 1
1998 RW = 2
1999 AC = 3
2000 CE = 1<<19
2001
Ethan Furman3515dcc2016-09-18 13:15:41 -07002002 def test_type(self):
2003 Perm = self.Perm
2004 Open = self.Open
2005 for f in Perm:
2006 self.assertTrue(isinstance(f, Perm))
2007 self.assertEqual(f, f.value)
2008 self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
2009 self.assertEqual(Perm.W | Perm.X, 3)
2010 for f in Open:
2011 self.assertTrue(isinstance(f, Open))
2012 self.assertEqual(f, f.value)
2013 self.assertTrue(isinstance(Open.WO | Open.RW, Open))
2014 self.assertEqual(Open.WO | Open.RW, 3)
2015
2016
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002017 def test_str(self):
2018 Perm = self.Perm
2019 self.assertEqual(str(Perm.R), 'Perm.R')
2020 self.assertEqual(str(Perm.W), 'Perm.W')
2021 self.assertEqual(str(Perm.X), 'Perm.X')
2022 self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
2023 self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
2024 self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
2025 self.assertEqual(str(Perm(0)), 'Perm.0')
2026 self.assertEqual(str(Perm(8)), 'Perm.8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002027 self.assertEqual(str(~Perm.R), 'Perm.W|X')
2028 self.assertEqual(str(~Perm.W), 'Perm.R|X')
2029 self.assertEqual(str(~Perm.X), 'Perm.R|W')
2030 self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002031 self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002032 self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X')
2033 self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
2034 self.assertEqual(str(Perm(~8)), 'Perm.R|W|X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002035
2036 Open = self.Open
2037 self.assertEqual(str(Open.RO), 'Open.RO')
2038 self.assertEqual(str(Open.WO), 'Open.WO')
2039 self.assertEqual(str(Open.AC), 'Open.AC')
2040 self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
2041 self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
2042 self.assertEqual(str(Open(4)), 'Open.4')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002043 self.assertEqual(str(~Open.RO), 'Open.CE|AC|RW|WO')
2044 self.assertEqual(str(~Open.WO), 'Open.CE|RW')
2045 self.assertEqual(str(~Open.AC), 'Open.CE')
2046 self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|RW|WO')
2047 self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
2048 self.assertEqual(str(Open(~4)), 'Open.CE|AC|RW|WO')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002049
2050 def test_repr(self):
2051 Perm = self.Perm
2052 self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
2053 self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
2054 self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
2055 self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
2056 self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
2057 self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
Ethan Furman27682d22016-09-04 11:39:01 -07002058 self.assertEqual(repr(Perm(0)), '<Perm.0: 0>')
2059 self.assertEqual(repr(Perm(8)), '<Perm.8: 8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002060 self.assertEqual(repr(~Perm.R), '<Perm.W|X: -5>')
2061 self.assertEqual(repr(~Perm.W), '<Perm.R|X: -3>')
2062 self.assertEqual(repr(~Perm.X), '<Perm.R|W: -2>')
2063 self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: -7>')
Ethan Furman27682d22016-09-04 11:39:01 -07002064 self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm.-8: -8>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002065 self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: -13>')
2066 self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: -1>')
2067 self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: -9>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002068
2069 Open = self.Open
2070 self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
2071 self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
2072 self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
2073 self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
2074 self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
Ethan Furman27682d22016-09-04 11:39:01 -07002075 self.assertEqual(repr(Open(4)), '<Open.4: 4>')
Ethan Furman3515dcc2016-09-18 13:15:41 -07002076 self.assertEqual(repr(~Open.RO), '<Open.CE|AC|RW|WO: -1>')
2077 self.assertEqual(repr(~Open.WO), '<Open.CE|RW: -2>')
2078 self.assertEqual(repr(~Open.AC), '<Open.CE: -4>')
2079 self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|RW|WO: -524289>')
2080 self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
2081 self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002082
2083 def test_or(self):
2084 Perm = self.Perm
2085 for i in Perm:
2086 for j in Perm:
2087 self.assertEqual(i | j, i.value | j.value)
2088 self.assertEqual((i | j).value, i.value | j.value)
2089 self.assertIs(type(i | j), Perm)
2090 for j in range(8):
2091 self.assertEqual(i | j, i.value | j)
2092 self.assertEqual((i | j).value, i.value | j)
2093 self.assertIs(type(i | j), Perm)
2094 self.assertEqual(j | i, j | i.value)
2095 self.assertEqual((j | i).value, j | i.value)
2096 self.assertIs(type(j | i), Perm)
2097 for i in Perm:
2098 self.assertIs(i | i, i)
2099 self.assertIs(i | 0, i)
2100 self.assertIs(0 | i, i)
2101 Open = self.Open
2102 self.assertIs(Open.RO | Open.CE, Open.CE)
2103
2104 def test_and(self):
2105 Perm = self.Perm
2106 RW = Perm.R | Perm.W
2107 RX = Perm.R | Perm.X
2108 WX = Perm.W | Perm.X
2109 RWX = Perm.R | Perm.W | Perm.X
2110 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2111 for i in values:
2112 for j in values:
2113 self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
2114 self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
2115 self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
2116 for j in range(8):
2117 self.assertEqual(i & j, i.value & j)
2118 self.assertEqual((i & j).value, i.value & j)
2119 self.assertIs(type(i & j), Perm)
2120 self.assertEqual(j & i, j & i.value)
2121 self.assertEqual((j & i).value, j & i.value)
2122 self.assertIs(type(j & i), Perm)
2123 for i in Perm:
2124 self.assertIs(i & i, i)
2125 self.assertIs(i & 7, i)
2126 self.assertIs(7 & i, i)
2127 Open = self.Open
2128 self.assertIs(Open.RO & Open.CE, Open.RO)
2129
2130 def test_xor(self):
2131 Perm = self.Perm
2132 for i in Perm:
2133 for j in Perm:
2134 self.assertEqual(i ^ j, i.value ^ j.value)
2135 self.assertEqual((i ^ j).value, i.value ^ j.value)
2136 self.assertIs(type(i ^ j), Perm)
2137 for j in range(8):
2138 self.assertEqual(i ^ j, i.value ^ j)
2139 self.assertEqual((i ^ j).value, i.value ^ j)
2140 self.assertIs(type(i ^ j), Perm)
2141 self.assertEqual(j ^ i, j ^ i.value)
2142 self.assertEqual((j ^ i).value, j ^ i.value)
2143 self.assertIs(type(j ^ i), Perm)
2144 for i in Perm:
2145 self.assertIs(i ^ 0, i)
2146 self.assertIs(0 ^ i, i)
2147 Open = self.Open
2148 self.assertIs(Open.RO ^ Open.CE, Open.CE)
2149 self.assertIs(Open.CE ^ Open.CE, Open.RO)
2150
2151 def test_invert(self):
2152 Perm = self.Perm
2153 RW = Perm.R | Perm.W
2154 RX = Perm.R | Perm.X
2155 WX = Perm.W | Perm.X
2156 RWX = Perm.R | Perm.W | Perm.X
2157 values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
2158 for i in values:
2159 self.assertEqual(~i, ~i.value)
2160 self.assertEqual((~i).value, ~i.value)
2161 self.assertIs(type(~i), Perm)
2162 self.assertEqual(~~i, i)
2163 for i in Perm:
2164 self.assertIs(~~i, i)
2165 Open = self.Open
2166 self.assertIs(Open.WO & ~Open.WO, Open.RO)
2167 self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
2168
2169 def test_programatic_function_string(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002170 Perm = IntFlag('Perm', 'R W X')
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002171 lst = list(Perm)
2172 self.assertEqual(len(lst), len(Perm))
2173 self.assertEqual(len(Perm), 3, Perm)
2174 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2175 for i, n in enumerate('R W X'.split()):
2176 v = 1<<i
2177 e = Perm(v)
2178 self.assertEqual(e.value, v)
2179 self.assertEqual(type(e.value), int)
2180 self.assertEqual(e, v)
2181 self.assertEqual(e.name, n)
2182 self.assertIn(e, Perm)
2183 self.assertIs(type(e), Perm)
2184
2185 def test_programatic_function_string_with_start(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002186 Perm = IntFlag('Perm', 'R W X', start=8)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002187 lst = list(Perm)
2188 self.assertEqual(len(lst), len(Perm))
2189 self.assertEqual(len(Perm), 3, Perm)
2190 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2191 for i, n in enumerate('R W X'.split()):
2192 v = 8<<i
2193 e = Perm(v)
2194 self.assertEqual(e.value, v)
2195 self.assertEqual(type(e.value), int)
2196 self.assertEqual(e, v)
2197 self.assertEqual(e.name, n)
2198 self.assertIn(e, Perm)
2199 self.assertIs(type(e), Perm)
2200
2201 def test_programatic_function_string_list(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002202 Perm = IntFlag('Perm', ['R', 'W', 'X'])
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002203 lst = list(Perm)
2204 self.assertEqual(len(lst), len(Perm))
2205 self.assertEqual(len(Perm), 3, Perm)
2206 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2207 for i, n in enumerate('R W X'.split()):
2208 v = 1<<i
2209 e = Perm(v)
2210 self.assertEqual(e.value, v)
2211 self.assertEqual(type(e.value), int)
2212 self.assertEqual(e, v)
2213 self.assertEqual(e.name, n)
2214 self.assertIn(e, Perm)
2215 self.assertIs(type(e), Perm)
2216
2217 def test_programatic_function_iterable(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002218 Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002219 lst = list(Perm)
2220 self.assertEqual(len(lst), len(Perm))
2221 self.assertEqual(len(Perm), 3, Perm)
2222 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2223 for i, n in enumerate('R W X'.split()):
2224 v = 1<<(2*i+1)
2225 e = Perm(v)
2226 self.assertEqual(e.value, v)
2227 self.assertEqual(type(e.value), int)
2228 self.assertEqual(e, v)
2229 self.assertEqual(e.name, n)
2230 self.assertIn(e, Perm)
2231 self.assertIs(type(e), Perm)
2232
2233 def test_programatic_function_from_dict(self):
Ethan Furman65a5a472016-09-01 23:55:19 -07002234 Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
Ethan Furmanee47e5c2016-08-31 00:12:15 -07002235 lst = list(Perm)
2236 self.assertEqual(len(lst), len(Perm))
2237 self.assertEqual(len(Perm), 3, Perm)
2238 self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
2239 for i, n in enumerate('R W X'.split()):
2240 v = 1<<(2*i+1)
2241 e = Perm(v)
2242 self.assertEqual(e.value, v)
2243 self.assertEqual(type(e.value), int)
2244 self.assertEqual(e, v)
2245 self.assertEqual(e.name, n)
2246 self.assertIn(e, Perm)
2247 self.assertIs(type(e), Perm)
2248
2249
Ethan Furman65a5a472016-09-01 23:55:19 -07002250 def test_containment(self):
2251 Perm = self.Perm
2252 R, W, X = Perm
2253 RW = R | W
2254 RX = R | X
2255 WX = W | X
2256 RWX = R | W | X
2257 self.assertTrue(R in RW)
2258 self.assertTrue(R in RX)
2259 self.assertTrue(R in RWX)
2260 self.assertTrue(W in RW)
2261 self.assertTrue(W in WX)
2262 self.assertTrue(W in RWX)
2263 self.assertTrue(X in RX)
2264 self.assertTrue(X in WX)
2265 self.assertTrue(X in RWX)
2266 self.assertFalse(R in WX)
2267 self.assertFalse(W in RX)
2268 self.assertFalse(X in RW)
2269
Ethan Furman25d94bb2016-09-02 16:32:32 -07002270 def test_bool(self):
2271 Perm = self.Perm
2272 for f in Perm:
2273 self.assertTrue(f)
2274 Open = self.Open
2275 for f in Open:
2276 self.assertEqual(bool(f.value), bool(f))
2277
Ethan Furmanf24bb352013-07-18 17:05:39 -07002278class TestUnique(unittest.TestCase):
2279
2280 def test_unique_clean(self):
2281 @unique
2282 class Clean(Enum):
2283 one = 1
2284 two = 'dos'
2285 tres = 4.0
2286 @unique
2287 class Cleaner(IntEnum):
2288 single = 1
2289 double = 2
2290 triple = 3
2291
2292 def test_unique_dirty(self):
2293 with self.assertRaisesRegex(ValueError, 'tres.*one'):
2294 @unique
2295 class Dirty(Enum):
2296 one = 1
2297 two = 'dos'
2298 tres = 1
2299 with self.assertRaisesRegex(
2300 ValueError,
2301 'double.*single.*turkey.*triple',
2302 ):
2303 @unique
2304 class Dirtier(IntEnum):
2305 single = 1
2306 double = 1
2307 triple = 3
2308 turkey = 3
2309
Ethan Furman3803ad42016-05-01 10:03:53 -07002310 def test_unique_with_name(self):
2311 @unique
2312 class Silly(Enum):
2313 one = 1
2314 two = 'dos'
2315 name = 3
2316 @unique
2317 class Sillier(IntEnum):
2318 single = 1
2319 name = 2
2320 triple = 3
2321 value = 4
2322
Ethan Furmanf24bb352013-07-18 17:05:39 -07002323
Ethan Furman3323da92015-04-11 09:39:59 -07002324expected_help_output_with_docs = """\
Ethan Furman5875d742013-10-21 20:45:55 -07002325Help on class Color in module %s:
2326
2327class Color(enum.Enum)
Ethan Furman48a724f2015-04-11 23:23:06 -07002328 | An enumeration.
Serhiy Storchakab599ca82015-04-04 12:48:04 +03002329 |\x20\x20
Ethan Furman5875d742013-10-21 20:45:55 -07002330 | Method resolution order:
2331 | Color
2332 | enum.Enum
2333 | builtins.object
2334 |\x20\x20
2335 | Data and other attributes defined here:
2336 |\x20\x20
2337 | blue = <Color.blue: 3>
2338 |\x20\x20
2339 | green = <Color.green: 2>
2340 |\x20\x20
2341 | red = <Color.red: 1>
2342 |\x20\x20
2343 | ----------------------------------------------------------------------
2344 | Data descriptors inherited from enum.Enum:
2345 |\x20\x20
2346 | name
2347 | The name of the Enum member.
2348 |\x20\x20
2349 | value
2350 | The value of the Enum member.
2351 |\x20\x20
2352 | ----------------------------------------------------------------------
2353 | Data descriptors inherited from enum.EnumMeta:
2354 |\x20\x20
2355 | __members__
2356 | Returns a mapping of member name->value.
2357 |\x20\x20\x20\x20\x20\x20
2358 | This mapping lists all enum members, including aliases. Note that this
Ethan Furman3323da92015-04-11 09:39:59 -07002359 | is a read-only view of the internal mapping."""
2360
2361expected_help_output_without_docs = """\
2362Help on class Color in module %s:
2363
2364class Color(enum.Enum)
2365 | Method resolution order:
2366 | Color
2367 | enum.Enum
2368 | builtins.object
2369 |\x20\x20
2370 | Data and other attributes defined here:
2371 |\x20\x20
2372 | blue = <Color.blue: 3>
2373 |\x20\x20
2374 | green = <Color.green: 2>
2375 |\x20\x20
2376 | red = <Color.red: 1>
2377 |\x20\x20
2378 | ----------------------------------------------------------------------
2379 | Data descriptors inherited from enum.Enum:
2380 |\x20\x20
2381 | name
2382 |\x20\x20
2383 | value
2384 |\x20\x20
2385 | ----------------------------------------------------------------------
2386 | Data descriptors inherited from enum.EnumMeta:
2387 |\x20\x20
2388 | __members__"""
Ethan Furman5875d742013-10-21 20:45:55 -07002389
2390class TestStdLib(unittest.TestCase):
2391
Ethan Furman48a724f2015-04-11 23:23:06 -07002392 maxDiff = None
2393
Ethan Furman5875d742013-10-21 20:45:55 -07002394 class Color(Enum):
2395 red = 1
2396 green = 2
2397 blue = 3
2398
2399 def test_pydoc(self):
2400 # indirectly test __objclass__
Ethan Furman3323da92015-04-11 09:39:59 -07002401 if StrEnum.__doc__ is None:
2402 expected_text = expected_help_output_without_docs % __name__
2403 else:
2404 expected_text = expected_help_output_with_docs % __name__
Ethan Furman5875d742013-10-21 20:45:55 -07002405 output = StringIO()
2406 helper = pydoc.Helper(output=output)
2407 helper(self.Color)
2408 result = output.getvalue().strip()
Victor Stinner4b0432d2014-06-16 22:48:43 +02002409 self.assertEqual(result, expected_text)
Ethan Furman5875d742013-10-21 20:45:55 -07002410
2411 def test_inspect_getmembers(self):
2412 values = dict((
2413 ('__class__', EnumMeta),
Ethan Furman48a724f2015-04-11 23:23:06 -07002414 ('__doc__', 'An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002415 ('__members__', self.Color.__members__),
2416 ('__module__', __name__),
2417 ('blue', self.Color.blue),
2418 ('green', self.Color.green),
2419 ('name', Enum.__dict__['name']),
2420 ('red', self.Color.red),
2421 ('value', Enum.__dict__['value']),
2422 ))
2423 result = dict(inspect.getmembers(self.Color))
2424 self.assertEqual(values.keys(), result.keys())
2425 failed = False
2426 for k in values.keys():
2427 if result[k] != values[k]:
2428 print()
2429 print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
2430 ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
2431 failed = True
2432 if failed:
2433 self.fail("result does not equal expected, see print above")
2434
2435 def test_inspect_classify_class_attrs(self):
2436 # indirectly test __objclass__
2437 from inspect import Attribute
2438 values = [
2439 Attribute(name='__class__', kind='data',
2440 defining_class=object, object=EnumMeta),
2441 Attribute(name='__doc__', kind='data',
Ethan Furman48a724f2015-04-11 23:23:06 -07002442 defining_class=self.Color, object='An enumeration.'),
Ethan Furman5875d742013-10-21 20:45:55 -07002443 Attribute(name='__members__', kind='property',
2444 defining_class=EnumMeta, object=EnumMeta.__members__),
2445 Attribute(name='__module__', kind='data',
2446 defining_class=self.Color, object=__name__),
2447 Attribute(name='blue', kind='data',
2448 defining_class=self.Color, object=self.Color.blue),
2449 Attribute(name='green', kind='data',
2450 defining_class=self.Color, object=self.Color.green),
2451 Attribute(name='red', kind='data',
2452 defining_class=self.Color, object=self.Color.red),
2453 Attribute(name='name', kind='data',
2454 defining_class=Enum, object=Enum.__dict__['name']),
2455 Attribute(name='value', kind='data',
2456 defining_class=Enum, object=Enum.__dict__['value']),
2457 ]
2458 values.sort(key=lambda item: item.name)
2459 result = list(inspect.classify_class_attrs(self.Color))
2460 result.sort(key=lambda item: item.name)
2461 failed = False
2462 for v, r in zip(values, result):
2463 if r != v:
2464 print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
2465 failed = True
2466 if failed:
2467 self.fail("result does not equal expected, see print above")
2468
Martin Panter19e69c52015-11-14 12:46:42 +00002469
2470class MiscTestCase(unittest.TestCase):
2471 def test__all__(self):
2472 support.check__all__(self, enum)
2473
2474
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +00002475# These are unordered here on purpose to ensure that declaration order
2476# makes no difference.
2477CONVERT_TEST_NAME_D = 5
2478CONVERT_TEST_NAME_C = 5
2479CONVERT_TEST_NAME_B = 5
2480CONVERT_TEST_NAME_A = 5 # This one should sort first.
2481CONVERT_TEST_NAME_E = 5
2482CONVERT_TEST_NAME_F = 5
2483
2484class TestIntEnumConvert(unittest.TestCase):
2485 def test_convert_value_lookup_priority(self):
2486 test_type = enum.IntEnum._convert(
2487 'UnittestConvert', 'test.test_enum',
2488 filter=lambda x: x.startswith('CONVERT_TEST_'))
2489 # We don't want the reverse lookup value to vary when there are
2490 # multiple possible names for a given value. It should always
2491 # report the first lexigraphical name in that case.
2492 self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
2493
2494 def test_convert(self):
2495 test_type = enum.IntEnum._convert(
2496 'UnittestConvert', 'test.test_enum',
2497 filter=lambda x: x.startswith('CONVERT_TEST_'))
2498 # Ensure that test_type has all of the desired names and values.
2499 self.assertEqual(test_type.CONVERT_TEST_NAME_F,
2500 test_type.CONVERT_TEST_NAME_A)
2501 self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
2502 self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
2503 self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
2504 self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
2505 # Ensure that test_type only picked up names matching the filter.
2506 self.assertEqual([name for name in dir(test_type)
2507 if name[0:2] not in ('CO', '__')],
2508 [], msg='Names other than CONVERT_TEST_* found.')
2509
2510
Ethan Furman6b3d64a2013-06-14 16:55:46 -07002511if __name__ == '__main__':
2512 unittest.main()