Skip to content

Commit b81189e

Browse files
committed
use ordered dict to ensure sorted order
1 parent e2c30a6 commit b81189e

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

bencode/__init__.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
"""bencode.py - bencode encoder + decoder."""
1414

15-
from collections import deque
15+
from collections import deque, OrderedDict
1616

1717
from bencode.BTL import BTFailure
1818
from bencode.exceptions import BencodeDecodeError
@@ -86,13 +86,30 @@ def decode_list(x, f):
8686
return r, f + 1
8787

8888

89-
def decode_dict(x, f):
90-
r, f = {}, f + 1
89+
def decode_dict(x, f, force_sort=True):
90+
"""
91+
decode bencoded data to an OrderedDict
92+
93+
The BitTorrent standard states that:
94+
Keys must be strings and appear in sorted order (sorted as raw
95+
strings, not alphanumerics)
96+
- http://www.bittorrent.org/beps/bep_0003.html
97+
98+
Therefore, this function will force the keys to be strings (decoded
99+
from utf-8), and by default the keys are (re)sorted after reading.
100+
Set force_sort to False to keep the order of the dictionary as
101+
represented in x, as many other encoders and decoders do not force this
102+
property.
103+
"""
104+
r, f = OrderedDict(), f + 1
91105

92106
while x[f : f+1] != b'e':
93107
k, f = decode_string(x, f, force_decode_utf8=True)
94108
r[k], f = decode_func[x[f : f+1]](x, f)
95109

110+
if force_sort:
111+
r = OrderedDict(sorted(r.items()))
112+
96113
return r, f + 1
97114

98115

@@ -209,6 +226,7 @@ def encode_dict(x, r):
209226
else:
210227
encode_func[bool] = encode_bool
211228
encode_func[dict] = encode_dict
229+
encode_func[OrderedDict] = encode_dict
212230
encode_func[int] = encode_int
213231
encode_func[list] = encode_list
214232
encode_func[str] = encode_string

tests/bencode_tests.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
"""bencode.py tests."""
55

6+
from collections import OrderedDict
7+
68
from bencode import BTFailure, bencode, bdecode
79

810
import unittest
@@ -31,6 +33,10 @@ class KnownValues(unittest.TestCase):
3133
'foo': 42,
3234
'bar': 'spam'
3335
}, 'd3:bar4:spam3:fooi42ee'.encode('utf-8')),
36+
(OrderedDict((
37+
('bar', 'spam'),
38+
('foo', 42)
39+
)), 'd3:bar4:spam3:fooi42ee'.encode('utf-8')),
3440
)
3541

3642
def testBencodeKnownValues(self):

0 commit comments

Comments
 (0)