@@ -0,0 +1,2121 @@
+# -*- coding: utf-8 -*-%0A%0Afrom io import BufferedReader, BytesIO%0A%0A%0Adef loads(data):%0A    if not isinstance(data, bytes):%0A        raise ValueError('loads expects bytes')%0A    return load(BufferedReader(BytesIO(data)))%0A%0A%0Adef load(stream):%0A    obj = decode(stream)%0A    if stream.read(1):%0A        raise ValueError('Unexpected data')%0A    return obj%0A%0A%0Adef decode(stream):%0A    %22%22%22Expects a binary stream.%22%22%22%0A    token = stream.peek(1)%5B:1%5D%0A    if not token:%0A        raise ValueError('Unexpected end of stream')%0A    if token == b'i':%0A        stream.read(1)%0A        return read_int(stream, b'e')%0A    elif token == b'l':%0A        stream.read(1)%0A        return read_list(stream)%0A    elif token == b'd':%0A        stream.read(1)%0A        return read_dict(stream)%0A    else:%0A        str_length = read_int(stream, b':')%0A        data = stream.read(str_length)%0A        if len(data) != str_length:%0A            raise ValueError('Unexpected end of stream')%0A        return data%0A%0A%0Adef read_list(stream):%0A    l = %5B%5D%0A    while True:%0A        if read_terminator(stream, b'e'):%0A            break%0A        val = decode(stream)%0A        l.append(val)%0A    return l%0A%0A%0Adef read_dict(stream):%0A    d = %7B%7D%0A    while True:%0A        if read_terminator(stream, b'e'):%0A            break%0A        key = decode(stream)%0A        if not isinstance(key, bytes):%0A            raise ValueError('Expected string key')%0A        val = decode(stream)%0A        d%5Bkey%5D = val%0A    return d%0A%0A%0Adef read_terminator(stream, term):%0A    ch = stream.peek(1)%5B:1%5D%0A    if not ch:%0A        raise ValueError('Expected terminator')%0A    if ch == term:%0A        stream.read(1)%0A        return True%0A    return False%0A%0A%0Adef read_int(stream, term):%0A    buf = BytesIO()%0A    while True:%0A        ch = stream.read(1)%0A        if not ch:%0A            raise ValueError('Unexpected end of stream')%0A        elif ch == term:%0A            break%0A        elif ch.isdigit():%0A            buf.write(ch)%0A        else:%0A            raise ValueError('Unexpected token: ' + repr(ch))%0A    data = buf.getvalue()%0A    if data.startswith(b'0') and data != b'0':%0A        raise ValueError('Leading zeros are not allowed')%0A    return int(data)%0A

Add bencode decoding