Skip to content

Commit

Permalink
Merge pull request #44 from dougalsutherland/py3k
Browse files Browse the repository at this point in the history
Python 3 support; closes #19.
  • Loading branch information
kwgoodman committed Apr 27, 2012
2 parents 7147ad8 + 524f269 commit 2f07774
Show file tree
Hide file tree
Showing 47 changed files with 300 additions and 291 deletions.
14 changes: 8 additions & 6 deletions Makefile
@@ -1,5 +1,7 @@
# Bottleneck Makefile

PYTHON=python

srcdir := bottleneck/src

help:
Expand All @@ -17,7 +19,7 @@ help:
all: clean pyx cfiles build test

pyx:
python -c "from bottleneck.src.makepyx import makepyx; makepyx()"
${PYTHON} -c "from bottleneck.src.makepyx import makepyx; makepyx()"

cfiles:
cython ${srcdir}/func/32bit/func.pyx
Expand All @@ -29,23 +31,23 @@ build: funcs moves

funcs:
rm -rf ${srcdir}/../func.so
python ${srcdir}/func/setup.py build_ext --inplace
${PYTHON} ${srcdir}/func/setup.py build_ext --inplace

moves:
rm -rf ${srcdir}/../move.so
python ${srcdir}/move/setup.py build_ext --inplace
${PYTHON} ${srcdir}/move/setup.py build_ext --inplace

test:
python -c "import bottleneck;bottleneck.test(extra_argv=['--processes=4'])"
${PYTHON} -c "import bottleneck;bottleneck.test(extra_argv=['--processes=4'])"

bench:
python -c "import bottleneck; bottleneck.bench()"
${PYTHON} -c "import bottleneck; bottleneck.bench()"

sdist: pyx cfiles
rm -f MANIFEST
git status
find -name *.c
python setup.py sdist
${PYTHON} setup.py sdist

# Phony targets for cleanup and similar uses

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -228,7 +228,7 @@ Install
Requirements:

======================== ====================================================
Bottleneck Python 2.5, 2.6, 2.7; NumPy 1.5.1 or 1.6.0
Bottleneck Python 2.6, 2.7, or 3.2; NumPy 1.5.1 or 1.6.0
Unit tests nose
Compile gcc or MinGW
Optional SciPy 0.8.0 or 0.9.0 (portions of benchmark)
Expand Down
1 change: 1 addition & 0 deletions RELEASE.rst
Expand Up @@ -17,6 +17,7 @@ Bottleneck 0.6.0

**Enhancements**

- Python 3 support -- only 3.2 tested, but earlier versions may work
- Upgrade numpydoc from 0.3.1 to 0.4 to support Sphinx 1.0.1

**Bug fixes**
Expand Down
9 changes: 5 additions & 4 deletions bottleneck/__init__.py
@@ -1,21 +1,22 @@
from __future__ import absolute_import

# Supported dtypes
dtypes = ['int32', 'int64', 'float32', 'float64']

import slow
from . import slow

# If you bork the build (e.g. by messing around with the templates),
# you still want to be able to import Bottleneck so that you can
# rebuild using the templates. So try to import the compiled Bottleneck
# functions to the top level, but move on if not successful.
try:
from func import (nansum, nanmax, nanmin, nanmean, nanstd, nanvar, median,
from .func import (nansum, nanmax, nanmin, nanmean, nanstd, nanvar, median,
nanmedian, nanargmin, nanargmax, rankdata, nanrankdata,
ss, partsort, argpartsort, replace)
except:
pass
try:
from move import (move_sum, move_nansum,
from .move import (move_sum, move_nansum,
move_mean, move_nanmean,
move_std, move_nanstd,
move_min, move_nanmin,
Expand All @@ -32,4 +33,4 @@
test = Tester().test
del Tester
except (ImportError, ValueError):
print "No Bottleneck unit testing available."
print("No Bottleneck unit testing available.")
2 changes: 1 addition & 1 deletion bottleneck/benchmark/autotimeit.py
Expand Up @@ -14,5 +14,5 @@ def autoscaler(timer, mintime):
if time > mintime:
return number, time
number *= 10
raise RuntimeError, 'function is too fast to test'
raise RuntimeError('function is too fast to test')

70 changes: 35 additions & 35 deletions bottleneck/benchmark/bench.py
@@ -1,10 +1,10 @@

# For support of python 2.5
from __future__ import with_statement
from __future__ import absolute_import, with_statement

import numpy as np
import bottleneck as bn
from autotimeit import autotimeit
from .autotimeit import autotimeit

__all__ = ['bench']

Expand Down Expand Up @@ -55,47 +55,47 @@ def bench(mode='fast', dtype='float64', axis=0,
tab = ' '

# Header
print 'Bottleneck performance benchmark'
print "%sBottleneck %s" % (tab, bn.__version__)
print "%sNumpy (np) %s" % (tab, np.__version__)
print('Bottleneck performance benchmark')
print("%sBottleneck %s" % (tab, bn.__version__))
print("%sNumpy (np) %s" % (tab, np.__version__))
if SCIPY:
print "%sScipy (sp) %s" % (tab, sp.__version__)
print("%sScipy (sp) %s" % (tab, sp.__version__))
else:
print "%sScipy (sp) Cannot import, skipping scipy benchmarks" % tab
print "%sSpeed is NumPy or SciPy time divided by Bottleneck time" % tab
print("%sScipy (sp) Cannot import, skipping scipy benchmarks" % tab)
print("%sSpeed is NumPy or SciPy time divided by Bottleneck time" % tab)
tup = (tab, dtype, axis)
print "%sNaN means one-third NaNs; %s and axis=%s are used" % tup
print("%sNaN means one-third NaNs; %s and axis=%s are used" % tup )
if mode == 'fast':
print "%sHigh-level functions used (mode='fast')" % tab
print("%sHigh-level functions used (mode='fast')" % tab)
elif mode == 'faster':
print "%sLow-level functions used (mode='faster')" % tab
print("%sLow-level functions used (mode='faster')" % tab)

print
print('')
header = [" "*14]
for nan in nans:
if nan:
header.append("NaN".center(11))
else:
header.append("no NaN".center(11))
print "".join(header)
print("".join(header))
header = ["".join(str(shape).split(" ")).center(11) for shape in shapes]
header = [" "*14] + header
print "".join(header)
print("".join(header))

suite = benchsuite(mode, shapes, dtype, axis, nans)
for test in suite:
name = test["name"].ljust(12)
fmt = name + "%10.2f" + "%11.2f"*(len(shapes) - 1)
if test['scipy_required'] and not SCIPY:
print "%s%s" % (name, "requires SciPy")
print("%s%s" % (name, "requires SciPy"))
else:
speed = timer(test['statements'], test['setups'])
print fmt % tuple(speed)
print(fmt % tuple(speed))

print
print 'Reference functions:'
print('')
print('Reference functions:')
for test in suite:
print "%s%s" % (test["name"].ljust(15), test['ref'])
print("%s%s" % (test["name"].ljust(15), test['ref']))

def timer(statements, setups):
speed = []
Expand Down Expand Up @@ -343,7 +343,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_sum"
run['ref'] = "sp.ndimage.convolve1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_sum(a, window=w, axis=AXIS)"
Expand All @@ -352,7 +352,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_sum(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_sum as scipy_move_sum
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_sum(a, window=w, axis=AXIS)
func, a = bn.move.move_sum_selector(a, axis=AXIS)
"""
Expand All @@ -364,7 +364,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_nansum"
run['ref'] = "sp.ndimage.convolve1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_nansum(a, window=w, axis=AXIS)"
Expand All @@ -373,7 +373,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_nansum(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_nansum as scipy_move_nansum
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_nansum(a, window=w, axis=AXIS)
func, a = bn.move.move_nansum_selector(a, axis=AXIS)
"""
Expand All @@ -385,7 +385,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_mean"
run['ref'] = "sp.ndimage.convolve1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_mean(a, window=w, axis=AXIS)"
Expand All @@ -394,7 +394,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_mean(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_mean as scipy_move_mean
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_mean(a, window=w, axis=AXIS)
func, a = bn.move.move_mean_selector(a, axis=AXIS)
"""
Expand All @@ -406,7 +406,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_nanmean"
run['ref'] = "sp.ndimage.convolve1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_nanmean(a, window=w, axis=AXIS)"
Expand All @@ -415,7 +415,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_nanmean(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_nanmean as scipy_move_nanmean
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_nanmean(a, window=w, axis=AXIS)
func, a = bn.move.move_nanmean_selector(a, axis=AXIS)
"""
Expand All @@ -427,7 +427,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_std"
run['ref'] = "sp.ndimage.convolve1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_std(a, window=w, axis=AXIS)"
Expand All @@ -436,7 +436,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_std(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_std as scipy_move_std
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_std(a, window=w, axis=AXIS)
func, a = bn.move.move_std_selector(a, axis=AXIS)
"""
Expand All @@ -448,7 +448,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_nanstd"
run['ref'] = "sp.ndimage.convolve1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_nanstd(a, window=w, axis=AXIS)"
Expand All @@ -457,7 +457,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_nanstd(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_nanstd as scipy_move_nanstd
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_nanstd(a, window=w, axis=AXIS)
func, a = bn.move.move_nanstd_selector(a, axis=AXIS)
"""
Expand All @@ -469,7 +469,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_max"
run['ref'] = "sp.ndimage.maximum_filter1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_max(a, window=w, axis=AXIS)"
Expand All @@ -478,7 +478,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_max(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_max as scipy_move_max
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_max(a, window=w, axis=AXIS)
func, a = bn.move.move_max_selector(a, axis=AXIS)
"""
Expand All @@ -490,7 +490,7 @@ def getsetups(setup, shapes, nans):
run = {}
run['name'] = "move_nanmax"
run['ref'] = "sp.ndimage.maximum_filter1d based, "
run['ref'] += "window=a.shape[%s]/5" % axis
run['ref'] += "window=a.shape[%s] // 5" % axis
run['scipy_required'] = True
if mode == 'fast':
code = "bn.move_nanmax(a, window=w, axis=AXIS)"
Expand All @@ -499,7 +499,7 @@ def getsetups(setup, shapes, nans):
run['statements'] = [code, "scipy_move_nanmax(a, window=w, axis=AXIS)"]
setup = """
from bottleneck.slow.move import move_nanmax as scipy_move_nanmax
w = a.shape[AXIS] / 5
w = a.shape[AXIS] // 5
ignore = bn.slow.move_nanmax(a, window=w, axis=AXIS)
func, a = bn.move.move_nanmax_selector(a, axis=AXIS)
"""
Expand Down
5 changes: 2 additions & 3 deletions bottleneck/slow/__init__.py
@@ -1,3 +1,2 @@

from func import *
from move import *
from bottleneck.slow.func import *
from bottleneck.slow.move import *
8 changes: 5 additions & 3 deletions bottleneck/slow/func.py
Expand Up @@ -70,7 +70,7 @@ def nanstd(arr, axis=None, ddof=0):
if axis < 0:
axis += arr.ndim
if (axis < 0) or (axis >= arr.ndim):
raise ValueError, "axis(=%d) out of bounds" % axis
raise ValueError("axis(=%d) out of bounds" % axis)
else:
# Older versions of scipy choke on axis=None
arr = arr.ravel()
Expand Down Expand Up @@ -107,6 +107,7 @@ def nanargmax(arr, axis=None):

def rankdata(arr, axis=None):
"Slow rankdata function used for unaccelerated ndim/dtype combinations."
arr = np.asarray(arr)
if axis is None:
arr = arr.ravel()
axis = 0
Expand All @@ -122,6 +123,7 @@ def rankdata(arr, axis=None):

def nanrankdata(arr, axis=None):
"Slow nanrankdata function used for unaccelerated ndim/dtype combinations."
arr = np.asarray(arr)
if axis is None:
arr = arr.ravel()
axis = 0
Expand Down Expand Up @@ -419,12 +421,12 @@ def scipy_rankdata(a):
sumranks = 0
dupcount = 0
newarray = np.zeros(n, float)
for i in xrange(n):
for i in range(n):
sumranks += i
dupcount += 1
if i==n-1 or svec[i] != svec[i+1]:
averank = sumranks / float(dupcount) + 1
for j in xrange(i-dupcount+1,i+1):
for j in range(i-dupcount+1,i+1):
newarray[ivec[j]] = averank
sumranks = 0
dupcount = 0
Expand Down

0 comments on commit 2f07774

Please sign in to comment.