flying-sheep / bcode Goto Github PK
View Code? Open in Web Editor NEWbencoding & -decoding library
Home Page: http://flying-sheep.github.com/bcode/
License: MIT License
bencoding & -decoding library
Home Page: http://flying-sheep.github.com/bcode/
License: MIT License
Bencoding sorts dict keys, so that the encoded forms can be compared for equality.
BytesIO doesn't have a peek method. I'm using the 1.0 version from PyPI.
(bcodeproblem)cal@curry:~/src$ python
Python 2.7.3 (default, Sep 26 2012, 21:51:14)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from bcoding import bencode, bdecode
>>> one = bdecode(b'i1e')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/cal/src/bcodeproblem/local/lib/python2.7/site-packages/bcoding.py", line 118, in bdecode
first_byte = f_or_data.peek(1)[:1]
AttributeError: '_io.BytesIO' object has no attribute 'peek'
>>> two = bdecode('3:two')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/cal/src/bcodeproblem/local/lib/python2.7/site-packages/bcoding.py", line 118, in bdecode
first_byte = f_or_data.peek(1)[:1]
AttributeError: '_io.BytesIO' object has no attribute 'peek'
yeah, …
asserts are only used here to capture misuse of internal functions, but they alter the state of the file (read individual bytes), so when they get removed, it stops working.
most likely nobody would ever encounter this, but sigh…
The bcoding package is a little hard to find, because searching for "bencode" on pypi doesn't list "bcoding" in the search results. Adding the term "bencode" to the summary, keywords, or description fields on pypi may make the package easier to find.
[mdevaev@reki(g:master) g:/]$ python2 -V
Python 2.7.5
[mdevaev@reki(g:master) g:/]$ python2 test.py
=========================================================================== test session starts ============================================================================
platform linux2 -- Python 2.7.5 -- pytest-2.4.2
collected 8 items
test.py FF...F..
================================================================================= FAILURES =================================================================================
___________________________________________________________________________ test_stream_decoding ___________________________________________________________________________
def test_stream_decoding():
with BytesIO(b'd2:hii1ee') as f:
> mapping = bdecode(f)
test.py:8:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
f_or_data = <_io.BytesIO object at 0x1e18c50>
def bdecode(f_or_data):
"""
bdecodes data by looking up the type byte,
and using it to look up the respective decoding function,
which in turn is used to return the decoded object
The parameter can be a file opened in bytes mode,
bytes or a string (the last of which will be decoded)
"""
if isinstance(f_or_data, str):
f_or_data = f_or_data.encode()
if isinstance(f_or_data, bytes):
f_or_data = BytesIO(f_or_data)
#TODO: the following like is the only one that needs readahead.
#peek returns a arbitrary amount of bytes, so we have to slice.
if f_or_data.seekable():
first_byte = f_or_data.read(1)
f_or_data.seek(-1, SEEK_CUR)
else:
first_byte = f_or_data.peek(1)[:1]
btype = TYPES.get(first_byte)
if btype is not None:
> return btype(f_or_data)
bcoding.py:126:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
f = <_io.BytesIO object at 0x1e18c50>
def _decode_dict(f):
assert_btype(f.read(1), _TYPE_DICT)
ret = {}
> key = bdecode(f)
bcoding.py:86:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
f_or_data = <_io.BytesIO object at 0x1e18c50>
def bdecode(f_or_data):
"""
bdecodes data by looking up the type byte,
and using it to look up the respective decoding function,
which in turn is used to return the decoded object
The parameter can be a file opened in bytes mode,
bytes or a string (the last of which will be decoded)
"""
if isinstance(f_or_data, str):
f_or_data = f_or_data.encode()
if isinstance(f_or_data, bytes):
f_or_data = BytesIO(f_or_data)
#TODO: the following like is the only one that needs readahead.
#peek returns a arbitrary amount of bytes, so we have to slice.
if f_or_data.seekable():
first_byte = f_or_data.read(1)
f_or_data.seek(-1, SEEK_CUR)
else:
first_byte = f_or_data.peek(1)[:1]
btype = TYPES.get(first_byte)
if btype is not None:
return btype(f_or_data)
else: #Used in dicts and lists to designate an end
> assert_btype(f_or_data.read(1), _TYPE_END)
bcoding.py:128:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
byte = '2', typ = 'e'
def assert_btype(byte, typ):
if not byte == typ:
raise TypeError(
'Tried to decode type {!r} with identifier {!r} but got identifier {!r} instead'
> .format(TYPES[typ] or 'End', typ, byte))
E TypeError: Tried to decode type 'End' with identifier 'e' but got identifier '2' instead
bcoding.py:29: TypeError
___________________________________________________________________________ test_buffer_decoding ___________________________________________________________________________
def test_buffer_decoding():
> assert bdecode(b'3:one') == 'one'
test.py:12:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
f_or_data = <_io.BytesIO object at 0x1e18f50>
def bdecode(f_or_data):
"""
bdecodes data by looking up the type byte,
and using it to look up the respective decoding function,
which in turn is used to return the decoded object
The parameter can be a file opened in bytes mode,
bytes or a string (the last of which will be decoded)
"""
if isinstance(f_or_data, str):
f_or_data = f_or_data.encode()
if isinstance(f_or_data, bytes):
f_or_data = BytesIO(f_or_data)
#TODO: the following like is the only one that needs readahead.
#peek returns a arbitrary amount of bytes, so we have to slice.
if f_or_data.seekable():
first_byte = f_or_data.read(1)
f_or_data.seek(-1, SEEK_CUR)
else:
first_byte = f_or_data.peek(1)[:1]
btype = TYPES.get(first_byte)
if btype is not None:
return btype(f_or_data)
else: #Used in dicts and lists to designate an end
> assert_btype(f_or_data.read(1), _TYPE_END)
bcoding.py:128:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
byte = '3', typ = 'e'
def assert_btype(byte, typ):
if not byte == typ:
raise TypeError(
'Tried to decode type {!r} with identifier {!r} but got identifier {!r} instead'
> .format(TYPES[typ] or 'End', typ, byte))
E TypeError: Tried to decode type 'End' with identifier 'e' but got identifier '3' instead
bcoding.py:29: TypeError
______________________________________________________________________ test_decode_incomplete_buffer _______________________________________________________________________
def test_decode_incomplete_buffer():
with raises(ValueError):
> bdecode('1:')
test.py:31:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
f_or_data = <_io.BytesIO object at 0x1ca3470>
def bdecode(f_or_data):
"""
bdecodes data by looking up the type byte,
and using it to look up the respective decoding function,
which in turn is used to return the decoded object
The parameter can be a file opened in bytes mode,
bytes or a string (the last of which will be decoded)
"""
if isinstance(f_or_data, str):
f_or_data = f_or_data.encode()
if isinstance(f_or_data, bytes):
f_or_data = BytesIO(f_or_data)
#TODO: the following like is the only one that needs readahead.
#peek returns a arbitrary amount of bytes, so we have to slice.
if f_or_data.seekable():
first_byte = f_or_data.read(1)
f_or_data.seek(-1, SEEK_CUR)
else:
first_byte = f_or_data.peek(1)[:1]
btype = TYPES.get(first_byte)
if btype is not None:
return btype(f_or_data)
else: #Used in dicts and lists to designate an end
> assert_btype(f_or_data.read(1), _TYPE_END)
bcoding.py:128:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
byte = '1', typ = 'e'
def assert_btype(byte, typ):
if not byte == typ:
raise TypeError(
'Tried to decode type {!r} with identifier {!r} but got identifier {!r} instead'
> .format(TYPES[typ] or 'End', typ, byte))
E TypeError: Tried to decode type 'End' with identifier 'e' but got identifier '1' instead
bcoding.py:29: TypeError
==================================================================== 3 failed, 5 passed in 0.03 seconds ====================================================================
have to leave now so this as a reminder
There are fields that are bytes encoded as string, like token, peer id, node id, etc. But actually they are better treated as bytes
instead of str
. And the decode of these values are just a guess. See bcoding.py#L76. It's better to handle a certain type rather than do a check of type before dealing with the data.
So, is there a way to disable the decoding?
def _decode_buffer(f):
"""
String types are normal (byte)strings
starting with an integer followed by ':'
which designates the string’s length.
Since there’s no way to specify the byte type
in bencoded files, we have to guess
"""
strlen = int(_readuntil(f, _TYPE_SEP))
buf = f.read(strlen)
if not len(buf) == strlen:
raise ValueError(
'string expected to be {} bytes long but the file ended after {} bytes'
.format(strlen, len(buf)))
try:
return buf.decode()
except UnicodeDecodeError:
return buf
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.