Coverage for /root/GitHubProjects/impacket/impacket/dcerpc/v5/enum.py: 53%

# Coverage for /root/GitHubProjects/impacket/impacket/dcerpc/v5/enum.py : 53%

## 383 statements

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

11 import sys as _sys

12

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

14

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

16

17 try:

18 any

19 except NameError:

20 def any(iterable):

21 for element in iterable:

22 if element:

23 return True

24 return False

25

26

27 class _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

51 def _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

59 def _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

67 def _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

75 def _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

83 class _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`

130 Enum = None

131

132

133 class 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########################################################

598 temp_enum_dict = {}

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

600

601 def __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__))

620 temp_enum_dict['__new__'] = __new__

621 del __new__

622

623 def __repr__(self):

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

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

626 temp_enum_dict['__repr__'] = __repr__

627 del __repr__

628

629 def __str__(self):

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

631 temp_enum_dict['__str__'] = __str__

632 del __str__

633

634 def __dir__(self):

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

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

637 temp_enum_dict['__dir__'] = __dir__

638 del __dir__

639

640 def __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)

654 temp_enum_dict['__format__'] = __format__

655 del __format__

656

657

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

659# Python's less than 2.6 use __cmp__

660

661 if 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

673 else:

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

696 def __eq__(self, other):

697 if type(other) is self.__class__:

698 return self is other

699 return NotImplemented

700 temp_enum_dict['__eq__'] = __eq__

701 del __eq__

702

703 def __ne__(self, other):

704 if type(other) is self.__class__:

705 return self is not other

706 return NotImplemented

707 temp_enum_dict['__ne__'] = __ne__

708 del __ne__

709

710 def __getnewargs__(self):

711 return (self._value_, )

712 temp_enum_dict['__getnewargs__'] = __getnewargs__

713 del __getnewargs__

714

715 def __hash__(self):

716 return hash(self._name_)

717 temp_enum_dict['__hash__'] = __hash__

718 del __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

728 def name(self):

729 return self._name_

730 temp_enum_dict['name'] = name

731 del name

732

733@_RouteClassAttributeToGetattr

734 def value(self):

735 return self._value_

736 temp_enum_dict['value'] = value

737 del value

738

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

740 del temp_enum_dict

741

742# Enum has now been created

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

744

745 class IntEnum(int, Enum):

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

747

748

749 def 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