1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 2 3# Copyright (C) 2003-2017 Nominum, Inc. 4# 5# Permission to use, copy, modify, and distribute this software and its 6# documentation for any purpose with or without fee is hereby granted, 7# provided that the above copyright notice and this permission notice 8# appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18import enum 19 20class IntEnum(enum.IntEnum): 21 @classmethod 22 def _check_value(cls, value): 23 max = cls._maximum() 24 if value < 0 or value > max: 25 name = cls._short_name() 26 raise ValueError(f"{name} must be between >= 0 and <= {max}") 27 28 @classmethod 29 def from_text(cls, text): 30 text = text.upper() 31 try: 32 return cls[text] 33 except KeyError: 34 pass 35 prefix = cls._prefix() 36 if text.startswith(prefix) and text[len(prefix):].isdigit(): 37 value = int(text[len(prefix):]) 38 cls._check_value(value) 39 try: 40 return cls(value) 41 except ValueError: 42 return value 43 raise cls._unknown_exception_class() 44 45 @classmethod 46 def to_text(cls, value): 47 cls._check_value(value) 48 try: 49 return cls(value).name 50 except ValueError: 51 return f"{cls._prefix()}{value}" 52 53 @classmethod 54 def make(cls, value): 55 """Convert text or a value into an enumerated type, if possible. 56 57 *value*, the ``int`` or ``str`` to convert. 58 59 Raises a class-specific exception if a ``str`` is provided that 60 cannot be converted. 61 62 Raises ``ValueError`` if the value is out of range. 63 64 Returns an enumeration from the calling class corresponding to the 65 value, if one is defined, or an ``int`` otherwise. 66 """ 67 68 if isinstance(value, str): 69 return cls.from_text(value) 70 cls._check_value(value) 71 try: 72 return cls(value) 73 except ValueError: 74 return value 75 76 @classmethod 77 def _maximum(cls): 78 raise NotImplementedError # pragma: no cover 79 80 @classmethod 81 def _short_name(cls): 82 return cls.__name__.lower() 83 84 @classmethod 85 def _prefix(cls): 86 return '' 87 88 @classmethod 89 def _unknown_exception_class(cls): 90 return ValueError 91