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

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

70 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 

5""" 

6Compatibility module to various older versions of Python 

7""" 

8 

9import base64 

10import binascii 

11import enum 

12import struct 

13import sys 

14 

15from typing import ( 

16 Any, 

17 AnyStr, 

18 Callable, 

19 Optional, 

20 TypeVar, 

21 TYPE_CHECKING, 

22 Union, 

23) 

24 

25# Very important: will issue typing errors otherwise 

26__all__ = [ 

27 # typing 

28 'DecoratorCallable', 

29 'Literal', 

30 'Protocol', 

31 'Self', 

32 'UserDict', 

33 # compat 

34 'base64_bytes', 

35 'bytes_base64', 

36 'bytes_encode', 

37 'bytes_hex', 

38 'chb', 

39 'hex_bytes', 

40 'orb', 

41 'plain_str', 

42 'raw', 

43 'StrEnum', 

44] 

45 

46# Typing compatibility 

47 

48# Note: 

49# supporting typing on multiple python versions is a nightmare. 

50# we provide a FakeType class to be able to use types added on 

51# later Python versions (since we run mypy on 3.14), on older 

52# ones. 

53 

54 

55# Import or create fake types 

56 

57def _FakeType(name, cls=object): 

58 # type: (str, Optional[type]) -> Any 

59 class _FT(object): 

60 def __init__(self, name): 

61 # type: (str) -> None 

62 self.name = name 

63 

64 # make the objects subscriptable indefinitely 

65 def __getitem__(self, item): # type: ignore 

66 return cls 

67 

68 def __call__(self, *args, **kargs): 

69 # type: (*Any, **Any) -> Any 

70 if isinstance(args[0], str): 

71 self.name = args[0] 

72 return self 

73 

74 def __repr__(self): 

75 # type: () -> str 

76 return "<Fake typing.%s>" % self.name 

77 return _FT(name) 

78 

79 

80# Python 3.8 Only 

81if sys.version_info >= (3, 8): 

82 from typing import Literal 

83 from typing import Protocol 

84else: 

85 Literal = _FakeType("Literal") 

86 

87 class Protocol: 

88 pass 

89 

90 

91# Python 3.9 Only 

92if sys.version_info >= (3, 9): 

93 from collections import UserDict 

94else: 

95 from collections import UserDict as _UserDict 

96 UserDict = _FakeType("_UserDict", _UserDict) 

97 

98 

99# Python 3.11 Only 

100if sys.version_info >= (3, 11): 

101 from typing import Self 

102else: 

103 Self = _FakeType("Self") 

104 

105 

106# Python 3.11 Only 

107if sys.version_info >= (3, 11): 

108 from enum import StrEnum 

109else: 

110 class StrEnum(str, enum.Enum): 

111 pass 

112 

113 

114########### 

115# Python3 # 

116########### 

117 

118# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators 

119DecoratorCallable = TypeVar("DecoratorCallable", bound=Callable[..., Any]) 

120 

121 

122# This is ugly, but we don't want to move raw() out of compat.py 

123# and it makes it much clearer 

124if TYPE_CHECKING: 

125 from scapy.packet import Packet 

126 

127 

128def raw(x): 

129 # type: (Packet) -> bytes 

130 """ 

131 Builds a packet and returns its bytes representation. 

132 This function is and will always be cross-version compatible 

133 """ 

134 return bytes(x) 

135 

136 

137def bytes_encode(x): 

138 # type: (Any) -> bytes 

139 """Ensure that the given object is bytes. If the parameter is a 

140 packet, raw() should be preferred. 

141 

142 """ 

143 if isinstance(x, str): 

144 return x.encode() 

145 return bytes(x) 

146 

147 

148def plain_str(x): 

149 # type: (Any) -> str 

150 """Convert basic byte objects to str""" 

151 if isinstance(x, bytes): 

152 return x.decode(errors="backslashreplace") 

153 return str(x) 

154 

155 

156def chb(x): 

157 # type: (int) -> bytes 

158 """Same than chr() but encode as bytes.""" 

159 return struct.pack("!B", x) 

160 

161 

162def orb(x): 

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

164 """Return ord(x) when not already an int.""" 

165 if isinstance(x, int): 

166 return x 

167 return ord(x) 

168 

169 

170def bytes_hex(x): 

171 # type: (AnyStr) -> bytes 

172 """Hexify a str or a bytes object""" 

173 return binascii.b2a_hex(bytes_encode(x)) 

174 

175 

176def hex_bytes(x): 

177 # type: (AnyStr) -> bytes 

178 """De-hexify a str or a byte object""" 

179 return binascii.a2b_hex(bytes_encode(x)) 

180 

181 

182def int_bytes(x, size): 

183 # type: (int, int) -> bytes 

184 """Convert an int to an arbitrary sized bytes string""" 

185 return x.to_bytes(size, byteorder='big') 

186 

187 

188def bytes_int(x): 

189 # type: (bytes) -> int 

190 """Convert an arbitrary sized bytes string to an int""" 

191 return int.from_bytes(x, "big") 

192 

193 

194def base64_bytes(x): 

195 # type: (AnyStr) -> bytes 

196 """Turn base64 into bytes""" 

197 return base64.decodebytes(bytes_encode(x)) 

198 

199 

200def bytes_base64(x): 

201 # type: (AnyStr) -> bytes 

202 """Turn bytes into base64""" 

203 return base64.encodebytes(bytes_encode(x)).replace(b'\n', b'')