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

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

66 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) 

23 

24# Very important: will issue typing errors otherwise 

25__all__ = [ 

26 # typing 

27 'DecoratorCallable', 

28 'Literal', 

29 'Protocol', 

30 'Self', 

31 'UserDict', 

32 # compat 

33 'base64_bytes', 

34 'bytes_base64', 

35 'bytes_encode', 

36 'bytes_hex', 

37 'chb', 

38 'hex_bytes', 

39 'plain_str', 

40 'raw', 

41 'StrEnum', 

42] 

43 

44# Typing compatibility 

45 

46# Note: 

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

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

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

50# ones. 

51 

52 

53# Import or create fake types 

54 

55def _FakeType(name, cls=object): 

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

57 class _FT(object): 

58 def __init__(self, name): 

59 # type: (str) -> None 

60 self.name = name 

61 

62 # make the objects subscriptable indefinitely 

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

64 return cls 

65 

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

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

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

69 self.name = args[0] 

70 return self 

71 

72 def __repr__(self): 

73 # type: () -> str 

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

75 return _FT(name) 

76 

77 

78# Python 3.8 Only 

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

80 from typing import Literal 

81 from typing import Protocol 

82else: 

83 Literal = _FakeType("Literal") 

84 

85 class Protocol: 

86 pass 

87 

88 

89# Python 3.9 Only 

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

91 from collections import UserDict 

92else: 

93 from collections import UserDict as _UserDict 

94 UserDict = _FakeType("_UserDict", _UserDict) 

95 

96 

97# Python 3.11 Only 

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

99 from typing import Self 

100else: 

101 Self = _FakeType("Self") 

102 

103 

104# Python 3.11 Only 

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

106 from enum import StrEnum 

107else: 

108 class StrEnum(str, enum.Enum): 

109 pass 

110 

111 

112########### 

113# Python3 # 

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

115 

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

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

118 

119 

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

121# and it makes it much clearer 

122if TYPE_CHECKING: 

123 from scapy.packet import Packet 

124 

125 

126def raw(x): 

127 # type: (Packet) -> bytes 

128 """ 

129 Builds a packet and returns its bytes representation. 

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

131 """ 

132 return bytes(x) 

133 

134 

135def bytes_encode(x): 

136 # type: (Any) -> bytes 

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

138 packet, raw() should be preferred. 

139 

140 """ 

141 if isinstance(x, str): 

142 return x.encode() 

143 return bytes(x) 

144 

145 

146def plain_str(x): 

147 # type: (Any) -> str 

148 """Convert basic byte objects to str""" 

149 if isinstance(x, bytes): 

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

151 return str(x) 

152 

153 

154def chb(x): 

155 # type: (int) -> bytes 

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

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

158 

159 

160def bytes_hex(x): 

161 # type: (AnyStr) -> bytes 

162 """Hexify a str or a bytes object""" 

163 return binascii.b2a_hex(bytes_encode(x)) 

164 

165 

166def hex_bytes(x): 

167 # type: (AnyStr) -> bytes 

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

169 return binascii.a2b_hex(bytes_encode(x)) 

170 

171 

172def int_bytes(x, size): 

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

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

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

176 

177 

178def bytes_int(x): 

179 # type: (bytes) -> int 

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

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

182 

183 

184def base64_bytes(x): 

185 # type: (AnyStr) -> bytes 

186 """Turn base64 into bytes""" 

187 return base64.decodebytes(bytes_encode(x)) 

188 

189 

190def bytes_base64(x): 

191 # type: (AnyStr) -> bytes 

192 """Turn bytes into base64""" 

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