Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/netaddr/strategy/__init__.py: 19%

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

113 statements  

1# ----------------------------------------------------------------------------- 

2# Copyright (c) 2008 by David P. D. Moss. All rights reserved. 

3# 

4# Released under the BSD license. See the LICENSE file for details. 

5# ----------------------------------------------------------------------------- 

6""" 

7Shared logic for various address types. 

8""" 

9import re as _re 

10 

11 

12def bytes_to_bits(): 

13 """ 

14 :return: A 256 element list containing 8-bit binary digit strings. The 

15 list index value is equivalent to its bit string value. 

16 """ 

17 lookup = [] 

18 bits_per_byte = range(7, -1, -1) 

19 for num in range(256): 

20 bits = 8 * [None] 

21 for i in bits_per_byte: 

22 bits[i] = '01'[num & 1] 

23 num >>= 1 

24 lookup.append(''.join(bits)) 

25 return lookup 

26 

27 

28#: A lookup table of 8-bit integer values to their binary digit bit strings. 

29BYTES_TO_BITS = bytes_to_bits() 

30 

31 

32def valid_words(words, word_size, num_words): 

33 """ 

34 :param words: A sequence of unsigned integer word values. 

35 

36 :param word_size: Width (in bits) of each unsigned integer word value. 

37 

38 :param num_words: Number of unsigned integer words expected. 

39 

40 :return: ``True`` if word sequence is valid for this address type, 

41 ``False`` otherwise. 

42 """ 

43 if not hasattr(words, '__iter__'): 

44 return False 

45 

46 if len(words) != num_words: 

47 return False 

48 

49 max_word = 2**word_size - 1 

50 

51 for i in words: 

52 if not 0 <= i <= max_word: 

53 return False 

54 

55 return True 

56 

57 

58def int_to_words(int_val, word_size, num_words): 

59 """ 

60 :param int_val: Unsigned integer to be divided into words of equal size. 

61 

62 :param word_size: Width (in bits) of each unsigned integer word value. 

63 

64 :param num_words: Number of unsigned integer words expected. 

65 

66 :return: A tuple contain unsigned integer word values split according 

67 to provided arguments. 

68 """ 

69 max_int = 2 ** (num_words * word_size) - 1 

70 

71 if not 0 <= int_val <= max_int: 

72 raise IndexError('integer out of bounds: %r!' % hex(int_val)) 

73 

74 max_word = 2**word_size - 1 

75 

76 words = [] 

77 for _ in range(num_words): 

78 word = int_val & max_word 

79 words.append(int(word)) 

80 int_val >>= word_size 

81 

82 return tuple(reversed(words)) 

83 

84 

85def words_to_int(words, word_size, num_words): 

86 """ 

87 :param words: A sequence of unsigned integer word values. 

88 

89 :param word_size: Width (in bits) of each unsigned integer word value. 

90 

91 :param num_words: Number of unsigned integer words expected. 

92 

93 :return: An unsigned integer that is equivalent to value represented 

94 by word sequence. 

95 """ 

96 if not valid_words(words, word_size, num_words): 

97 raise ValueError('invalid integer word sequence: %r!' % (words,)) 

98 

99 int_val = 0 

100 for i, num in enumerate(reversed(words)): 

101 word = num 

102 word = word << word_size * i 

103 int_val = int_val | word 

104 

105 return int_val 

106 

107 

108def valid_bits(bits, width, word_sep=''): 

109 """ 

110 :param bits: A network address in a delimited binary string format. 

111 

112 :param width: Maximum width (in bits) of a network address (excluding 

113 delimiters). 

114 

115 :param word_sep: (optional) character or string used to delimit word 

116 groups (default: '', no separator). 

117 

118 :return: ``True`` if network address is valid, ``False`` otherwise. 

119 """ 

120 if not isinstance(bits, str): 

121 return False 

122 

123 if word_sep != '': 

124 bits = bits.replace(word_sep, '') 

125 

126 if len(bits) != width: 

127 return False 

128 

129 max_int = 2**width - 1 

130 

131 try: 

132 if 0 <= int(bits, 2) <= max_int: 

133 return True 

134 except ValueError: 

135 pass 

136 

137 return False 

138 

139 

140def bits_to_int(bits, width, word_sep=''): 

141 """ 

142 :param bits: A network address in a delimited binary string format. 

143 

144 :param width: Maximum width (in bits) of a network address (excluding 

145 delimiters). 

146 

147 :param word_sep: (optional) character or string used to delimit word 

148 groups (default: '', no separator). 

149 

150 :return: An unsigned integer that is equivalent to value represented 

151 by network address in readable binary form. 

152 """ 

153 if not valid_bits(bits, width, word_sep): 

154 raise ValueError('invalid readable binary string: %r!' % (bits,)) 

155 

156 if word_sep != '': 

157 bits = bits.replace(word_sep, '') 

158 

159 return int(bits, 2) 

160 

161 

162def int_to_bits(int_val, word_size, num_words, word_sep=''): 

163 """ 

164 :param int_val: An unsigned integer. 

165 

166 :param word_size: Width (in bits) of each unsigned integer word value. 

167 

168 :param num_words: Number of unsigned integer words expected. 

169 

170 :param word_sep: (optional) character or string used to delimit word 

171 groups (default: '', no separator). 

172 

173 :return: A network address in a delimited binary string format that is 

174 equivalent in value to unsigned integer. 

175 """ 

176 bit_words = [] 

177 

178 for word in int_to_words(int_val, word_size, num_words): 

179 bits = [] 

180 while word: 

181 bits.append(BYTES_TO_BITS[word & 255]) 

182 word >>= 8 

183 bits.reverse() 

184 bit_str = ''.join(bits) or '0' * word_size 

185 bits = ('0' * word_size + bit_str)[-word_size:] 

186 bit_words.append(bits) 

187 

188 if word_sep != '': 

189 # Check custom separator. 

190 if not isinstance(word_sep, str): 

191 raise ValueError('word separator is not a string: %r!' % (word_sep,)) 

192 

193 return word_sep.join(bit_words) 

194 

195 

196def valid_bin(bin_val, width): 

197 """ 

198 :param bin_val: A network address in Python's binary representation format 

199 ('0bxxx'). 

200 

201 :param width: Maximum width (in bits) of a network address (excluding 

202 delimiters). 

203 

204 :return: ``True`` if network address is valid, ``False`` otherwise. 

205 """ 

206 if not isinstance(bin_val, str): 

207 return False 

208 

209 if not bin_val.startswith('0b'): 

210 return False 

211 

212 bin_val = bin_val.replace('0b', '') 

213 

214 if len(bin_val) > width: 

215 return False 

216 

217 max_int = 2**width - 1 

218 

219 try: 

220 if 0 <= int(bin_val, 2) <= max_int: 

221 return True 

222 except ValueError: 

223 pass 

224 

225 return False 

226 

227 

228def int_to_bin(int_val, width): 

229 """ 

230 :param int_val: An unsigned integer. 

231 

232 :param width: Maximum allowed width (in bits) of a unsigned integer. 

233 

234 :return: Equivalent string value in Python's binary representation format 

235 ('0bxxx'). 

236 """ 

237 bin_tokens = [] 

238 

239 try: 

240 # Python 2.6.x and upwards. 

241 bin_val = bin(int_val) 

242 except NameError: 

243 # Python 2.4.x and 2.5.x 

244 i = int_val 

245 while i > 0: 

246 word = i & 0xFF 

247 bin_tokens.append(BYTES_TO_BITS[word]) 

248 i >>= 8 

249 

250 bin_tokens.reverse() 

251 bin_val = '0b' + _re.sub(r'^[0]+([01]+)$', r'\1', ''.join(bin_tokens)) 

252 

253 if len(bin_val[2:]) > width: 

254 raise IndexError('binary string out of bounds: %s!' % (bin_val,)) 

255 

256 return bin_val 

257 

258 

259def bin_to_int(bin_val, width): 

260 """ 

261 :param bin_val: A string containing an unsigned integer in Python's binary 

262 representation format ('0bxxx'). 

263 

264 :param width: Maximum allowed width (in bits) of a unsigned integer. 

265 

266 :return: An unsigned integer that is equivalent to value represented 

267 by Python binary string format. 

268 """ 

269 if not valid_bin(bin_val, width): 

270 raise ValueError('not a valid Python binary string: %r!' % (bin_val,)) 

271 

272 return int(bin_val.replace('0b', ''), 2)