3333except ImportError :
3434 pathlib = None
3535
36+ PY2 = sys .version_info [0 ] == 2
37+ PY3 = sys .version_info [0 ] == 3
38+
3639__all__ = (
3740 'BTFailure' ,
3841 'BencodeDecodeError' ,
@@ -62,8 +65,7 @@ def decode_int(x, f):
6265
6366def decode_string (x , f ):
6467 # 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."""
6769 colon = x .index (b':' , f )
6870 n = int (x [f :colon ])
6971
@@ -87,17 +89,6 @@ def decode_list(x, f):
8789 return r , f + 1
8890
8991
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-
10192def decode_dict (x , f , force_sort = True ):
10293 # type: (bytes, int, bool) -> Tuple[OrderedDict[str, Any], int]
10394 """Decode bencoded data to an OrderedDict.
@@ -140,11 +131,7 @@ def decode_dict(x, f, force_sort=True):
140131decode_func [b'7' ] = decode_string
141132decode_func [b'8' ] = decode_string
142133decode_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
148135
149136
150137def bdecode (value ):
@@ -159,14 +146,14 @@ def bdecode(value):
159146 :rtype: object
160147 """
161148 try :
162- r , l = decode_func [value [0 :1 ]](value , 0 )
149+ data , length = decode_func [value [0 :1 ]](value , 0 )
163150 except (IndexError , KeyError , TypeError , ValueError ):
164151 raise BencodeDecodeError ("not a valid bencoded string" )
165152
166- if l != len (value ):
153+ if length != len (value ):
167154 raise BencodeDecodeError ("invalid bencoded value (data after valid prefix)" )
168155
169- return r
156+ return data
170157
171158
172159class Bencached (object ):
@@ -219,7 +206,7 @@ def encode_dict(x, r):
219206 r .append (b'd' )
220207
221208 # 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 ()]
223210 ilist .sort (key = lambda kv : kv [0 ])
224211
225212 for k , v in ilist :
@@ -229,11 +216,35 @@ def encode_dict(x, r):
229216 r .append (b'e' )
230217
231218
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+
232243# noinspection PyDictCreation
233244encode_func = {}
234245encode_func [Bencached ] = encode_bencached
235246
236- if sys . version_info [ 0 ] == 2 :
247+ if PY2 :
237248 from types import DictType , IntType , ListType , LongType , StringType , TupleType , UnicodeType
238249
239250 encode_func [DictType ] = encode_dict
@@ -307,8 +318,10 @@ def bread(fd):
307318 return bdecode (fd .read ())
308319
309320
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
312325 """Write data in bencoded form to filename, file, or file-like object.
313326
314327 if fd is bytes/string or pathlib.Path-like object, it is opened and
0 commit comments