Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make brian ready for python 3 #26

Merged
merged 24 commits into from Mar 29, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
82e63c1
Adapt setup.py to support python 3.x via 2to3
Mar 26, 2013
3354823
Enable testing in Python 3
Mar 26, 2013
c031801
Make sure to run the built brian2 package, not the source one (important
Mar 27, 2013
fa588a0
Convert checks for isNumericType and isSequenceType into something
Mar 26, 2013
684d42f
Really check the test for number types and test it a bit more thoroughly
Mar 26, 2013
c85d7e9
Make itertools usage python3-ready.
Mar 27, 2013
d74027f
Correct some print statements, do not insist on sympy 0.7.1 anymore
Mar 27, 2013
e3600db
Make Dimension object hashable
Mar 27, 2013
b603510
Make ipython check work for python 3
Mar 27, 2013
71d9ee5
Make sure the logger module encodes strings in a way that works with
Mar 27, 2013
e4b2ff8
Do not run nosetests from the source directory to make sure it uses the
Mar 28, 2013
9ff1282
Adapt doctests for python3-style print statements
Mar 28, 2013
fae52ff
Fail gracefully when weave is not available (it does not work for Python
Mar 28, 2013
a1cce02
Do not implement __eq__ and __lt__ for clocks
Mar 28, 2013
0615753
Use operator.truediv instead of operator.div
Mar 28, 2013
fa1de0c
Make sure to pass strings (not Expression objects) to sympy
Mar 28, 2013
e419338
Don't print the type of objects as part of doctests (format changes from
Mar 28, 2013
fb04c7e
Use the IGNORE_EXCEPTION_DETAIL directive for doctest that use a
Mar 28, 2013
731c47a
Ignore errors when generating the xml report
Mar 28, 2013
99b1872
Use the correct .coveragerc file for testing
Mar 28, 2013
2dec509
Remove unused import
Mar 28, 2013
3556d5c
Install different numpy versions for Python 2 and 3
Mar 28, 2013
ad8f88c
Add notes about Python 2 vs. Python 3 to the coding guidelines
Mar 29, 2013
b8be01f
Explicitly specify the tarball to use for sympy under python 3
Mar 29, 2013
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 11 additions & 4 deletions .travis.yml
Expand Up @@ -2,16 +2,23 @@ language: python
python: python:
- "2.6" - "2.6"
- "2.7" - "2.7"
- "3.2"
- "3.3"
# install build dependencies # install build dependencies
before_install: before_install:
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get build-dep -qq python-scipy python-sympy python-pyparsing - sudo apt-get build-dep -qq python-scipy python-sympy python-pyparsing
# command to install dependencies # command to install dependencies
install: install:
- "pip install numpy==1.6.2" # install different versions of numpy for python 2 and 3
- "pip install scipy sympy pyparsing==1.5.7 sphinx ipython --use-mirrors" - "if [ ${TRAVIS_PYTHON_VERSION:0:1} == '2' ]; then pip install numpy==1.6.2 --use-mirrors; else pip install numpy --use-mirrors; fi"
- "pip install scipy sphinx ipython --use-mirrors"
# Make sure to use the python 3 version for sympy
- "if [ ${TRAVIS_PYTHON_VERSION:0:1} == '2' ]; then pip install sympy --use-mirrors; else pip install http://sympy.googlecode.com/files/sympy-0.7.2-py3.2.tar.gz; fi"
# install different pyparsing versions for python 2 and 3
- "if [ ${TRAVIS_PYTHON_VERSION:0:1} == '2' ]; then pip install pyparsing==1.5.7 --use-mirrors; else pip install pyparsing --use-mirrors; fi"
- "pip install . --use-mirrors" - "pip install . --use-mirrors"
# command to run tests # command to run tests (make sure to not run it from the source directory)
script: nosetests --with-doctest brian2 script: "cd ~;nosetests --with-doctest brian2"
notifications: notifications:
email: false email: false
8 changes: 4 additions & 4 deletions brian2/__init__.py
Expand Up @@ -13,22 +13,22 @@
try: try:
import numpy import numpy
except ImportError as ex: except ImportError as ex:
print >>sys.stderr, 'Importing numpy failed:', ex sys.stderr.write('Importing numpy failed: %s\n' % ex)
missing.append('numpy') missing.append('numpy')
try: try:
import scipy import scipy
except ImportError as ex: except ImportError as ex:
print >>sys.stderr, 'Importing scipy failed:', ex sys.stderr.write('Importing scipy failed: %s\n' % ex)
missing.append('scipy') missing.append('scipy')
try: try:
import sympy import sympy
except ImportError as ex: except ImportError as ex:
print >>sys.stderr, 'Importing sympy failed:', ex sys.stderr.write('Importing sympy failed: %s\n' % ex)
missing.append('sympy') missing.append('sympy')
try: try:
import pyparsing import pyparsing
except ImportError as ex: except ImportError as ex:
print >>sys.stderr, 'Importing pyparsing failed:', ex sys.stderr.write('Importing pyparsing failed: %s\n' % ex)
missing.append('pyparsing') missing.append('pyparsing')


if len(missing): if len(missing):
Expand Down
14 changes: 9 additions & 5 deletions brian2/codegen/languages/cpp.py
@@ -1,20 +1,24 @@
''' '''
TODO: restrict keyword optimisations TODO: restrict keyword optimisations
''' '''
import itertools import re


from sympy.printing.ccode import CCodePrinter from sympy.printing.ccode import CCodePrinter
import numpy import numpy
from scipy import weave
import re


from brian2.utils.stringtools import deindent from brian2.utils.stringtools import deindent
from brian2.utils.parsing import parse_to_sympy from brian2.utils.parsing import parse_to_sympy

from brian2.codegen.functions.base import Function from brian2.codegen.functions.base import Function
from .base import Language, CodeObject from brian2.utils.logger import get_logger


from .base import Language, CodeObject


logger = get_logger(__name__)
try:
from scipy import weave
except ImportError as ex:
logger.warn('Importing scipy.weave failed: %s' % ex)
weave = None


__all__ = ['CPPLanguage', 'CPPCodeObject', __all__ = ['CPPLanguage', 'CPPCodeObject',
'c_data_type', 'c_data_type',
Expand Down
18 changes: 1 addition & 17 deletions brian2/core/clocks.py
Expand Up @@ -45,10 +45,10 @@ class Clock(Nameable):


@check_units(dt=second, t=second) @check_units(dt=second, t=second)
def __init__(self, dt=None, name=None): def __init__(self, dt=None, name=None):
Nameable.__init__(self, name)
self._dt_spec = dt self._dt_spec = dt
self.i = 0 #: The time step of the simulation as an integer. self.i = 0 #: The time step of the simulation as an integer.
self.i_end = 0 #: The time step the simulation will end as an integer self.i_end = 0 #: The time step the simulation will end as an integer
Nameable.__init__(self, name)
logger.debug("Created clock {self.name} with dt={self._dt_spec}".format(self=self)) logger.debug("Created clock {self.name} with dt={self._dt_spec}".format(self=self))


def reinit(self): def reinit(self):
Expand Down Expand Up @@ -153,21 +153,5 @@ def running(self):
return self.i<self.i_end return self.i<self.i_end


epsilon = 1e-14 epsilon = 1e-14

def __lt__(self, other):
selft = self.t_
othert = other.t_
if selft==othert or abs(selft-othert)<=self.epsilon*abs(selft):
return False
return selft<othert

def __eq__(self, other):
selft = self.t_
othert = other.t_
if selft==othert or abs(selft-othert)<=self.epsilon*abs(selft):
return True
else:
return False



defaultclock = Clock(name='defaultclock') defaultclock = Clock(name='defaultclock')
7 changes: 5 additions & 2 deletions brian2/core/network.py
Expand Up @@ -3,6 +3,7 @@
from brian2.utils.logger import get_logger from brian2.utils.logger import get_logger
from brian2.core.names import Nameable from brian2.core.names import Nameable
from brian2.core.base import BrianObject from brian2.core.base import BrianObject
from brian2.core.clocks import Clock
from brian2.units.fundamentalunits import check_units from brian2.units.fundamentalunits import check_units
from brian2.units.allunits import second from brian2.units.allunits import second
from brian2.core.preferences import brian_prefs from brian2.core.preferences import brian_prefs
Expand Down Expand Up @@ -236,8 +237,10 @@ def prepare(self):
self._prepared = True self._prepared = True


def _nextclocks(self): def _nextclocks(self):
minclock = min(self._clocks) minclock = min(self._clocks, key=lambda c: c.t_)
curclocks = set(clock for clock in self._clocks if clock==minclock) curclocks = set(clock for clock in self._clocks if
(clock.t_ == minclock.t_ or
abs(clock.t_ - minclock.t_)<Clock.epsilon))
return minclock, curclocks return minclock, curclocks


@check_units(duration=second, report_period=second) @check_units(duration=second, report_period=second)
Expand Down
6 changes: 3 additions & 3 deletions brian2/core/operations.py
Expand Up @@ -63,15 +63,15 @@ def network_operation(*args, **kwds):
>>> from brian2 import * >>> from brian2 import *
>>> @network_operation >>> @network_operation
... def f(): ... def f():
... print 'something' ... print('something')
... ...
>>> net = Network(f) >>> net = Network(f)


Print the time each time step: Print the time each time step:


>>> @network_operation >>> @network_operation
... def f(t): ... def f(t):
... print 'The time is', t ... print('The time is', t)
... ...
>>> net = Network(f) >>> net = Network(f)


Expand All @@ -80,7 +80,7 @@ def network_operation(*args, **kwds):
>>> myclock = Clock(dt=0.5*ms) >>> myclock = Clock(dt=0.5*ms)
>>> @network_operation(when=(myclock, 'start', 0)) >>> @network_operation(when=(myclock, 'start', 0))
... def f(): ... def f():
... print 'This will happen at the start of each timestep.' ... print('This will happen at the start of each timestep.')
... ...
>>> net = Network(f) >>> net = Network(f)


Expand Down
10 changes: 5 additions & 5 deletions brian2/memory/dynamicarray.py
Expand Up @@ -60,11 +60,11 @@ class DynamicArray(object):
>>> x.resize((4, 4)) >>> x.resize((4, 4))
>>> x[:] += 1 >>> x[:] += 1
>>> x.data[:] = x.data**2 >>> x.data[:] = x.data**2
>>> print x.data >>> x.data
[[16 16 16 4] array([[16, 16, 16, 4],
[16 16 16 4] [16, 16, 16, 4],
[ 9 9 9 4] [ 9, 9, 9, 4],
[ 1 1 1 1]] [ 1, 1, 1, 1]])


Notes Notes
----- -----
Expand Down
8 changes: 4 additions & 4 deletions brian2/stateupdaters/integration.py
Expand Up @@ -61,11 +61,11 @@ def split_expression(expr):


Examples Examples
-------- --------
>>> print split_expression('dt * f(x, t)') >>> split_expression('dt * f(x, t)')
(dt*f(x, t), None) (dt*f(x, t), None)
>>> print split_expression('dt * f(x, t) + dW * g(x, t)') >>> split_expression('dt * f(x, t) + dW * g(x, t)')
(dt*f(x, t), dW*g(x, t)) (dt*f(x, t), dW*g(x, t))
>>> print split_expression('1/(2*dt**.5)*(g_support - g(x, t))*(dW**2)') >>> split_expression('1/(2*dt**.5)*(g_support - g(x, t))*(dW**2)')
(0, dW**2*dt**(-0.5)*g_support/2 - dW**2*dt**(-0.5)*g(x, t)/2) (0, dW**2*dt**(-0.5)*g_support/2 - dW**2*dt**(-0.5)*g(x, t)/2)
''' '''


Expand Down Expand Up @@ -255,7 +255,7 @@ def replace_func(x, t, expr, temp_vars):
replacements (see `_generate_RHS`). replacements (see `_generate_RHS`).
''' '''
try: try:
s_expr = parse_to_sympy(expr, local_dict=symbols) s_expr = parse_to_sympy(unicode(expr), local_dict=symbols)
except SympifyError as ex: except SympifyError as ex:
raise ValueError('Error parsing the expression "%s": %s' % raise ValueError('Error parsing the expression "%s": %s' %
(expr, str(ex))) (expr, str(ex)))
Expand Down
9 changes: 8 additions & 1 deletion brian2/tests/test_functions.py
Expand Up @@ -11,8 +11,15 @@ def test_math_functions():
''' '''
test_array = np.array([-1, -0.5, 0, 0.5, 1]) test_array = np.array([-1, -0.5, 0, 0.5, 1])


with catch_logs() as _: # Let's suppress warnings about illegal values # We can only test C++ if weave is availabe
try:
import scipy.weave
languages = [PythonLanguage(), CPPLanguage()] languages = [PythonLanguage(), CPPLanguage()]
except ImportError:
# Can't test C++
languages = [PythonLanguage()]

with catch_logs() as _: # Let's suppress warnings about illegal values
for lang in languages: for lang in languages:


# Functions with a single argument # Functions with a single argument
Expand Down
13 changes: 12 additions & 1 deletion brian2/tests/test_units.py
@@ -1,7 +1,6 @@
import itertools import itertools
import warnings import warnings
import pickle import pickle
from exceptions import RuntimeWarning


import numpy as np import numpy as np
from numpy.testing import assert_raises, assert_equal from numpy.testing import assert_raises, assert_equal
Expand All @@ -14,6 +13,7 @@
Unit, Unit,
have_same_dimensions, have_same_dimensions,
get_dimensions, get_dimensions,
is_scalar_type,
DimensionMismatchError, DimensionMismatchError,
check_units, check_units,
in_unit, in_unit,
Expand Down Expand Up @@ -99,6 +99,17 @@ def test_get_dimensions():
assert_equal(dims.get_dimension('length'), 0) assert_equal(dims.get_dimension('length'), 0)


assert get_dimensions(5) is DIMENSIONLESS assert get_dimensions(5) is DIMENSIONLESS
assert get_dimensions(5.0) is DIMENSIONLESS
assert get_dimensions(np.array(5, dtype=np.int)) is DIMENSIONLESS
assert get_dimensions(np.array(5.0)) is DIMENSIONLESS
assert get_dimensions(np.float32(5.0)) is DIMENSIONLESS
assert get_dimensions(np.float64(5.0)) is DIMENSIONLESS
assert is_scalar_type(5)
assert is_scalar_type(5.0)
assert is_scalar_type(np.array(5, dtype=np.int))
assert is_scalar_type(np.array(5.0))
assert is_scalar_type(np.float32(5.0))
assert is_scalar_type(np.float64(5.0))
assert_raises(TypeError, lambda: get_dimensions('a string')) assert_raises(TypeError, lambda: get_dimensions('a string'))


# wrong number of indices # wrong number of indices
Expand Down
15 changes: 10 additions & 5 deletions brian2/tests/test_utils.py
Expand Up @@ -4,20 +4,25 @@ def test_environment():
''' '''
Test information about the environment we are running under. Test information about the environment we are running under.
''' '''
import __builtin__ try:
# Python 2
import __builtin__ as builtins
except ImportError:
# Python 3
import builtins


if hasattr(__builtin__, '__IPYTHON__'): if hasattr(builtins, '__IPYTHON__'):
testing_under_ipython = True testing_under_ipython = True
del __builtin__.__IPYTHON__ del builtins.__IPYTHON__
else: else:
testing_under_ipython = False testing_under_ipython = False


assert not running_from_ipython() assert not running_from_ipython()
__builtin__.__IPYTHON__ = True builtins.__IPYTHON__ = True
assert running_from_ipython() assert running_from_ipython()


if not testing_under_ipython: if not testing_under_ipython:
del __builtin__.__IPYTHON__ del builtins.__IPYTHON__




if __name__ == '__main__': if __name__ == '__main__':
Expand Down