Try to import weave before scipy.weave
Weave is now deprecated in the latest scipy 1.5 so we should do something like:

```
try:
   import weave
except ImportError:
  try:
    from scipy import weave
  except ImportError:
    weave = None
```

diff --git a/brian2/__init__.py b/brian2/__init__.py
index bf337644..c684a946 100644
--- a/brian2/__init__.py
+++ b/brian2/__init__.py
@@ -10,11 +10,6 @@
 except ImportError as ex:
     sys.stderr.write('Importing numpy failed: %s\n' % ex)
     missing.append('numpy')
-try:
-    import scipy
-except ImportError as ex:
-    sys.stderr.write('Importing scipy failed: %s\n' % ex)
-    missing.append('scipy')
 try:
     import sympy
 except ImportError as ex:
@@ -81,6 +76,5 @@ def _check_dependency_version(name, version):
             logger.warn(message, 'outdated_dependency')
 
 for name, version in [('numpy', '1.8.0'),
-                      ('scipy', '0.13.3'),
                       ('sympy', '0.7.6')]:
     _check_dependency_version(name, version)
diff --git a/brian2/codegen/generators/numpy_generator.py b/brian2/codegen/generators/numpy_generator.py
index f8775d53..3b0fac52 100644
--- a/brian2/codegen/generators/numpy_generator.py
+++ b/brian2/codegen/generators/numpy_generator.py
@@ -121,8 +121,13 @@ def translate_one_statement_sequence(self, statements):
         return lines
 
     def determine_keywords(self):
-        # For numpy, no addiional keywords are provided to the template
-        return {}
+        try:
+            import scipy
+            scipy_available = True
+        except ImportError:
+            scipy_available = False
+
+        return {'_scipy_available': scipy_available}
 
 ################################################################################
 # Implement functions
@@ -133,7 +138,8 @@ def determine_keywords(self):
                         ('exp', np.exp), ('log', np.log), ('log10', np.log10),
                         ('sqrt', np.sqrt), ('arcsin', np.arcsin),
                         ('arccos', np.arccos), ('arctan', np.arctan),
-                        ('abs', np.abs), ('mod', np.fmod)]:
+                        ('abs', np.abs), ('mod', np.fmod),
+                        ('sign', np.sign)]:
     DEFAULT_FUNCTIONS[func_name].implementations.add_implementation(NumpyCodeGenerator,
                                                                     code=func)
 
diff --git a/brian2/codegen/runtime/numpy_rt/templates/spatialstateupdate.py_ b/brian2/codegen/runtime/numpy_rt/templates/spatialstateupdate.py_
index bc1a6a4d..f2a50594 100644
--- a/brian2/codegen/runtime/numpy_rt/templates/spatialstateupdate.py_
+++ b/brian2/codegen/runtime/numpy_rt/templates/spatialstateupdate.py_
@@ -10,7 +10,6 @@
 Solves the cable equation (spatial diffusion of currents).
 This is where most time-consuming time computations are done.
 '''
-from scipy.linalg import solve_banded
 from numpy.linalg import solve
 from numpy import zeros
 
@@ -22,6 +21,9 @@ _vectorisation_idx = 1
 _vectorisation_idx = N
 {{vector_code|autoindent}}
 
+{%if _scipy_available %}
+from scipy.linalg import solve_banded
+
 # Particular solution
 b=-({{Cm}}/dt*{{v}})-_I0
 ab = zeros((3,N))
@@ -43,6 +45,74 @@ ab[1,:]={{ab_minus1}}
 ab[2,:]={{ab_minus2}}
 ab[1,:]-=_gtot
 {{u_minus}}[:]=solve_banded((1,1),ab,b,overwrite_ab=True,overwrite_b=True)
+{% else %}
+# Pure numpy solution, very slow because it needs forward and backward passes
+# along the array that can't be vectorized
+c = zeros(N)
+ab = zeros((3, N))
+_gtot_all = zeros(N)
+_gtot_all[:] = _gtot
+b = -({{Cm}} / dt*{{v}}) - _I0
+
+# Tridiagonal solving
+forward = range(1, N)
+backward = range(N-2, -1, -1)
+
+# Pass 1
+bi = {{ab_star1}} - _gtot_all  # main diagonal
+
+# First compartment
+c[0] = {{ab_star0}}[1] / bi[0]
+{{v_star}}[0] = b[0] / bi[0]
+
+# Other compartments
+c[1:-1] = {{ab_star0}}[2:]
+for i in forward:
+    ai = {{ab_star2}}[i-1]  # subdiagonal
+    _m = 1.0/(bi[i]-ai*c[i-1])
+    c[i] *= _m
+    {{v_star}}[i] = (b[i] - ai*{{v_star}}[i-1])*_m
+
+for i in backward:
+    {{v_star}}[i] -= c[i]*{{v_star}}[i+1]
+
+# Pass 2
+bi = {{ab_plus1}} - _gtot_all  # main diagonal
+
+# First compartment
+c[0] = {{ab_plus0}}[1]/bi[0]
+{{u_plus}}[0] = {{b_plus}}[0]/bi[0]
+
+# Other compartments
+c[1:-1] = {{ab_plus0}}[2:]  # superdiagonal
+
+for i in forward:
+    ai = {{ab_plus2}}[i-1]  # subdiagonal
+    _m = 1.0/(bi[i]-ai*c[i-1])
+    c[i] *= _m
+    {{u_plus}}[i] = ({{b_plus}}[i] - ai*{{u_plus}}[i-1])*_m
+
+for i in backward:
+    {{u_plus}}[i] -= c[i]*{{u_plus}}[i+1]
+
+# Pass 3
+bi = {{ab_minus1}} - _gtot_all  # main diagonal
+
+# First compartment
+c[0] = {{ab_minus0}}[1]/bi[0]
+{{u_minus}}[0] = {{b_minus}}[0]/bi[0]
+
+# Other compartments
+c[1:-1] = {{ab_minus0}}[2:]  # superdiagonal
+for i in forward:
+    ai = {{ab_minus2}}[i-1]  # subdiagonal
+    _m = 1.0/(bi[i]-ai*c[i-1]);
+    c[i] *= _m
+    {{u_minus}}[i] = ({{b_minus}}[i] - ai*{{u_minus}}[i-1])*_m
+
+for i in backward:
+    {{u_minus}}[i] -= c[i]*{{u_minus}}[i+1]
+{% endif %}
 
 # Prepare matrix for solving the linear system
 _n_segments = len({{_B}})
diff --git a/brian2/codegen/runtime/weave_rt/weave_rt.py b/brian2/codegen/runtime/weave_rt/weave_rt.py
index a79e28e2..df664fde 100644
--- a/brian2/codegen/runtime/weave_rt/weave_rt.py
+++ b/brian2/codegen/runtime/weave_rt/weave_rt.py
@@ -10,8 +10,12 @@
     from scipy import weave
     from scipy.weave.c_spec import num_to_c_types
 except ImportError:
-    # No weave for Python 3
-    weave = None
+    try:  # weave as an independent package
+        import weave
+        from weave.c_spec import num_to_c_types
+    except ImportError:
+        # No weave for Python 3
+        weave = None
 
 from brian2.core.variables import (DynamicArrayVariable, ArrayVariable,
                                    AttributeVariable, AuxiliaryVariable,
diff --git a/brian2/spatialneuron/spatialneuron.py b/brian2/spatialneuron/spatialneuron.py
index 9b278af4..33306ae7 100644
--- a/brian2/spatialneuron/spatialneuron.py
+++ b/brian2/spatialneuron/spatialneuron.py
@@ -410,6 +410,20 @@ def before_run(self, run_namespace=None, level=0):
                                                           run_namespace=run_namespace,
                                                           level=level+1)
         self._prepare_codeobj()
+        # Raise a warning if the slow pure numpy version is used
+        # For simplicity, we check which CodeObject class the _prepare_codeobj
+        # is using, this will be the same as the main state updater
+        from brian2.codegen.runtime.numpy_rt.numpy_rt import NumpyCodeObject
+        if isinstance(self._prepare_codeobj, NumpyCodeObject):
+            # If numpy is used, raise a warning if scipy is not present
+            try:
+                import scipy
+            except ImportError:
+                logger.warn(('SpatialNeuron will use numpy to do the numerical '
+                             'integration -- this will be very slow. Either '
+                             'switch to a different code generation target '
+                             '(e.g. weave or cython) or install scipy.'),
+                            once=True)
         CodeRunner.before_run(self, run_namespace, level=level + 1)
 
     def _pre_calc_iteration(self, morphology, counter=0):
diff --git a/brian2/tests/__init__.py b/brian2/tests/__init__.py
index 4ee393c9..d3cc1888 100644
--- a/brian2/tests/__init__.py
+++ b/brian2/tests/__init__.py
@@ -44,7 +44,11 @@ def run(codegen_targets=None, long_tests=False, test_codegen_independent=True,
             import scipy.weave
             codegen_targets.append('weave')
         except ImportError:
-            pass
+            try:
+                import weave
+                codegen_targets.append('weave')
+            except ImportError:
+                pass
         try:
             import Cython
             codegen_targets.append('cython')
diff --git a/brian2/tests/test_parsing.py b/brian2/tests/test_parsing.py
index a53446f6..1d892228 100644
--- a/brian2/tests/test_parsing.py
+++ b/brian2/tests/test_parsing.py
@@ -30,7 +30,10 @@
 try:
     from scipy import weave
 except ImportError:
-    weave = None
+    try:
+        import weave
+    except ImportError:
+        weave = None
 import nose
 
 
diff --git a/brian2/utils/logger.py b/brian2/utils/logger.py
index 14293e38..6eec0260 100644
--- a/brian2/utils/logger.py
+++ b/brian2/utils/logger.py
@@ -15,7 +15,17 @@
 from warnings import warn
 
 import numpy
-import scipy
+try:
+    import scipy
+except ImportError:
+    scipy = None
+try:
+    import scipy.weave as weave
+except ImportError:
+    try:
+        import weave
+    except ImportError:
+        weave = None
 import sympy
 
 import brian2
@@ -180,7 +190,8 @@ def _encode(text):
 logger.debug('Platform: %s' % sys.platform)
 version_infos = {'brian': brian2.__version__,
                  'numpy': numpy.__version__,
-                 'scipy': scipy.__version__,
+                 'scipy': scipy.__version__ if scipy else 'not installed',
+                 'weave': weave.__version__ if weave else 'not installed',
                  'sympy': sympy.__version__,
                  'python': sys.version,
                  }
diff --git a/setup.py b/setup.py
index 15a19183..d923f0d4 100644
--- a/setup.py
+++ b/setup.py
@@ -144,7 +144,6 @@ def build_extension(self, ext):
                     'brian2': ['default_preferences']
                     },
       install_requires=['numpy>=1.8.0',
-                        'scipy>=0.13.3',
                         'sympy>=0.7.6',
                         'pyparsing',
                         'jinja2>=2.7',
['brian2/codegen/generators/numpy_generator.py', 'brian2/codegen/runtime/numpy_rt/templates/spatialstateupdate.py_', 'brian2/utils/logger.py', 'setup.py', 'brian2/spatialneuron/spatialneuron.py', 'brian2/codegen/runtime/weave_rt/weave_rt.py', 'brian2/__init__.py', 'brian2/tests/__init__.py', 'brian2/tests/test_parsing.py']