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

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

## 382 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"""Python Enumerations"""

2

3 import sys as _sys

4

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

6

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

8

9 try:

10 any

11 except NameError:

12 def any(iterable):

13 for element in iterable:

14 if element:

15 return True

16 return False

17

18

19 class _RouteClassAttributeToGetattr(object):

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

21

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

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

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

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

26

27 """

28 def __init__(self, fget=None):

29 self.fget = fget

30

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

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

33 raise AttributeError()

34 return self.fget(instance)

35

36 def __set__(self, instance, value):

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

38

39 def __delete__(self, instance):

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

41

42

43 def _is_descriptor(obj):

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

45 return (

46 hasattr(obj, '__get__') or

47 hasattr(obj, '__set__') or

48 hasattr(obj, '__delete__'))

49

50

51 def _is_dunder(name):

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

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

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

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

56 len(name) > 4)

57

58

59 def _is_sunder(name):

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

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

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

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

64 len(name) > 2)

65

66

67 def _make_class_unpicklable(cls):

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

69 def _break_on_call_reduce(self):

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

71 cls.__reduce__ = _break_on_call_reduce

72 cls.__module__ = '<unknown>'

73

74

75 class _EnumDict(dict):

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

77

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

79 enumeration member names.

80

81 """

82 def __init__(self):

83 super(_EnumDict, self).__init__()

84 self._member_names = []

85

86 def __setitem__(self, key, value):

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

88

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

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

91 sequence of values).

92

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

94 values are not checked for.

95

96 Single underscore (sunder) names are reserved.

97

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

99 leftover from 2.x

100

101 """

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

103 return

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

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

106 elif _is_dunder(key):

107 pass

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

109 # descriptor overwriting an enum?

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

111 elif not _is_descriptor(value):

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

113 # enum overwriting a descriptor?

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

115 self._member_names.append(key)

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

117

118

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

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

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

122 Enum = None

123

124

125 class EnumMeta(type):

126 """Metaclass for Enum"""

127 @classmethod

128 def __prepare__(metacls, cls, bases):

129 return _EnumDict()

130

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

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

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

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

135 # class will fail).

136 if type(classdict) is dict:

137 original_dict = classdict

138 classdict = _EnumDict()

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

140 classdict[k] = v

141

142 member_type, first_enum = metacls._get_mixins_(bases)

143 #if member_type is object:

144 # use_args = False

145 #else:

146 # use_args = True

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

148 first_enum)

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

150 # the new class

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

152 for name in classdict._member_names:

153 del classdict[name]

154

155 # py2 support for definition order

156 __order__ = classdict.get('__order__')

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

158 __order__ = classdict._member_names

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

160 order_specified = False

161 else:

162 order_specified = True

163 else:

164 del classdict['__order__']

165 order_specified = True

166 if pyver < 3.0:

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

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

169 __order__ += aliases

170

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

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

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

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

175 ', '.join(invalid_names), ))

176

177 # create our new Enum type

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

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

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

181 enum_class._member_type_ = member_type

182

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

184 enum_class._value2member_map_ = {}

185

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

187 # pickling, since it won't work anyway

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

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

190 ):

191 _make_class_unpicklable(enum_class)

192

193 # instantiate them, checking for duplicates as we go

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

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

196 # auto-numbering ;)

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

198 __new__ = enum_class.__new__

199 for member_name in __order__:

200 value = members[member_name]

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

202 args = (value, )

203 else:

204 args = value

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

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

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

208 enum_member = __new__(enum_class)

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

210 enum_member._value_ = value

211 else:

212 enum_member = __new__(enum_class, *args)

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

214 enum_member._value_ = member_type(*args)

215 value = enum_member._value_

216 enum_member._name_ = member_name

217 enum_member.__objclass__ = enum_class

218 enum_member.__init__(*args)

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

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

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

222 if canonical_member.value == enum_member._value_:

223 enum_member = canonical_member

224 break

225 else:

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

227 enum_class._member_names_.append(member_name)

228 enum_class._member_map_[member_name] = enum_member

229 try:

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

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

232 # linear.

233 enum_class._value2member_map_[value] = enum_member

234 except TypeError:

235 pass

236

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

238 # unless __order__ was specified in the class definition

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

240 enum_class._member_names_ = [

241 e[0] for e in sorted(

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

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

244 )]

245

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

247 # things break (such as pickle)

248 if Enum is not None:

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

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

251 class_method = getattr(enum_class, name)

252 obj_method = getattr(member_type, name, None)

253 enum_method = getattr(first_enum, name, None)

254 if obj_method is not None and obj_method is class_method:

255 setattr(enum_class, name, enum_method)

256

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

258 # Python's less than 2.6 use __cmp__

259

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

261

262 if issubclass(enum_class, int):

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

264

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

266

267 if issubclass(enum_class, int):

268 for method in (

269 '__le__',

270 '__lt__',

271 '__gt__',

272 '__ge__',

273 '__eq__',

274 '__ne__',

275 '__hash__',

276 ):

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

278

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

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

281 if Enum is not None:

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

283 # clobbered in case they subclass later

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

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

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

287 return enum_class

288

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

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

291

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

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

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

295

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

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

298 as the first base class.

299

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

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

302 the resulting class will not be pickleable.

303

304 """

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

306 return cls.__new__(cls, value)

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

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

309

310 def __contains__(cls, member):

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

312

313 def __delattr__(cls, attr):

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

315 # (see issue19025).

316 if attr in cls._member_map_:

317 raise AttributeError(

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

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

320

321 def __dir__(self):

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

323 self._member_names_)

324

325 @property

326 def __members__(cls):

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

328

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

330 is a copy of the internal mapping.

331

332 """

333 return cls._member_map_.copy()

334

335 def __getattr__(cls, name):

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

337

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

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

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

341 enum members themselves.

342

343 """

344 if _is_dunder(name):

345 raise AttributeError(name)

346 try:

347 return cls._member_map_[name]

348 except KeyError:

349 raise AttributeError(name)

350

351 def __getitem__(cls, name):

352 return cls._member_map_[name]

353

354 def __iter__(cls):

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

356

357 def __reversed__(cls):

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

359

360 def __len__(cls):

361 return len(cls._member_names_)

362

363 def __repr__(cls):

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

365

366 def __setattr__(cls, name, value):

367 """Block attempts to reassign Enum members.

368

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

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

371 resulting in an inconsistent Enumeration.

372

373 """

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

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

376 raise AttributeError('Cannot reassign members.')

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

378

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

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

381

382 `names` can be:

383

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

385 commas. Values are auto-numbered from 1.

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

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

388 * A mapping of member name -> value.

389

390 """

391 metacls = cls.__class__

392 if type is None:

393 bases = (cls, )

394 else:

395 bases = (type, cls)

396 classdict = metacls.__prepare__(class_name, bases)

397 __order__ = []

398

399 # special processing needed for names?

400 if isinstance(names, str):

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

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

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

404

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

406 for item in names:

407 if isinstance(item, str):

408 member_name, member_value = item, names[item]

409 else:

410 member_name, member_value = item

411 classdict[member_name] = member_value

412 __order__.append(member_name)

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

414 if not isinstance(item, str):

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

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

417

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

419 # module is ever developed

420 if module is None:

421 try:

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

423 except (AttributeError, ValueError):

424 pass

425 if module is None:

426 _make_class_unpicklable(enum_class)

427 else:

428 enum_class.__module__ = module

429

430 return enum_class

431

432 @staticmethod

433 def _get_mixins_(bases):

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

435 enum class.

436

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

438

439 """

440 if not bases or Enum is None:

441 return object, Enum

442

443

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

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

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

447 member_type = first_enum = None

448 for base in bases:

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

450 issubclass(base, Enum) and

451 base._member_names_):

452 raise TypeError("Cannot extend enumerations")

453 # base is now the last base in bases

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

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

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

457

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

459 # first base if last base is Enum)

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

461 member_type = bases[0] # first data type

462 first_enum = bases[-1] # enum type

463 else:

464 for base in bases[0].__mro__:

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

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

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

468 # <class 'object'>)

469 if issubclass(base, Enum):

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

471 first_enum = base

472 else:

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

474 member_type = base

475

476 return member_type, first_enum

477

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

479 @staticmethod

480 def _find_new_(classdict, member_type, first_enum):

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

482

483 classdict: the class dictionary given to __new__

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

485 first_enum: enumeration to check for an overriding __new__

486

487 """

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

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

490 # saved as __member_new__

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

492 if __new__:

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

494

495 N__new__ = getattr(None, '__new__')

496 O__new__ = getattr(object, '__new__')

497 if Enum is None:

498 E__new__ = N__new__

499 else:

500 E__new__ = Enum.__dict__['__new__']

501 # check all possibles for __member_new__ before falling back to

502 # __new__

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

504 for possible in (member_type, first_enum):

505 try:

506 target = possible.__dict__[method]

507 except (AttributeError, KeyError):

508 target = getattr(possible, method, None)

509 if target not in [

510 None,

511 N__new__,

512 O__new__,

513 E__new__,

514 ]:

515 if method == '__member_new__':

516 classdict['__new__'] = target

517 return None, False, True

518 if isinstance(target, staticmethod):

519 target = target.__get__(member_type)

520 __new__ = target

521 break

522 if __new__ is not None:

523 break

524 else:

525 __new__ = object.__new__

526

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

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

529 # new enum member's __init__

530 if __new__ is object.__new__:

531 use_args = False

532 else:

533 use_args = True

534

535 return __new__, False, use_args

536 else:

537 @staticmethod

538 def _find_new_(classdict, member_type, first_enum):

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

540

541 classdict: the class dictionary given to __new__

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

543 first_enum: enumeration to check for an overriding __new__

544

545 """

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

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

548 # saved as __member_new__

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

550

551 # should __new__ be saved as __member_new__ later?

552 save_new = __new__ is not None

553

554 if __new__ is None:

555 # check all possibles for __member_new__ before falling back to

556 # __new__

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

558 for possible in (member_type, first_enum):

559 target = getattr(possible, method, None)

560 if target not in (

561 None,

562 None.__new__,

563 object.__new__,

564 Enum.__new__,

565 ):

566 __new__ = target

567 break

568 if __new__ is not None:

569 break

570 else:

571 __new__ = object.__new__

572

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

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

575 # new enum member's __init__

576 if __new__ is object.__new__:

577 use_args = False

578 else:

579 use_args = True

580

581 return __new__, save_new, use_args

582

583

584########################################################

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

586# codebase we have to create the Enum methods separately

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

588# create the class.

589########################################################

590 temp_enum_dict = {}

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

592

593 def __new__(cls, value):

594 # all enum instances are actually created during class construction

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

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

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

598 # For lookups like Color(Color.red)

599 value = value.value

600 #return value

601 # by-value search for a matching enum member

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

603 try:

604 if value in cls._value2member_map_:

605 return cls._value2member_map_[value]

606 except TypeError:

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

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

609 if member.value == value:

610 return member

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

612 temp_enum_dict['__new__'] = __new__

613 del __new__

614

615 def __repr__(self):

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

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

618 temp_enum_dict['__repr__'] = __repr__

619 del __repr__

620

621 def __str__(self):

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

623 temp_enum_dict['__str__'] = __str__

624 del __str__

625

626 def __dir__(self):

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

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

629 temp_enum_dict['__dir__'] = __dir__

630 del __dir__

631

632 def __format__(self, format_spec):

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

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

635 # the value

636

637 # pure Enum branch

638 if self._member_type_ is object:

639 cls = str

640 val = str(self)

641 # mix-in branch

642 else:

643 cls = self._member_type_

644 val = self.value

645 return cls.__format__(val, format_spec)

646 temp_enum_dict['__format__'] = __format__

647 del __format__

648

649

650####################################

651# Python's less than 2.6 use __cmp__

652

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

654

655 def __cmp__(self, other):

656 if type(other) is self.__class__:

657 if self is other:

658 return 0

659 return -1

660 return NotImplemented

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

662 temp_enum_dict['__cmp__'] = __cmp__

663 del __cmp__

664

665 else:

666

667 def __le__(self, other):

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

669 temp_enum_dict['__le__'] = __le__

670 del __le__

671

672 def __lt__(self, other):

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

674 temp_enum_dict['__lt__'] = __lt__

675 del __lt__

676

677 def __ge__(self, other):

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

679 temp_enum_dict['__ge__'] = __ge__

680 del __ge__

681

682 def __gt__(self, other):

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

684 temp_enum_dict['__gt__'] = __gt__

685 del __gt__

686

687

688 def __eq__(self, other):

689 if type(other) is self.__class__:

690 return self is other

691 return NotImplemented

692 temp_enum_dict['__eq__'] = __eq__

693 del __eq__

694

695 def __ne__(self, other):

696 if type(other) is self.__class__:

697 return self is not other

698 return NotImplemented

699 temp_enum_dict['__ne__'] = __ne__

700 del __ne__

701

702 def __getnewargs__(self):

703 return (self._value_, )

704 temp_enum_dict['__getnewargs__'] = __getnewargs__

705 del __getnewargs__

706

707 def __hash__(self):

708 return hash(self._name_)

709 temp_enum_dict['__hash__'] = __hash__

710 del __hash__

711

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

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

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

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

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

717# used to look them up.

718

719@_RouteClassAttributeToGetattr

720 def name(self):

721 return self._name_

722 temp_enum_dict['name'] = name

723 del name

724

725@_RouteClassAttributeToGetattr

726 def value(self):

727 return self._value_

728 temp_enum_dict['value'] = value

729 del value

730

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

732 del temp_enum_dict

733

734# Enum has now been created

735###########################

736

737 class IntEnum(int, Enum):

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

739

740

741 def unique(enumeration):

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

743 duplicates = []

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

745 if name != member.name:

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

747 if duplicates:

748 duplicate_names = ', '.join(

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

750 )

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

752 (enumeration, duplicate_names)

753 )

754 return enumeration