Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/dadict.py: 70%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

69 statements  

1# SPDX-License-Identifier: GPL-2.0-only 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Copyright (C) Philippe Biondi <phil@secdev.org> 

5 

6""" 

7Direct Access dictionary. 

8""" 

9 

10from scapy.error import Scapy_Exception 

11from scapy.compat import plain_str 

12 

13# Typing 

14from typing import ( 

15 Any, 

16 Dict, 

17 Generic, 

18 Iterator, 

19 List, 

20 Tuple, 

21 Type, 

22 TypeVar, 

23 Union, 

24) 

25from scapy.compat import Self 

26 

27 

28############################### 

29# Direct Access dictionary # 

30############################### 

31 

32 

33def fixname(x): 

34 # type: (Union[bytes, str]) -> str 

35 """ 

36 Modifies a string to make sure it can be used as an attribute name. 

37 """ 

38 x = plain_str(x) 

39 if x and str(x[0]) in "0123456789": 

40 x = "n_" + x 

41 return x.translate( 

42 "________________________________________________" 

43 "0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______" 

44 "abcdefghijklmnopqrstuvwxyz____________________________" 

45 "______________________________________________________" 

46 "___________________________________________________" 

47 ) 

48 

49 

50class DADict_Exception(Scapy_Exception): 

51 pass 

52 

53 

54_K = TypeVar('_K') # Key type 

55_V = TypeVar('_V') # Value type 

56 

57 

58class DADict(Generic[_K, _V]): 

59 """ 

60 Direct Access Dictionary 

61 

62 This acts like a dict, but it provides a direct attribute access 

63 to its keys through its values. This is used to store protocols, 

64 manuf... 

65 

66 For instance, scapy fields will use a DADict as an enum:: 

67 

68 ETHER_TYPES[2048] -> IPv4 

69 

70 Whereas humans can access:: 

71 

72 ETHER_TYPES.IPv4 -> 2048 

73 """ 

74 __slots__ = ["_name", "d"] 

75 

76 def __init__(self, _name="DADict", **kargs): 

77 # type: (str, **Any) -> None 

78 self._name = _name 

79 self.d = {} # type: Dict[_K, _V] 

80 self.update(kargs) # type: ignore 

81 

82 def ident(self, v): 

83 # type: (_V) -> str 

84 """ 

85 Return value that is used as key for the direct access 

86 """ 

87 if isinstance(v, (str, bytes)): 

88 return fixname(v) 

89 return "unknown" 

90 

91 def update(self, *args, **kwargs): 

92 # type: (*Dict[_K, _V], **Dict[_K, _V]) -> None 

93 for k, v in dict(*args, **kwargs).items(): 

94 self[k] = v # type: ignore 

95 

96 def iterkeys(self): 

97 # type: () -> Iterator[_K] 

98 for x in self.d: 

99 if not isinstance(x, str) or x[0] != "_": 

100 yield x 

101 

102 def keys(self): 

103 # type: () -> List[_K] 

104 return list(self.iterkeys()) 

105 

106 def __iter__(self): 

107 # type: () -> Iterator[_K] 

108 return self.iterkeys() 

109 

110 def itervalues(self): 

111 # type: () -> Iterator[_V] 

112 return self.d.values() # type: ignore 

113 

114 def values(self): 

115 # type: () -> List[_V] 

116 return list(self.itervalues()) 

117 

118 def _show(self): 

119 # type: () -> None 

120 for k in self.iterkeys(): 

121 print("%10s = %r" % (k, self[k])) 

122 

123 def __repr__(self): 

124 # type: () -> str 

125 return "<%s - %s elements>" % (self._name, len(self)) 

126 

127 def __getitem__(self, attr): 

128 # type: (_K) -> _V 

129 return self.d[attr] 

130 

131 def __setitem__(self, attr, val): 

132 # type: (_K, _V) -> None 

133 self.d[attr] = val 

134 

135 def __len__(self): 

136 # type: () -> int 

137 return len(self.d) 

138 

139 def __nonzero__(self): 

140 # type: () -> bool 

141 # Always has at least its name 

142 return len(self) > 1 

143 __bool__ = __nonzero__ 

144 

145 def __getattr__(self, attr): 

146 # type: (str) -> _K 

147 try: 

148 return object.__getattribute__(self, attr) # type: ignore 

149 except AttributeError: 

150 for k, v in self.d.items(): 

151 if self.ident(v) == attr: 

152 return k 

153 raise AttributeError 

154 

155 def __dir__(self): 

156 # type: () -> List[str] 

157 return [self.ident(x) for x in self.itervalues()] 

158 

159 def __reduce__(self): 

160 # type: () -> Tuple[Type[Self], Tuple[str], Tuple[Dict[_K, _V]]] 

161 return (self.__class__, (self._name,), (self.d,)) 

162 

163 def __setstate__(self, state): 

164 # type: (Tuple[Dict[_K, _V]]) -> Self 

165 self.d.update(state[0]) 

166 return self