1# 2# This file is part of pyasn1 software. 3# 4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com> 5# License: http://snmplabs.com/pyasn1/license.html 6# 7# ASN.1 named integers 8# 9from pyasn1 import error 10 11__all__ = ['NamedValues'] 12 13 14class NamedValues(object): 15 """Create named values object. 16 17 The |NamedValues| object represents a collection of string names 18 associated with numeric IDs. These objects are used for giving 19 names to otherwise numerical values. 20 21 |NamedValues| objects are immutable and duck-type Python 22 :class:`dict` object mapping ID to name and vice-versa. 23 24 Parameters 25 ---------- 26 *args: variable number of two-element :py:class:`tuple` 27 28 name: :py:class:`str` 29 Value label 30 31 value: :py:class:`int` 32 Numeric value 33 34 Keyword Args 35 ------------ 36 name: :py:class:`str` 37 Value label 38 39 value: :py:class:`int` 40 Numeric value 41 42 Examples 43 -------- 44 45 .. code-block:: pycon 46 47 >>> nv = NamedValues('a', 'b', ('c', 0), d=1) 48 >>> nv 49 >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3} 50 >>> nv[0] 51 'c' 52 >>> nv['a'] 53 2 54 """ 55 def __init__(self, *args, **kwargs): 56 self.__names = {} 57 self.__numbers = {} 58 59 anonymousNames = [] 60 61 for namedValue in args: 62 if isinstance(namedValue, (tuple, list)): 63 try: 64 name, number = namedValue 65 66 except ValueError: 67 raise error.PyAsn1Error('Not a proper attribute-value pair %r' % (namedValue,)) 68 69 else: 70 anonymousNames.append(namedValue) 71 continue 72 73 if name in self.__names: 74 raise error.PyAsn1Error('Duplicate name %s' % (name,)) 75 76 if number in self.__numbers: 77 raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) 78 79 self.__names[name] = number 80 self.__numbers[number] = name 81 82 for name, number in kwargs.items(): 83 if name in self.__names: 84 raise error.PyAsn1Error('Duplicate name %s' % (name,)) 85 86 if number in self.__numbers: 87 raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) 88 89 self.__names[name] = number 90 self.__numbers[number] = name 91 92 if anonymousNames: 93 94 number = self.__numbers and max(self.__numbers) + 1 or 0 95 96 for name in anonymousNames: 97 98 if name in self.__names: 99 raise error.PyAsn1Error('Duplicate name %s' % (name,)) 100 101 self.__names[name] = number 102 self.__numbers[number] = name 103 104 number += 1 105 106 def __repr__(self): 107 representation = ', '.join(['%s=%d' % x for x in self.items()]) 108 109 if len(representation) > 64: 110 representation = representation[:32] + '...' + representation[-32:] 111 112 return '<%s object, enums %s>' % ( 113 self.__class__.__name__, representation) 114 115 def __eq__(self, other): 116 return dict(self) == other 117 118 def __ne__(self, other): 119 return dict(self) != other 120 121 def __lt__(self, other): 122 return dict(self) < other 123 124 def __le__(self, other): 125 return dict(self) <= other 126 127 def __gt__(self, other): 128 return dict(self) > other 129 130 def __ge__(self, other): 131 return dict(self) >= other 132 133 def __hash__(self): 134 return hash(self.items()) 135 136 # Python dict protocol (read-only) 137 138 def __getitem__(self, key): 139 try: 140 return self.__numbers[key] 141 142 except KeyError: 143 return self.__names[key] 144 145 def __len__(self): 146 return len(self.__names) 147 148 def __contains__(self, key): 149 return key in self.__names or key in self.__numbers 150 151 def __iter__(self): 152 return iter(self.__names) 153 154 def values(self): 155 return iter(self.__numbers) 156 157 def keys(self): 158 return iter(self.__names) 159 160 def items(self): 161 for name in self.__names: 162 yield name, self.__names[name] 163 164 # support merging 165 166 def __add__(self, namedValues): 167 return self.__class__(*tuple(self.items()) + tuple(namedValues.items())) 168 169 # XXX clone/subtype? 170 171 def clone(self, *args, **kwargs): 172 new = self.__class__(*args, **kwargs) 173 return self + new 174 175 # legacy protocol 176 177 def getName(self, value): 178 if value in self.__numbers: 179 return self.__numbers[value] 180 181 def getValue(self, name): 182 if name in self.__names: 183 return self.__names[name] 184 185 def getValues(self, *names): 186 try: 187 return [self.__names[name] for name in names] 188 189 except KeyError: 190 raise error.PyAsn1Error( 191 'Unknown bit identifier(s): %s' % (set(names).difference(self.__names),) 192 ) 193