diff --git a/INSTALL.rst b/INSTALL.rst
index a944ddbb609ce2a5cd47ca91f31f99ef8f95a1ad..336dd2db0ddbe2fa067559f79884ba910f00fbbc 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -32,7 +32,11 @@ Building Kwant requires
  * `Python <https://www.python.org/>`_ 3.5 or above (Kwant 1.1 is the last
    version to support Python 2),
  * `NumPy <http://numpy.org/>`_ 1.11.0 or newer,
- * `SciPy <https://scipy.org/>`_ 0.17.0 or newer,
+ * `SciPy <https://www.scipy.org/>`_ 0.17.0 or newer,
+ * `LAPACK <http://netlib.org/lapack/>`_ and `BLAS <http://netlib.org/blas/>`_,
+   (For best performance we recommend the free `OpenBLAS
+   <http://www.openblas.net/>`_ or the nonfree `MKL
+   <https://software.intel.com/en-us/intel-mkl>`_.)
  * `Tinyarray <https://gitlab.kwant-project.org/kwant/tinyarray>`_ 1.2 or newer,
 a NumPy-like Python package optimized for very small arrays,
  * An environment which allows to compile Python extensions written in C and
@@ -170,7 +174,7 @@ are extracted form the diff file.
 The diff file may be modified directly.  Another possible way of working is to
 directly modify either the tutorial script or the figure generation script.
 Then ``make html`` will use the command line tool `wiggle
-<http://neil.brown.name/wiggle/>`_ to propagate the modifications accordingly.
+<https://github.com/neilbrown/wiggle>`_ to propagate the modifications accordingly.
 This will often just work, but may sometimes result in conflicts, in which case
 a message will be printed.  The conflicts then have to be resolved much like
 with a version control system.
diff --git a/kwant/builder.py b/kwant/builder.py
index 0737f3a10a0ddfee86541e13b911e6267e51f884..6441083d244d7649784d121213b8f287ce3f4356 100644
--- a/kwant/builder.py
+++ b/kwant/builder.py
@@ -1806,7 +1806,7 @@ def _translate_cons_law(cons_law):
                 return 1
             return np.linalg.eigh(cons_law(site, *args, **kwargs))[1]
 
-    elif isinstance(cons_law, collections.Mapping):
+    elif isinstance(cons_law, collections.abc.Mapping):
         vals = {family: (value if family.norbs == 1 else
                          ta.array(np.diag(np.linalg.eigvalsh(value))))
                 for family, value in cons_law.items()}
diff --git a/kwant/kpm.py b/kwant/kpm.py
index 4a24a9ad54032f4569268163469ba8d82f6f09c7..93e395ad7cccdd45db012776550f52b4f5fadce3 100644
--- a/kwant/kpm.py
+++ b/kwant/kpm.py
@@ -30,7 +30,7 @@ __all__ = ['SpectralDensity', 'Correlator', 'conductivity',
 SAMPLING = 2 # number of sampling points to number of moments ratio
 
 class SpectralDensity:
-    """Calculate the spectral density of an operator.
+    r"""Calculate the spectral density of an operator.
 
     This class makes use of the kernel polynomial
     method (KPM), presented in [1]_, to obtain the spectral density
diff --git a/kwant/linalg/mumps.py b/kwant/linalg/mumps.py
index 465ef1aa359ab3c88adbf5a4a4ccf125c73094dd..c3bec6fddf6b45cf951351abe9b9dc7dd67db28e 100644
--- a/kwant/linalg/mumps.py
+++ b/kwant/linalg/mumps.py
@@ -239,9 +239,9 @@ class MUMPSContext:
         self.mumps_instance.set_assembled_matrix(a.shape[0], row, col, data)
         self.mumps_instance.icntl[7] = orderings[ordering]
         self.mumps_instance.job = 1
-        t1 = time.clock()
+        t1 = time.process_time()
         self.mumps_instance.call()
-        t2 = time.clock()
+        t2 = time.process_time()
         self.factored = False
 
         if self.mumps_instance.infog[1] < 0:
@@ -325,9 +325,9 @@ class MUMPSContext:
 
         done = False
         while not done:
-            t1 = time.clock()
+            t1 = time.process_time()
             self.mumps_instance.call()
-            t2 = time.clock()
+            t2 = time.process_time()
 
             # error -8, -9 (not enough allocated memory) is treated
             # specially, by increasing the memory relaxation parameter
@@ -492,9 +492,9 @@ def schur_complement(a, indices, ordering='auto', ooc=False, pivot_tol=0.01,
     mumps_instance.set_schur(schur_compl, indices)
 
     mumps_instance.job = 4   # job=4 -> 1 and 2 after each other
-    t1 = time.clock()
+    t1 = time.process_time()
     mumps_instance.call()
-    t2 = time.clock()
+    t2 = time.process_time()
 
     if not calc_stats:
         return schur_compl
diff --git a/kwant/operator.pyx b/kwant/operator.pyx
index e0483d60cb7c4d96d94b261cbe6beb3170d3f675..0b1a8e279f5b3a95609e61dd23ddb183474889c5 100644
--- a/kwant/operator.pyx
+++ b/kwant/operator.pyx
@@ -266,7 +266,7 @@ def _normalize_onsite(syst, onsite, check_hermiticity):
             _onsite = _FunctionalOnsite(onsite, syst.sites)
         except AttributeError:
             _onsite = onsite
-    elif isinstance(onsite, collections.Mapping):
+    elif isinstance(onsite, collections.abc.Mapping):
         if not hasattr(syst, 'sites'):
             raise TypeError('Provide `onsite` as a value or a function for '
                             'systems that are not finalized Builders.')
diff --git a/kwant/plotter.py b/kwant/plotter.py
index e415e58bcce9441a732f7fde7eea8a9ff819dd88..1af73aecfc904c0eef8dcb339b8e0cff500a5603 100644
--- a/kwant/plotter.py
+++ b/kwant/plotter.py
@@ -2161,7 +2161,7 @@ def current(syst, current, relwidth=0.05, **kwargs):
         Relative width of the bumps used to smooth the field, as a fraction
         of the length of the longest side of the bounding box.
     **kwargs : various
-        Keyword args to be passed verbatim to `~kwant.plotter.streamplot`.
+        Keyword args to be passed verbatim to `kwant.plotter.streamplot`.
 
     Returns
     -------
diff --git a/kwant/wraparound.py b/kwant/wraparound.py
index d707c265a5f4c3f0f3ae67070eccc621bb05f1dd..fdfcc9f2598714ad5189ceff5e50d6fc5440ecd7 100644
--- a/kwant/wraparound.py
+++ b/kwant/wraparound.py
@@ -27,7 +27,7 @@ __all__ = ['wraparound', 'plot_2d_bands']
 
 
 def _hashable(obj):
-    return isinstance(obj, collections.Hashable)
+    return isinstance(obj, collections.abc.Hashable)
 
 
 def _memoize(f):