Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Impacket - Collection of Python classes for working with network protocols. 

2# 

3# SECUREAUTH LABS. Copyright (C) 2018 SecureAuth Corporation. All rights reserved. 

4# 

5# This software is provided under a slightly modified version 

6# of the Apache Software License. See the accompanying LICENSE file 

7# for more information. 

8# 

9"""Python Enumerations""" 

10 

11import sys as _sys 

12 

13__all__ = ['Enum', 'IntEnum', 'unique'] 

14 

15pyver = float('%s.%s' % _sys.version_info[:2]) 

16 

17try: 

18 any 

19except NameError: 

20 def any(iterable): 

21 for element in iterable: 

22 if element: 

23 return True 

24 return False 

25 

26 

27class _RouteClassAttributeToGetattr(object): 

28 """Route attribute access on a class to __getattr__. 

29 

30 This is a descriptor, used to define attributes that act differently when 

31 accessed through an instance and through a class. Instance access remains 

32 normal, but access to an attribute through a class will be routed to the 

33 class's __getattr__ method; this is done by raising AttributeError. 

34 

35 """ 

36 def __init__(self, fget=None): 

37 self.fget = fget 

38 

39 def __get__(self, instance, ownerclass=None): 

40 if instance is None: 40 ↛ 41line 40 didn't jump to line 41, because the condition on line 40 was never true

41 raise AttributeError() 

42 return self.fget(instance) 

43 

44 def __set__(self, instance, value): 

45 raise AttributeError("can't set attribute") 

46 

47 def __delete__(self, instance): 

48 raise AttributeError("can't delete attribute") 

49 

50 

51def _is_descriptor(obj): 

52 """Returns True if obj is a descriptor, False otherwise.""" 

53 return ( 

54 hasattr(obj, '__get__') or 

55 hasattr(obj, '__set__') or 

56 hasattr(obj, '__delete__')) 

57 

58 

59def _is_dunder(name): 

60 """Returns True if a __dunder__ name, False otherwise.""" 

61 return (name[:2] == name[-2:] == '__' and 

62 name[2:3] != '_' and 

63 name[-3:-2] != '_' and 

64 len(name) > 4) 

65 

66 

67def _is_sunder(name): 

68 """Returns True if a _sunder_ name, False otherwise.""" 

69 return (name[0] == name[-1] == '_' and 

70 name[1:2] != '_' and 

71 name[-2:-1] != '_' and 

72 len(name) > 2) 

73 

74 

75def _make_class_unpicklable(cls): 

76 """Make the given class un-picklable.""" 

77 def _break_on_call_reduce(self): 

78 raise TypeError('%r cannot be pickled' % self) 

79 cls.__reduce__ = _break_on_call_reduce 

80 cls.__module__ = '<unknown>' 

81 

82 

83class _EnumDict(dict): 

84 """Track enum member order and ensure member names are not reused. 

85 

86 EnumMeta will use the names found in self._member_names as the 

87 enumeration member names. 

88 

89 """ 

90 def __init__(self): 

91 super(_EnumDict, self).__init__() 

92 self._member_names = [] 

93 

94 def __setitem__(self, key, value): 

95 """Changes anything not dundered or not a descriptor. 

96 

97 If a descriptor is added with the same name as an enum member, the name 

98 is removed from _member_names (this may leave a hole in the numerical 

99 sequence of values). 

100 

101 If an enum member name is used twice, an error is raised; duplicate 

102 values are not checked for. 

103 

104 Single underscore (sunder) names are reserved. 

105 

106 Note: in 3.x __order__ is simply discarded as a not necessary piece 

107 leftover from 2.x 

108 

109 """ 

110 if pyver >= 3.0 and key == '__order__': 110 ↛ 111line 110 didn't jump to line 111, because the condition on line 110 was never true

111 return 

112 if _is_sunder(key): 112 ↛ 113line 112 didn't jump to line 113, because the condition on line 112 was never true

113 raise ValueError('_names_ are reserved for future Enum use') 

114 elif _is_dunder(key): 

115 pass 

116 elif key in self._member_names: 116 ↛ 118line 116 didn't jump to line 118, because the condition on line 116 was never true

117 # descriptor overwriting an enum? 

118 raise TypeError('Attempted to reuse key: %r' % key) 

119 elif not _is_descriptor(value): 

120 if key in self: 120 ↛ 122line 120 didn't jump to line 122, because the condition on line 120 was never true

121 # enum overwriting a descriptor? 

122 raise TypeError('Key already defined as: %r' % self[key]) 

123 self._member_names.append(key) 

124 super(_EnumDict, self).__setitem__(key, value) 

125 

126 

127# Dummy value for Enum as EnumMeta explicitly checks for it, but of course until 

128# EnumMeta finishes running the first time the Enum class doesn't exist. This 

129# is also why there are checks in EnumMeta like `if Enum is not None` 

130Enum = None 

131 

132 

133class EnumMeta(type): 

134 """Metaclass for Enum""" 

135 @classmethod 

136 def __prepare__(metacls, cls, bases): 

137 return _EnumDict() 

138 

139 def __new__(metacls, cls, bases, classdict): 

140 # an Enum class is final once enumeration items have been defined; it 

141 # cannot be mixed with other types (int, float, etc.) if it has an 

142 # inherited __new__ unless a new __new__ is defined (or the resulting 

143 # class will fail). 

144 if type(classdict) is dict: 

145 original_dict = classdict 

146 classdict = _EnumDict() 

147 for k, v in original_dict.items(): 

148 classdict[k] = v 

149 

150 member_type, first_enum = metacls._get_mixins_(bases) 

151 #if member_type is object: 

152 # use_args = False 

153 #else: 

154 # use_args = True 

155 __new__, save_new, use_args = metacls._find_new_(classdict, member_type, 

156 first_enum) 

157 # save enum items into separate mapping so they don't get baked into 

158 # the new class 

159 members = dict((k, classdict[k]) for k in classdict._member_names) 

160 for name in classdict._member_names: 

161 del classdict[name] 

162 

163 # py2 support for definition order 

164 __order__ = classdict.get('__order__') 

165 if __order__ is None: 165 ↛ 172line 165 didn't jump to line 172, because the condition on line 165 was never false

166 __order__ = classdict._member_names 

167 if pyver < 3.0: 167 ↛ 168line 167 didn't jump to line 168, because the condition on line 167 was never true

168 order_specified = False 

169 else: 

170 order_specified = True 

171 else: 

172 del classdict['__order__'] 

173 order_specified = True 

174 if pyver < 3.0: 

175 __order__ = __order__.replace(',', ' ').split() 

176 aliases = [name for name in members if name not in __order__] 

177 __order__ += aliases 

178 

179 # check for illegal enum names (any others?) 

180 invalid_names = set(members) & set(['mro']) 

181 if invalid_names: 181 ↛ 182line 181 didn't jump to line 182, because the condition on line 181 was never true

182 raise ValueError('Invalid enum member name(s): %s' % ( 

183 ', '.join(invalid_names), )) 

184 

185 # create our new Enum type 

186 enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) 

187 enum_class._member_names_ = [] # names in random order 

188 enum_class._member_map_ = {} # name->value map 

189 enum_class._member_type_ = member_type 

190 

191 # Reverse value->name map for hashable values. 

192 enum_class._value2member_map_ = {} 

193 

194 # check for a __getnewargs__, and if not present sabotage 

195 # pickling, since it won't work anyway 

196 if (member_type is not object and 196 ↛ 199line 196 didn't jump to line 199, because the condition on line 196 was never true

197 member_type.__dict__.get('__getnewargs__') is None 

198 ): 

199 _make_class_unpicklable(enum_class) 

200 

201 # instantiate them, checking for duplicates as we go 

202 # we instantiate first instead of checking for duplicates first in case 

203 # a custom __new__ is doing something funky with the values -- such as 

204 # auto-numbering ;) 

205 if __new__ is None: 205 ↛ 206line 205 didn't jump to line 206, because the condition on line 205 was never true

206 __new__ = enum_class.__new__ 

207 for member_name in __order__: 

208 value = members[member_name] 

209 if not isinstance(value, tuple): 209 ↛ 212line 209 didn't jump to line 212, because the condition on line 209 was never false

210 args = (value, ) 

211 else: 

212 args = value 

213 if member_type is tuple: # special case for tuple enums 213 ↛ 214line 213 didn't jump to line 214, because the condition on line 213 was never true

214 args = (args, ) # wrap it one more time 

215 if not use_args or not args: 215 ↛ 220line 215 didn't jump to line 220, because the condition on line 215 was never false

216 enum_member = __new__(enum_class) 

217 if not hasattr(enum_member, '_value_'): 217 ↛ 223line 217 didn't jump to line 223, because the condition on line 217 was never false

218 enum_member._value_ = value 

219 else: 

220 enum_member = __new__(enum_class, *args) 

221 if not hasattr(enum_member, '_value_'): 

222 enum_member._value_ = member_type(*args) 

223 value = enum_member._value_ 

224 enum_member._name_ = member_name 

225 enum_member.__objclass__ = enum_class 

226 enum_member.__init__(*args) 

227 # If another member with the same value was already defined, the 

228 # new member becomes an alias to the existing one. 

229 for name, canonical_member in enum_class._member_map_.items(): 

230 if canonical_member.value == enum_member._value_: 

231 enum_member = canonical_member 

232 break 

233 else: 

234 # Aliases don't appear in member names (only in __members__). 

235 enum_class._member_names_.append(member_name) 

236 enum_class._member_map_[member_name] = enum_member 

237 try: 

238 # This may fail if value is not hashable. We can't add the value 

239 # to the map, and by-value lookups for this value will be 

240 # linear. 

241 enum_class._value2member_map_[value] = enum_member 

242 except TypeError: 

243 pass 

244 

245 # in Python2.x we cannot know definition order, so go with value order 

246 # unless __order__ was specified in the class definition 

247 if not order_specified: 247 ↛ 248line 247 didn't jump to line 248, because the condition on line 247 was never true

248 enum_class._member_names_ = [ 

249 e[0] for e in sorted( 

250 [(name, enum_class._member_map_[name]) for name in enum_class._member_names_], 

251 key=lambda t: t[1]._value_ 

252 )] 

253 

254 # double check that repr and friends are not the mixin's or various 

255 # things break (such as pickle) 

256 if Enum is not None: 

257 setattr(enum_class, '__getnewargs__', Enum.__getnewargs__) 

258 for name in ('__repr__', '__str__', '__format__'): 

259 class_method = getattr(enum_class, name) 

260 obj_method = getattr(member_type, name, None) 

261 enum_method = getattr(first_enum, name, None) 

262 if obj_method is not None and obj_method is class_method: 

263 setattr(enum_class, name, enum_method) 

264 

265 # method resolution and int's are not playing nice 

266 # Python's less than 2.6 use __cmp__ 

267 

268 if pyver < 2.6: 268 ↛ 270line 268 didn't jump to line 270, because the condition on line 268 was never true

269 

270 if issubclass(enum_class, int): 

271 setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) 

272 

273 elif pyver < 3.0: 273 ↛ 275line 273 didn't jump to line 275, because the condition on line 273 was never true

274 

275 if issubclass(enum_class, int): 

276 for method in ( 

277 '__le__', 

278 '__lt__', 

279 '__gt__', 

280 '__ge__', 

281 '__eq__', 

282 '__ne__', 

283 '__hash__', 

284 ): 

285 setattr(enum_class, method, getattr(int, method)) 

286 

287 # replace any other __new__ with our own (as long as Enum is not None, 

288 # anyway) -- again, this is to support pickle 

289 if Enum is not None: 

290 # if the user defined their own __new__, save it before it gets 

291 # clobbered in case they subclass later 

292 if save_new: 292 ↛ 293line 292 didn't jump to line 293, because the condition on line 292 was never true

293 setattr(enum_class, '__member_new__', enum_class.__dict__['__new__']) 

294 setattr(enum_class, '__new__', Enum.__dict__['__new__']) 

295 return enum_class 

296 

297 def __call__(cls, value, names=None, module=None, type=None): 

298 """Either returns an existing member, or creates a new enum class. 

299 

300 This method is used both when an enum class is given a value to match 

301 to an enumeration member (i.e. Color(3)) and for the functional API 

302 (i.e. Color = Enum('Color', names='red green blue')). 

303 

304 When used for the functional API: `module`, if set, will be stored in 

305 the new class' __module__ attribute; `type`, if set, will be mixed in 

306 as the first base class. 

307 

308 Note: if `module` is not set this routine will attempt to discover the 

309 calling module by walking the frame stack; if this is unsuccessful 

310 the resulting class will not be pickleable. 

311 

312 """ 

313 if names is None: # simple value lookup 313 ↛ 316line 313 didn't jump to line 316, because the condition on line 313 was never false

314 return cls.__new__(cls, value) 

315 # otherwise, functional API: we're creating a new Enum type 

316 return cls._create_(value, names, module=module, type=type) 

317 

318 def __contains__(cls, member): 

319 return isinstance(member, cls) and member.name in cls._member_map_ 

320 

321 def __delattr__(cls, attr): 

322 # nicer error message when someone tries to delete an attribute 

323 # (see issue19025). 

324 if attr in cls._member_map_: 

325 raise AttributeError( 

326 "%s: cannot delete Enum member." % cls.__name__) 

327 super(EnumMeta, cls).__delattr__(attr) 

328 

329 def __dir__(self): 

330 return (['__class__', '__doc__', '__members__', '__module__'] + 

331 self._member_names_) 

332 

333 @property 

334 def __members__(cls): 

335 """Returns a mapping of member name->value. 

336 

337 This mapping lists all enum members, including aliases. Note that this 

338 is a copy of the internal mapping. 

339 

340 """ 

341 return cls._member_map_.copy() 

342 

343 def __getattr__(cls, name): 

344 """Return the enum member matching `name` 

345 

346 We use __getattr__ instead of descriptors or inserting into the enum 

347 class' __dict__ in order to support `name` and `value` being both 

348 properties for enum members (which live in the class' __dict__) and 

349 enum members themselves. 

350 

351 """ 

352 if _is_dunder(name): 

353 raise AttributeError(name) 

354 try: 

355 return cls._member_map_[name] 

356 except KeyError: 

357 raise AttributeError(name) 

358 

359 def __getitem__(cls, name): 

360 return cls._member_map_[name] 

361 

362 def __iter__(cls): 

363 return (cls._member_map_[name] for name in cls._member_names_) 

364 

365 def __reversed__(cls): 

366 return (cls._member_map_[name] for name in reversed(cls._member_names_)) 

367 

368 def __len__(cls): 

369 return len(cls._member_names_) 

370 

371 def __repr__(cls): 

372 return "<enum %r>" % cls.__name__ 

373 

374 def __setattr__(cls, name, value): 

375 """Block attempts to reassign Enum members. 

376 

377 A simple assignment to the class namespace only changes one of the 

378 several possible ways to get an Enum member from the Enum class, 

379 resulting in an inconsistent Enumeration. 

380 

381 """ 

382 member_map = cls.__dict__.get('_member_map_', {}) 

383 if name in member_map: 383 ↛ 384line 383 didn't jump to line 384, because the condition on line 383 was never true

384 raise AttributeError('Cannot reassign members.') 

385 super(EnumMeta, cls).__setattr__(name, value) 

386 

387 def _create_(cls, class_name, names=None, module=None, type=None): 

388 """Convenience method to create a new Enum class. 

389 

390 `names` can be: 

391 

392 * A string containing member names, separated either with spaces or 

393 commas. Values are auto-numbered from 1. 

394 * An iterable of member names. Values are auto-numbered from 1. 

395 * An iterable of (member name, value) pairs. 

396 * A mapping of member name -> value. 

397 

398 """ 

399 metacls = cls.__class__ 

400 if type is None: 

401 bases = (cls, ) 

402 else: 

403 bases = (type, cls) 

404 classdict = metacls.__prepare__(class_name, bases) 

405 __order__ = [] 

406 

407 # special processing needed for names? 

408 if isinstance(names, str): 

409 names = names.replace(',', ' ').split() 

410 if isinstance(names, (tuple, list)) and isinstance(names[0], str): 

411 names = [(e, i+1) for (i, e) in enumerate(names)] 

412 

413 # Here, names is either an iterable of (name, value) or a mapping. 

414 for item in names: 

415 if isinstance(item, str): 

416 member_name, member_value = item, names[item] 

417 else: 

418 member_name, member_value = item 

419 classdict[member_name] = member_value 

420 __order__.append(member_name) 

421 # only set __order__ in classdict if name/value was not from a mapping 

422 if not isinstance(item, str): 

423 classdict['__order__'] = ' '.join(__order__) 

424 enum_class = metacls.__new__(metacls, class_name, bases, classdict) 

425 

426 # TODO: replace the frame hack if a blessed way to know the calling 

427 # module is ever developed 

428 if module is None: 

429 try: 

430 module = _sys._getframe(2).f_globals['__name__'] 

431 except (AttributeError, ValueError): 

432 pass 

433 if module is None: 

434 _make_class_unpicklable(enum_class) 

435 else: 

436 enum_class.__module__ = module 

437 

438 return enum_class 

439 

440 @staticmethod 

441 def _get_mixins_(bases): 

442 """Returns the type for creating enum members, and the first inherited 

443 enum class. 

444 

445 bases: the tuple of bases that was given to __new__ 

446 

447 """ 

448 if not bases or Enum is None: 

449 return object, Enum 

450 

451 

452 # double check that we are not subclassing a class with existing 

453 # enumeration members; while we're at it, see if any other data 

454 # type has been mixed in so we can use the correct __new__ 

455 member_type = first_enum = None 

456 for base in bases: 

457 if (base is not Enum and 457 ↛ 460line 457 didn't jump to line 460, because the condition on line 457 was never true

458 issubclass(base, Enum) and 

459 base._member_names_): 

460 raise TypeError("Cannot extend enumerations") 

461 # base is now the last base in bases 

462 if not issubclass(base, Enum): 462 ↛ 463line 462 didn't jump to line 463, because the condition on line 462 was never true

463 raise TypeError("new enumerations must be created as " 

464 "`ClassName([mixin_type,] enum_type)`") 

465 

466 # get correct mix-in type (either mix-in type of Enum subclass, or 

467 # first base if last base is Enum) 

468 if not issubclass(bases[0], Enum): 

469 member_type = bases[0] # first data type 

470 first_enum = bases[-1] # enum type 

471 else: 

472 for base in bases[0].__mro__: 

473 # most common: (IntEnum, int, Enum, object) 

474 # possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>, 

475 # <class 'int'>, <Enum 'Enum'>, 

476 # <class 'object'>) 

477 if issubclass(base, Enum): 

478 if first_enum is None: 478 ↛ 472line 478 didn't jump to line 472, because the condition on line 478 was never false

479 first_enum = base 

480 else: 

481 if member_type is None: 481 ↛ 472line 481 didn't jump to line 472, because the condition on line 481 was never false

482 member_type = base 

483 

484 return member_type, first_enum 

485 

486 if pyver < 3.0: 486 ↛ 487line 486 didn't jump to line 487, because the condition on line 486 was never true

487 @staticmethod 

488 def _find_new_(classdict, member_type, first_enum): 

489 """Returns the __new__ to be used for creating the enum members. 

490 

491 classdict: the class dictionary given to __new__ 

492 member_type: the data type whose __new__ will be used by default 

493 first_enum: enumeration to check for an overriding __new__ 

494 

495 """ 

496 # now find the correct __new__, checking to see of one was defined 

497 # by the user; also check earlier enum classes in case a __new__ was 

498 # saved as __member_new__ 

499 __new__ = classdict.get('__new__', None) 

500 if __new__: 

501 return None, True, True # __new__, save_new, use_args 

502 

503 N__new__ = getattr(None, '__new__') 

504 O__new__ = getattr(object, '__new__') 

505 if Enum is None: 

506 E__new__ = N__new__ 

507 else: 

508 E__new__ = Enum.__dict__['__new__'] 

509 # check all possibles for __member_new__ before falling back to 

510 # __new__ 

511 for method in ('__member_new__', '__new__'): 

512 for possible in (member_type, first_enum): 

513 try: 

514 target = possible.__dict__[method] 

515 except (AttributeError, KeyError): 

516 target = getattr(possible, method, None) 

517 if target not in [ 

518 None, 

519 N__new__, 

520 O__new__, 

521 E__new__, 

522 ]: 

523 if method == '__member_new__': 

524 classdict['__new__'] = target 

525 return None, False, True 

526 if isinstance(target, staticmethod): 

527 target = target.__get__(member_type) 

528 __new__ = target 

529 break 

530 if __new__ is not None: 

531 break 

532 else: 

533 __new__ = object.__new__ 

534 

535 # if a non-object.__new__ is used then whatever value/tuple was 

536 # assigned to the enum member name will be passed to __new__ and to the 

537 # new enum member's __init__ 

538 if __new__ is object.__new__: 

539 use_args = False 

540 else: 

541 use_args = True 

542 

543 return __new__, False, use_args 

544 else: 

545 @staticmethod 

546 def _find_new_(classdict, member_type, first_enum): 

547 """Returns the __new__ to be used for creating the enum members. 

548 

549 classdict: the class dictionary given to __new__ 

550 member_type: the data type whose __new__ will be used by default 

551 first_enum: enumeration to check for an overriding __new__ 

552 

553 """ 

554 # now find the correct __new__, checking to see of one was defined 

555 # by the user; also check earlier enum classes in case a __new__ was 

556 # saved as __member_new__ 

557 __new__ = classdict.get('__new__', None) 

558 

559 # should __new__ be saved as __member_new__ later? 

560 save_new = __new__ is not None 

561 

562 if __new__ is None: 

563 # check all possibles for __member_new__ before falling back to 

564 # __new__ 

565 for method in ('__member_new__', '__new__'): 

566 for possible in (member_type, first_enum): 

567 target = getattr(possible, method, None) 

568 if target not in ( 

569 None, 

570 None.__new__, 

571 object.__new__, 

572 Enum.__new__, 

573 ): 

574 __new__ = target 

575 break 

576 if __new__ is not None: 

577 break 

578 else: 

579 __new__ = object.__new__ 

580 

581 # if a non-object.__new__ is used then whatever value/tuple was 

582 # assigned to the enum member name will be passed to __new__ and to the 

583 # new enum member's __init__ 

584 if __new__ is object.__new__: 

585 use_args = False 

586 else: 

587 use_args = True 

588 

589 return __new__, save_new, use_args 

590 

591 

592######################################################## 

593# In order to support Python 2 and 3 with a single 

594# codebase we have to create the Enum methods separately 

595# and then use the `type(name, bases, dict)` method to 

596# create the class. 

597######################################################## 

598temp_enum_dict = {} 

599temp_enum_dict['__doc__'] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" 

600 

601def __new__(cls, value): 

602 # all enum instances are actually created during class construction 

603 # without calling this method; this method is called by the metaclass' 

604 # __call__ (i.e. Color(3) ), and by pickle 

605 if type(value) is cls: 605 ↛ 607line 605 didn't jump to line 607, because the condition on line 605 was never true

606 # For lookups like Color(Color.red) 

607 value = value.value 

608 #return value 

609 # by-value search for a matching enum member 

610 # see if it's in the reverse mapping (for hashable values) 

611 try: 

612 if value in cls._value2member_map_: 

613 return cls._value2member_map_[value] 

614 except TypeError: 

615 # not there, now do long search -- O(n) behavior 

616 for member in cls._member_map_.values(): 

617 if member.value == value: 

618 return member 

619 raise ValueError("%s is not a valid %s" % (value, cls.__name__)) 

620temp_enum_dict['__new__'] = __new__ 

621del __new__ 

622 

623def __repr__(self): 

624 return "<%s.%s: %r>" % ( 

625 self.__class__.__name__, self._name_, self._value_) 

626temp_enum_dict['__repr__'] = __repr__ 

627del __repr__ 

628 

629def __str__(self): 

630 return "%s.%s" % (self.__class__.__name__, self._name_) 

631temp_enum_dict['__str__'] = __str__ 

632del __str__ 

633 

634def __dir__(self): 

635 added_behavior = [m for m in self.__class__.__dict__ if m[0] != '_'] 

636 return (['__class__', '__doc__', '__module__', 'name', 'value'] + added_behavior) 

637temp_enum_dict['__dir__'] = __dir__ 

638del __dir__ 

639 

640def __format__(self, format_spec): 

641 # mixed-in Enums should use the mixed-in type's __format__, otherwise 

642 # we can get strange results with the Enum name showing up instead of 

643 # the value 

644 

645 # pure Enum branch 

646 if self._member_type_ is object: 

647 cls = str 

648 val = str(self) 

649 # mix-in branch 

650 else: 

651 cls = self._member_type_ 

652 val = self.value 

653 return cls.__format__(val, format_spec) 

654temp_enum_dict['__format__'] = __format__ 

655del __format__ 

656 

657 

658#################################### 

659# Python's less than 2.6 use __cmp__ 

660 

661if pyver < 2.6: 661 ↛ 663line 661 didn't jump to line 663, because the condition on line 661 was never true

662 

663 def __cmp__(self, other): 

664 if type(other) is self.__class__: 

665 if self is other: 

666 return 0 

667 return -1 

668 return NotImplemented 

669 raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) 

670 temp_enum_dict['__cmp__'] = __cmp__ 

671 del __cmp__ 

672 

673else: 

674 

675 def __le__(self, other): 

676 raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) 

677 temp_enum_dict['__le__'] = __le__ 

678 del __le__ 

679 

680 def __lt__(self, other): 

681 raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) 

682 temp_enum_dict['__lt__'] = __lt__ 

683 del __lt__ 

684 

685 def __ge__(self, other): 

686 raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) 

687 temp_enum_dict['__ge__'] = __ge__ 

688 del __ge__ 

689 

690 def __gt__(self, other): 

691 raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) 

692 temp_enum_dict['__gt__'] = __gt__ 

693 del __gt__ 

694 

695 

696def __eq__(self, other): 

697 if type(other) is self.__class__: 

698 return self is other 

699 return NotImplemented 

700temp_enum_dict['__eq__'] = __eq__ 

701del __eq__ 

702 

703def __ne__(self, other): 

704 if type(other) is self.__class__: 

705 return self is not other 

706 return NotImplemented 

707temp_enum_dict['__ne__'] = __ne__ 

708del __ne__ 

709 

710def __getnewargs__(self): 

711 return (self._value_, ) 

712temp_enum_dict['__getnewargs__'] = __getnewargs__ 

713del __getnewargs__ 

714 

715def __hash__(self): 

716 return hash(self._name_) 

717temp_enum_dict['__hash__'] = __hash__ 

718del __hash__ 

719 

720# _RouteClassAttributeToGetattr is used to provide access to the `name` 

721# and `value` properties of enum members while keeping some measure of 

722# protection from modification, while still allowing for an enumeration 

723# to have members named `name` and `value`. This works because enumeration 

724# members are not set directly on the enum class -- __getattr__ is 

725# used to look them up. 

726 

727@_RouteClassAttributeToGetattr 

728def name(self): 

729 return self._name_ 

730temp_enum_dict['name'] = name 

731del name 

732 

733@_RouteClassAttributeToGetattr 

734def value(self): 

735 return self._value_ 

736temp_enum_dict['value'] = value 

737del value 

738 

739Enum = EnumMeta('Enum', (object, ), temp_enum_dict) 

740del temp_enum_dict 

741 

742# Enum has now been created 

743########################### 

744 

745class IntEnum(int, Enum): 

746 """Enum where members are also (and must be) ints""" 

747 

748 

749def unique(enumeration): 

750 """Class decorator that ensures only unique members exist in an enumeration.""" 

751 duplicates = [] 

752 for name, member in enumeration.__members__.items(): 

753 if name != member.name: 

754 duplicates.append((name, member.name)) 

755 if duplicates: 

756 duplicate_names = ', '.join( 

757 ["%s -> %s" % (alias, name) for (alias, name) in duplicates] 

758 ) 

759 raise ValueError('duplicate names found in %r: %s' % 

760 (enumeration, duplicate_names) 

761 ) 

762 return enumeration