33
33
except ImportError :
34
34
pathlib = None
35
35
36
+ PY2 = sys .version_info [0 ] == 2
37
+ PY3 = sys .version_info [0 ] == 3
38
+
36
39
__all__ = (
37
40
'BTFailure' ,
38
41
'BencodeDecodeError' ,
@@ -62,8 +65,7 @@ def decode_int(x, f):
62
65
63
66
def decode_string (x , f ):
64
67
# type: (bytes, int) -> Tuple[bytes, int]
65
- """Decode torrent bencoded 'string' in x starting at f.
66
- """
68
+ """Decode torrent bencoded 'string' in x starting at f."""
67
69
colon = x .index (b':' , f )
68
70
n = int (x [f :colon ])
69
71
@@ -87,17 +89,6 @@ def decode_list(x, f):
87
89
return r , f + 1
88
90
89
91
90
- def decode_dict_py26 (x , f ):
91
- # type: (bytes, int) -> Tuple[Dict[str, Any], int]
92
- r , f = {}, f + 1
93
-
94
- while x [f ] != 'e' :
95
- k , f = decode_string (x , f )
96
- r [k ], f = decode_func [x [f ]](x , f )
97
-
98
- return r , f + 1
99
-
100
-
101
92
def decode_dict (x , f , force_sort = True ):
102
93
# type: (bytes, int, bool) -> Tuple[OrderedDict[str, Any], int]
103
94
"""Decode bencoded data to an OrderedDict.
@@ -140,11 +131,7 @@ def decode_dict(x, f, force_sort=True):
140
131
decode_func [b'7' ] = decode_string
141
132
decode_func [b'8' ] = decode_string
142
133
decode_func [b'9' ] = decode_string
143
-
144
- if sys .version_info [0 ] == 2 and sys .version_info [1 ] == 6 :
145
- decode_func [b'd' ] = decode_dict_py26
146
- else :
147
- decode_func [b'd' ] = decode_dict
134
+ decode_func [b'd' ] = decode_dict
148
135
149
136
150
137
def bdecode (value ):
@@ -159,14 +146,14 @@ def bdecode(value):
159
146
:rtype: object
160
147
"""
161
148
try :
162
- r , l = decode_func [value [0 :1 ]](value , 0 )
149
+ data , length = decode_func [value [0 :1 ]](value , 0 )
163
150
except (IndexError , KeyError , TypeError , ValueError ):
164
151
raise BencodeDecodeError ("not a valid bencoded string" )
165
152
166
- if l != len (value ):
153
+ if length != len (value ):
167
154
raise BencodeDecodeError ("invalid bencoded value (data after valid prefix)" )
168
155
169
- return r
156
+ return data
170
157
171
158
172
159
class Bencached (object ):
@@ -219,7 +206,7 @@ def encode_dict(x, r):
219
206
r .append (b'd' )
220
207
221
208
# force all keys to bytes, because str and bytes are incomparable
222
- ilist = [(k if type ( k ) == type ( b"" ) else k . encode ( "UTF-8" ), v ) for k , v in x .items ()]
209
+ ilist = [(to_binary ( k ), v ) for k , v in x .items ()]
223
210
ilist .sort (key = lambda kv : kv [0 ])
224
211
225
212
for k , v in ilist :
@@ -229,11 +216,35 @@ def encode_dict(x, r):
229
216
r .append (b'e' )
230
217
231
218
219
+ def is_binary (s ):
220
+ if PY3 :
221
+ return isinstance (s , bytes )
222
+
223
+ return isinstance (s , str )
224
+
225
+
226
+ def is_text (s ):
227
+ if PY3 :
228
+ return isinstance (s , str )
229
+
230
+ return isinstance (s , unicode ) # noqa: F821
231
+
232
+
233
+ def to_binary (s ):
234
+ if is_binary (s ):
235
+ return s
236
+
237
+ if is_text (s ):
238
+ return s .encode ('utf-8' , 'strict' )
239
+
240
+ raise TypeError ("expected binary or text (found %s)" % type (s ))
241
+
242
+
232
243
# noinspection PyDictCreation
233
244
encode_func = {}
234
245
encode_func [Bencached ] = encode_bencached
235
246
236
- if sys . version_info [ 0 ] == 2 :
247
+ if PY2 :
237
248
from types import DictType , IntType , ListType , LongType , StringType , TupleType , UnicodeType
238
249
239
250
encode_func [DictType ] = encode_dict
@@ -307,8 +318,10 @@ def bread(fd):
307
318
return bdecode (fd .read ())
308
319
309
320
310
- def bwrite (data , fd ):
311
- # type: (Union[Tuple, List, OrderedDict, Dict, bool, int, str, bytes], Union[bytes, str, pathlib.Path, pathlib.PurePath, TextIO, BinaryIO]) -> None
321
+ def bwrite (data , # type: Union[Tuple, List, OrderedDict, Dict, bool, int, str, bytes]
322
+ fd # type: Union[bytes, str, pathlib.Path, pathlib.PurePath, TextIO, BinaryIO]
323
+ ):
324
+ # type: (...) -> None
312
325
"""Write data in bencoded form to filename, file, or file-like object.
313
326
314
327
if fd is bytes/string or pathlib.Path-like object, it is opened and
0 commit comments