Skip to content

Commit 6d0d462

Browse files
committed
Merge branch 'develop'
2 parents 4e28384 + 9914c3b commit 6d0d462

File tree

12 files changed

+170
-104
lines changed

12 files changed

+170
-104
lines changed

MANIFEST.in

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
include bencoder.c bencoder.pyx README.rst pytest.ini LICENSE
2-
recursive-include tests *
1+
include bencoder.pyx README.rst LICENSE
2+
global-exclude *.pyc __pycache__
3+
recursive-include tests *.py *.torrent

README.rst

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ Bencoder.pyx
33

44
A fast bencode implementation in Cython supports both Python2 & Python3 .
55

6-
.. image:: https://img.shields.io/travis/whtsky/bencoder.pyx/master.svg?maxAge=3600&label=macOS
6+
.. image:: https://img.shields.io/travis/whtsky/bencoder.pyx/develop.svg?maxAge=3600&label=macOS
77
:target: https://travis-ci.org/whtsky/bencoder.pyx
8-
.. image:: https://img.shields.io/appveyor/ci/whtsky/bencoder-pyx/master.svg?maxAge=3600&label=Windows
8+
.. image:: https://img.shields.io/appveyor/ci/whtsky/bencoder-pyx/develop.svg?maxAge=3600&label=Windows
99
:target: https://ci.appveyor.com/project/whtsky/bencoder-pyx
10-
.. image:: https://semaphoreci.com/api/v1/whtsky/bencoder-pyx/branches/master/shields_badge.svg
10+
.. image:: https://semaphoreci.com/api/v1/whtsky/bencoder-pyx/branches/develop/shields_badge.svg
1111
:target: https://semaphoreci.com/whtsky/bencoder-pyx
1212

13-
14-
.. image:: https://img.shields.io/travis/whtsky/bencoder.pyx/master.svg?maxAge=3600&label=wheels
13+
.. image:: https://img.shields.io/travis/whtsky/bencoder.pyx/develop.svg?maxAge=3600&label=wheels
1514
:target: https://travis-ci.org/whtsky/bencoder.pyx
16-
.. image:: https://codecov.io/gh/whtsky/bencoder.pyx/branch/master/graph/badge.svg
15+
.. image:: https://codecov.io/gh/whtsky/bencoder.pyx/branch/develop/graph/badge.svg
1716
:target: https://codecov.io/gh/whtsky/bencoder.pyx
1817

1918
Install
@@ -43,6 +42,12 @@ Usage
4342
ChangeLog
4443
----------
4544

45+
Version 1.1.3
46+
~~~~~~~~~~~~~~~
47+
48+
+ Performance Improvement
49+
+ Fix package metainfo ` #3 <https://github.com/whtsky/bencoder.pyx/issues/3>`_
50+
4651
Version 1.1.2
4752
~~~~~~~~~~~~~~~
4853

appveyor.yml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,39 @@ cache:
44
environment:
55
PYPI_PASSWD:
66
secure: pp1j5lAB9NN8ZDasgY+oxoGrNw0+4gGzbNZmHVwJkCzUyrNBP5ZIuCrwjmx4q6ifg7RMiE3bVt9MljFCJh3XpsvVOAcx+AGKsHSjtXd40HM=
7+
8+
matrix:
9+
- PYTHON: "C:\\Python26"
10+
- PYTHON: "C:\\Python26-x64"
11+
- PYTHON: "C:\\Python27"
12+
- PYTHON: "C:\\Python27-x64"
13+
- PYTHON: "C:\\Python33"
14+
- PYTHON: "C:\\Python33-x64"
15+
- PYTHON: "C:\\Python34"
16+
- PYTHON: "C:\\Python34-x64"
17+
- PYTHON: "C:\\Python35"
18+
- PYTHON: "C:\\Python35-x64"
19+
720
init:
821
- ps: "ls C:/Python*"
922

1023
install:
11-
- choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1)
12-
- SET PATH=C:\Python35;C:\Python35\scripts;C:\tools\pypy\pypy;%PATH%
24+
- SET PATH=%PYTHON%;%PYTHON%\scripts;%PATH%
1325
- echo "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 > "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64\vcvars64.bat"
1426
- pip install -r dev-requirements.txt
1527

1628
build: off
1729

1830
test_script:
19-
- tox
31+
- pip install --upgrade --user pip setuptools
32+
- pip install codecov
33+
- python setup.py test
34+
- codecov --required
2035

2136
after_test:
22-
- pip install codecov
23-
- codecov
2437
- del bencoder.c
25-
- tox -c tox-wheels.ini
38+
- pip install wheel
39+
- pip wheel . -w wheelhouse/
2640
- ps: "ls wheelhouse/*"
2741

2842
deploy_script:

bencoder.pyx

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,23 @@
1212

1313
# Based on https://github.com/karamanolev/bencode3/blob/master/bencode.py
1414

15-
__version__ = '1.1.2'
15+
__version__ = '1.1.3'
1616

17-
import sys
18-
IS_PY2 = sys.version[0] == '2'
17+
import array
1918

2019
try:
2120
from collections import OrderedDict
2221
except ImportError:
2322
from ordereddict import OrderedDict
2423

24+
from cpython.version cimport PY_MAJOR_VERSION
25+
IS_PY2 = PY_MAJOR_VERSION == 2
2526
if IS_PY2:
2627
END_CHAR = 'e'
28+
ARRAY_TYPECODE = b'b'
2729
else:
2830
END_CHAR = ord('e')
31+
ARRAY_TYPECODE = 'b'
2932

3033

3134
class BTFailure(Exception):
@@ -34,7 +37,7 @@ class BTFailure(Exception):
3437

3538
def decode_int(bytes x, int f):
3639
f += 1
37-
new_f = x.index(b'e', f)
40+
cdef long new_f = x.index(b'e', f)
3841
n = int(x[f:new_f])
3942
if x[f] == b'-'[0]:
4043
if x[f + 1] == b'0'[0]:
@@ -45,8 +48,8 @@ def decode_int(bytes x, int f):
4548

4649

4750
def decode_string(bytes x, int f):
48-
colon = x.index(b':', f)
49-
n = int(x[f:colon])
51+
cdef long colon = x.index(b':', f)
52+
cdef long n = int(x[f:colon])
5053
if x[f] == b'0'[0] and colon != f + 1:
5154
raise ValueError()
5255
colon += 1
@@ -62,7 +65,8 @@ def decode_list(bytes x, int f):
6265

6366

6467
def decode_dict(bytes x, int f):
65-
r, f = OrderedDict(), f + 1
68+
r = OrderedDict()
69+
f += 1
6670
while x[f] != END_CHAR:
6771
k, f = decode_string(x, f)
6872
r[k], f = decode_func[x[f]](x, f)
@@ -107,56 +111,63 @@ def encode(v, r):
107111
)
108112

109113

110-
def encode_int(x, list r):
111-
r.extend((b'i', str(x).encode(), b'e'))
114+
def encode_int(long x, r):
115+
r.fromstring(b'i')
116+
r.fromstring(str(x).encode())
117+
r.fromstring(b'e')
112118

113119

114-
def encode_bool(x, list r):
115-
if x:
116-
encode_int(1, r)
117-
else:
118-
encode_int(0, r)
120+
def encode_long(x, r):
121+
r.fromstring(b'i')
122+
r.fromstring(str(x).encode())
123+
r.fromstring(b'e')
124+
125+
126+
def encode_bytes(bytes x, r):
127+
r.fromstring(str(len(x)).encode())
128+
r.fromstring(b':')
129+
r.fromstring(x)
119130

120131

121-
def encode_string(x, list r):
122-
if isinstance(x, str):
123-
x = x.encode()
124-
r.extend((str(len(x)).encode(), b':', x))
132+
def encode_string(str x, r):
133+
r.fromstring(str(len(x)).encode())
134+
r.fromstring(b':')
135+
r.fromstring(x.encode())
125136

126137

127-
def encode_list(x, list r):
128-
r.append(b'l')
138+
def encode_list(x, r):
139+
r.fromstring(b'l')
129140
for i in x:
130141
encode(i, r)
131-
r.append(b'e')
142+
r.fromstring(b'e')
132143

133144

134-
def encode_dict(x, list r):
135-
r.append(b'd')
145+
def encode_dict(x, r):
146+
r.fromstring(b'd')
136147
item_list = list(x.items())
137148
item_list.sort()
138149
for k, v in item_list:
139150
if isinstance(k, str):
140151
k = k.encode()
141-
r.extend((str(len(k)).encode(), b':', k))
152+
encode_bytes(k, r)
142153
encode(v, r)
143-
r.append(b'e')
154+
r.fromstring(b'e')
144155

145156

146157
encode_func = {
147158
int: encode_int,
148-
long: encode_int,
149-
bytes: encode_string,
159+
bool: encode_int,
160+
long: encode_long,
161+
bytes: encode_bytes,
150162
str: encode_string,
151163
list: encode_list,
152164
tuple: encode_list,
153165
dict: encode_dict,
154166
OrderedDict: encode_dict,
155-
bool: encode_bool,
156167
}
157168

158169

159170
def bencode(x):
160-
r = []
171+
r = array.array(ARRAY_TYPECODE)
161172
encode(x, r)
162-
return b''.join(r)
173+
return r.tostring()

ci/build-wheels.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ cp /tmp/wheelhouse/ordereddict* /io/wheelhouse
1919
# Install packages and test again
2020
for PYBIN in /opt/python/*/bin/; do
2121
${PYBIN}/pip install bencoder.pyx --no-index -f /io/wheelhouse
22-
${PYBIN}/pip install pytest
22+
${PYBIN}/pip install pytest pytest-benchmark
2323
(cd /io; ${PYBIN}/py.test)
2424
done

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pytest
2+
pytest-benchmark
23
coverage
34
cython
45
tox

pytest.ini

Lines changed: 0 additions & 3 deletions
This file was deleted.

setup.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
[bdist_wheel]
2+
3+
[pytest]
4+
testpaths = tests
5+
addopts = -rw

setup.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,42 @@
1111
if version < ('2', '7'):
1212
install_requires.append('ordereddict>=1.1')
1313

14-
base_path = os.path.dirname(os.path.abspath(__file__))
15-
pyx_path = os.path.join(base_path, 'bencoder.pyx')
16-
c_path = os.path.join(base_path, 'bencoder.c')
14+
pyx_path = 'bencoder.pyx'
15+
c_path = 'bencoder.c'
1716

18-
if 'test' in sys.argv and platform.python_implementation() == 'CPython':
17+
try:
18+
import Cython
19+
HAVE_CYTHON = True
20+
except ImportError:
21+
HAVE_CYTHON = False
22+
23+
if HAVE_CYTHON:
1924
if os.path.exists(c_path):
2025
# Remove C file to force Cython recompile.
2126
os.remove(c_path)
22-
from Cython.Compiler.Options import directive_defaults
23-
24-
directive_defaults['linetrace'] = True
25-
directive_defaults['binding'] = True
26-
27-
from Cython.Build import cythonize
28-
ext_modules = cythonize(Extension(
29-
"bencoder",
30-
[pyx_path],
31-
define_macros=[('CYTHON_TRACE', '1')]
32-
))
33-
elif os.path.exists(c_path):
27+
if 'test' in sys.argv and platform.python_implementation() == 'CPython':
28+
from Cython.Compiler.Options import directive_defaults
29+
30+
directive_defaults['linetrace'] = True
31+
directive_defaults['binding'] = True
32+
33+
from Cython.Build import cythonize
34+
ext_modules = cythonize(Extension(
35+
"bencoder",
36+
[pyx_path],
37+
define_macros=[('CYTHON_TRACE', '1')]
38+
))
39+
else:
40+
from Cython.Build import cythonize
41+
ext_modules = cythonize(Extension(
42+
"bencoder",
43+
[pyx_path]
44+
))
45+
else:
3446
ext_modules = [Extension(
3547
'bencoder',
3648
[c_path]
3749
)]
38-
else:
39-
from Cython.Build import cythonize
40-
ext_modules = cythonize(Extension(
41-
"bencoder",
42-
[pyx_path]
43-
))
4450

4551

4652
class PyTest(TestCommand):
@@ -93,7 +99,7 @@ def get_tag(self):
9399

94100
setup(
95101
name='bencoder.pyx',
96-
version='1.1.2',
102+
version='1.1.3',
97103
description='Yet another bencode implementation in Cython',
98104
long_description=open('README.rst', 'r').read(),
99105
author='whtsky',
@@ -121,12 +127,12 @@ def get_tag(self):
121127
'Programming Language :: Python :: 3.5',
122128
'Programming Language :: Python :: Implementation :: CPython',
123129
'Programming Language :: Python :: Implementation :: PyPy',
130+
'Intended Audience :: Developers',
131+
'Topic :: Software Development :: Libraries',
124132
'Topic :: Software Development :: Libraries :: Python Modules',
133+
'Topic :: Utilities',
125134
],
126135
ext_modules=ext_modules,
127136
install_requires=install_requires,
128-
setup_requires=[
129-
'pytest-runner',
130-
],
131137
tests_require=['cython', 'pytest', 'coverage'],
132138
)

tests/test_decode.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,37 @@
1010
)
1111

1212

13-
def test_decode_str():
14-
assert bdecode(b'6:WWWWWW') == b"WWWWWW"
13+
def test_decode_str(benchmark):
14+
assert benchmark(bdecode, b'6:WWWWWW') == b"WWWWWW"
1515

1616

17-
def test_decode_int():
18-
assert bdecode(b'i233e') == 233
17+
def test_decode_int(benchmark):
18+
assert benchmark(bdecode, b'i233e') == 233
1919

2020

21-
def test_decode_large_int():
21+
def test_decode_large_int(benchmark):
2222
assert bdecode(b'i1455189890e') == 1455189890
2323
assert bdecode(b'i25735241490e') == 25735241490
24-
assert bdecode(('i%de' % sys.maxsize).encode()) == sys.maxsize
2524

25+
MAX_SIZE = sys.maxsize + 1
26+
BENCODED_MAXSIZE = ('i%de' % MAX_SIZE).encode()
27+
assert benchmark(bdecode, BENCODED_MAXSIZE) == MAX_SIZE
2628

27-
def test_decode_list():
28-
assert bdecode(b'l1:a1:bi3ee') == [b'a', b'b', 3]
2929

30+
def test_decode_list(benchmark):
31+
assert benchmark(bdecode, b'l1:a1:bi3ee') == [b'a', b'b', 3]
3032

31-
def test_decode_dict():
33+
34+
def test_decode_dict(benchmark):
3235
od = dict()
3336
od[b'ka'] = b'va'
3437
od[b'kb'] = 2
35-
assert bdecode(b'd2:ka2:va2:kbi2ee') == od
38+
assert benchmark(bdecode, b'd2:ka2:va2:kbi2ee') == od
3639

3740

38-
def test_ordered_dict():
41+
def test_ordered_dict(benchmark):
3942
from bencoder import OrderedDict
40-
rv = bdecode(b'd2:ka2:va2:kbi2ee')
43+
rv = benchmark(bdecode, b'd2:ka2:va2:kbi2ee')
4144
assert isinstance(rv, OrderedDict)
4245
assert list(rv.keys()) == [b'ka', b'kb']
4346
assert list(bdecode(b'd2:kc2:va2:kei2ee').keys()) == [b'kc', b'ke']

0 commit comments

Comments
 (0)