From d8fa9e942b69303cd1fe3ac79cefe60fd1e07e44 Mon Sep 17 00:00:00 2001
From: Joseph Weston <joseph.weston@cea.fr>
Date: Thu, 6 Aug 2015 19:09:37 +0200
Subject: [PATCH] run 2to3 on Kwant codebase

---
 kwant/__init__.py                    |  4 +--
 kwant/_common.py                     |  2 +-
 kwant/builder.py                     | 42 +++++++++++++---------------
 kwant/digest.py                      |  6 ++--
 kwant/graph/__init__.py              |  6 ++--
 kwant/graph/tests/test_core.py       | 10 +++----
 kwant/graph/tests/test_dissection.py |  6 ++--
 kwant/graph/tests/test_scotch.py     | 14 +++++-----
 kwant/graph/tests/test_slicer.py     | 14 +++++-----
 kwant/graph/tests/test_utils.py      |  2 +-
 kwant/lattice.py                     |  4 +--
 kwant/linalg/__init__.py             |  6 ++--
 kwant/linalg/decomp_lu.py            |  8 +++---
 kwant/linalg/fortran_helpers.py      |  2 +-
 kwant/linalg/lll.py                  |  4 +--
 kwant/linalg/mumps.py                |  4 +--
 kwant/linalg/tests/_test_utils.py    | 18 ++++++------
 kwant/linalg/tests/test_linalg.py    |  2 +-
 kwant/linalg/tests/test_lll.py       |  2 +-
 kwant/linalg/tests/test_mumps.py     |  4 +--
 kwant/physics/__init__.py            |  6 ++--
 kwant/physics/leads.py               | 16 +++++------
 kwant/physics/tests/test_leads.py    |  8 +++---
 kwant/plotter.py                     | 40 +++++++++++++-------------
 kwant/rmt.py                         |  2 +-
 kwant/solvers/common.py              | 23 ++++++++-------
 kwant/solvers/mumps.py               |  4 +--
 kwant/solvers/sparse.py              |  2 +-
 kwant/solvers/tests/_test_sparse.py  | 22 +++++++--------
 kwant/solvers/tests/test_mumps.py    |  2 +-
 kwant/solvers/tests/test_sparse.py   |  2 +-
 kwant/system.py                      | 19 ++++++-------
 kwant/tests/test_builder.py          | 28 +++++++++----------
 kwant/tests/test_lattice.py          |  8 +++---
 kwant/tests/test_plotter.py          | 10 +++----
 kwant/tests/test_system.py           |  8 +++---
 36 files changed, 177 insertions(+), 183 deletions(-)

diff --git a/kwant/__init__.py b/kwant/__init__.py
index c45de3fd..74e80f9f 100644
--- a/kwant/__init__.py
+++ b/kwant/__init__.py
@@ -29,7 +29,7 @@ __all__.append('KwantDeprecationWarning')
 from ._common import version as __version__
 
 for module in ['system', 'builder', 'lattice', 'solvers', 'digest', 'rmt']:
-    exec 'from . import {0}'.format(module)
+    exec('from . import {0}'.format(module))
     __all__.append(module)
 
 # Make selected functionality available directly in the root namespace.
@@ -38,7 +38,7 @@ available = [('builder', ['Builder', 'HoppingKind']),
              ('solvers.default',
               ['smatrix', 'greens_function', 'ldos', 'wave_function'])]
 for module, names in available:
-    exec 'from .{0} import {1}'.format(module, ', '.join(names))
+    exec('from .{0} import {1}'.format(module, ', '.join(names)))
     __all__.extend(names)
 
 # Importing plotter might not work, but this does not have to be a problem --
diff --git a/kwant/_common.py b/kwant/_common.py
index e050f2ed..50afc250 100644
--- a/kwant/_common.py
+++ b/kwant/_common.py
@@ -42,7 +42,7 @@ def get_version_from_git():
             break
     else:
         return
-    description = p.communicate()[0].strip('v').rstrip('\n')
+    description = p.communicate()[0].decode().strip('v').rstrip('\n')
 
     release, dev, git = description.rsplit('-', 2)
     version = [release]
diff --git a/kwant/builder.py b/kwant/builder.py
index c594f720..2bb18572 100644
--- a/kwant/builder.py
+++ b/kwant/builder.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 
 __all__ = ['Builder', 'Site', 'SiteFamily', 'SimpleSiteFamily', 'Symmetry',
            'HoppingKind', 'Lead', 'BuilderLead', 'SelfEnergyLead', 'ModesLead']
@@ -14,11 +14,12 @@ __all__ = ['Builder', 'Site', 'SiteFamily', 'SimpleSiteFamily', 'Symmetry',
 import abc
 import warnings
 import operator
-from itertools import izip, islice, chain
+from itertools import islice, chain
 import tinyarray as ta
 import numpy as np
 from . import system, graph, KwantDeprecationWarning
 from ._common import ensure_isinstance
+import collections
 
 
 
@@ -84,7 +85,7 @@ class Site(tuple):
         return self.family.pos(self.tag)
 
 
-class SiteFamily(object):
+class SiteFamily(object, metaclass=abc.ABCMeta):
     """Abstract base class for site families.
 
     Site families are the 'type' of `Site` objects.  Within a family, individual
@@ -107,7 +108,6 @@ class SiteFamily(object):
     site belonging to this family with a given tag.
 
     """
-    __metaclass__ = abc.ABCMeta
 
     def __init__(self, canonical_repr, name):
         self.canonical_repr = canonical_repr
@@ -224,7 +224,7 @@ def validate_hopping(hopping):
 
 ################ Symmetries
 
-class Symmetry(object):
+class Symmetry(object, metaclass=abc.ABCMeta):
     """Abstract base class for spatial symmetries.
 
     Many physical systems possess a discrete spatial symmetry, which results in
@@ -249,7 +249,6 @@ class Symmetry(object):
     typical example of this is when the vector defining a translational
     symmetry is not a lattice vector.
     """
-    __metaclass__ = abc.ABCMeta
 
     @abc.abstractproperty
     def num_directions(self):
@@ -430,7 +429,7 @@ class HermConjOfFunc(object):
 
 ################ Leads
 
-class Lead(object):
+class Lead(object, metaclass=abc.ABCMeta):
     """Abstract base class for leads that can be attached to a `Builder`.
 
     To attach a lead to a builder, append it to the builder's `~Builder.leads`
@@ -442,7 +441,6 @@ class Lead(object):
     interface : sequence of sites
 
     """
-    __metaclass__ = abc.ABCMeta
 
     @abc.abstractmethod
     def finalized(self):
@@ -567,7 +565,7 @@ def edges(seq):
     # izip, when given the same iterator twice, turns a sequence into a
     # sequence of pairs.
     seq_iter = iter(seq)
-    result = izip(seq_iter, seq_iter)
+    result = zip(seq_iter, seq_iter)
     next(result)                # Skip the special loop edge.
     return result
 
@@ -766,7 +764,7 @@ class Builder(object):
         result.H = self.H
         return result
 
-    def __nonzero__(self):
+    def __bool__(self):
         return bool(self.H)
 
     def expand(self, key):
@@ -797,7 +795,7 @@ class Builder(object):
         iter_stack = [None]
         while iter_stack:
             for key in itr:
-                while callable(key):
+                while isinstance(key, collections.Callable):
                     key = key(self)
                 if isinstance(key, tuple):
                     # Site instances are also tuples.
@@ -828,7 +826,7 @@ class Builder(object):
                 b, a = sym.to_fd(b, a)
                 assert not sym.in_fd(a)
             value = self._get_edge(b, a)
-            if callable(value):
+            if isinstance(value, collections.Callable):
                 assert not isinstance(value, HermConjOfFunc)
                 value = HermConjOfFunc(value)
             else:
@@ -974,13 +972,13 @@ class Builder(object):
         initially (but always the equivalent ones).
         """
         try:
-            return self.H.viewkeys()
+            return self.H.keys()
         except AttributeError:
             return frozenset(self.H)
 
     def site_value_pairs(self):
         """Return an iterator over all (site, value) pairs."""
-        for site, hvhv in self.H.iteritems():
+        for site, hvhv in self.H.items():
             yield site, hvhv[1]
 
     def hoppings(self):
@@ -990,7 +988,7 @@ class Builder(object):
         `Builder` symmetry, and are not necessarily the ones that were set
         initially (but always the equivalent ones).
         """
-        for tail, hvhv in self.H.iteritems():
+        for tail, hvhv in self.H.items():
             for head, value in edges(hvhv):
                 if value is Other:
                     continue
@@ -998,7 +996,7 @@ class Builder(object):
 
     def hopping_value_pairs(self):
         """Return an iterator over all (hopping, value) pairs."""
-        for tail, hvhv in self.H.iteritems():
+        for tail, hvhv in self.H.items():
             for head, value in edges(hvhv):
                 if value is Other:
                     continue
@@ -1201,7 +1199,7 @@ class Builder(object):
         #### Make graph.
         g = graph.Graph()
         g.num_nodes = len(sites)  # Some sites could not appear in any edge.
-        for tail, hvhv in self.H.iteritems():
+        for tail, hvhv in self.H.items():
             for head in islice(hvhv, 2, None, 2):
                 if tail == head:
                     continue
@@ -1225,7 +1223,7 @@ class Builder(object):
                     msg = 'When finalizing lead {0}:'.format(lead_nr)
                     warnings.warn(w.__class__(' '.join((msg,) + w.args)),
                                   stacklevel=3)
-            except ValueError, e:
+            except ValueError as e:
                 # Re-raise the exception with an additional message.
                 msg = 'Problem finalizing lead {0}:'.format(lead_nr)
                 e.args = (' '.join((msg,) + e.args),)
@@ -1387,7 +1385,7 @@ class FiniteSystem(system.FiniteSystem):
     def hamiltonian(self, i, j, *args):
         if i == j:
             value = self.onsite_hamiltonians[i]
-            if callable(value):
+            if isinstance(value, collections.Callable):
                 value = value(self.sites[i], *args)
         else:
             edge_id = self.graph.first_edge_id(i, j)
@@ -1397,7 +1395,7 @@ class FiniteSystem(system.FiniteSystem):
                 i, j = j, i
                 edge_id = self.graph.first_edge_id(i, j)
                 value = self.hoppings[edge_id]
-            if callable(value):
+            if isinstance(value, collections.Callable):
                 sites = self.sites
                 value = value(sites[i], sites[j], *args)
             if conj:
@@ -1421,7 +1419,7 @@ class InfiniteSystem(system.InfiniteSystem):
             if i >= self.cell_size:
                 i -= self.cell_size
             value = self.onsite_hamiltonians[i]
-            if callable(value):
+            if isinstance(value, collections.Callable):
                 value = value(self.symmetry.to_fd(self.sites[i]), *args)
         else:
             edge_id = self.graph.first_edge_id(i, j)
@@ -1431,7 +1429,7 @@ class InfiniteSystem(system.InfiniteSystem):
                 i, j = j, i
                 edge_id = self.graph.first_edge_id(i, j)
                 value = self.hoppings[edge_id]
-            if callable(value):
+            if isinstance(value, collections.Callable):
                 sites = self.sites
                 site_i = sites[i]
                 site_j = sites[j]
diff --git a/kwant/digest.py b/kwant/digest.py
index 8daac5cc..ecc90f9d 100644
--- a/kwant/digest.py
+++ b/kwant/digest.py
@@ -19,7 +19,7 @@ good enough to pass the "dieharder" battery of tests: see the function `test` of
 this module.
 """
 
-from __future__ import division
+
 
 from math import pi, log, sqrt, cos
 from hashlib import md5
@@ -96,8 +96,8 @@ def test(n=20000):
 
     f = tempfile.NamedTemporaryFile(delete=False)
     try:
-        for x in xrange(n):
-            for y in xrange(n):
+        for x in range(n):
+            for y in range(n):
                 a = array((x, y))
                 i = int(2**32 * uniform(a))
                 f.write(pack('I', i))
diff --git a/kwant/graph/__init__.py b/kwant/graph/__init__.py
index dc946344..29057770 100644
--- a/kwant/graph/__init__.py
+++ b/kwant/graph/__init__.py
@@ -11,6 +11,6 @@
 # Merge the public interface of all submodules.
 __all__ = []
 for module in ['core', 'defs', 'slicer', 'utils']:
-    exec 'from . import {0}'.format(module)
-    exec 'from .{0} import *'.format(module)
-    exec '__all__.extend({0}.__all__)'.format(module)
+    exec('from . import {0}'.format(module))
+    exec('from .{0} import *'.format(module))
+    exec('__all__.extend({0}.__all__)'.format(module))
diff --git a/kwant/graph/tests/test_core.py b/kwant/graph/tests/test_core.py
index 967ff6d8..14cdad0b 100644
--- a/kwant/graph/tests/test_core.py
+++ b/kwant/graph/tests/test_core.py
@@ -6,8 +6,8 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from StringIO import StringIO
-from itertools import izip_longest
+from io import StringIO
+from itertools import zip_longest
 import numpy as np
 from nose.tools import assert_equal, assert_raises
 from kwant.graph.core import (Graph, NodeDoesNotExistError,
@@ -41,12 +41,12 @@ def test_num_nodes():
 def test_large():
     num_edges = 1000
     graph = Graph()
-    for i in xrange(num_edges):
+    for i in range(num_edges):
         graph.add_edge(i, i + 1)
     g = graph.compressed()
     g2 = graph.compressed(twoway=True)
     assert_equal(num_edges, g.num_nodes - 1)
-    for i in xrange(num_edges):
+    for i in range(num_edges):
         assert_equal(tuple(g.out_neighbors(i)), (i + 1,))
         assert_equal(tuple(g2.in_neighbors(i + 1)), (i,))
 
@@ -71,7 +71,7 @@ def test_small():
     check_dot(dot_expect, g)
     g = g.compressed(twoway=True)
 
-    for edge_should, edge_is in izip_longest(edges, g):
+    for edge_should, edge_is in zip_longest(edges, g):
         assert_equal(edge_should, edge_is)
 
     edge_ids = []
diff --git a/kwant/graph/tests/test_dissection.py b/kwant/graph/tests/test_dissection.py
index cb8fc8f7..fb21fe78 100644
--- a/kwant/graph/tests/test_dissection.py
+++ b/kwant/graph/tests/test_dissection.py
@@ -19,13 +19,13 @@ def _DISABLED_test_edge_dissection():
     size = 5
     graph = Graph()
 
-    for i in xrange(size - 1):
+    for i in range(size - 1):
         offset = i * size
-        for j in xrange(size - 1):
+        for j in range(size - 1):
             graph.add_edge(offset + j, offset + j + 1)
             graph.add_edge(offset + j + 1, offset + j)
         if i > 0:
-            for j in xrange(size):
+            for j in range(size):
                 graph.add_edge(offset + j, offset + j - size)
                 graph.add_edge(offset + j - size, offset + j)
     g = graph.compressed()
diff --git a/kwant/graph/tests/test_scotch.py b/kwant/graph/tests/test_scotch.py
index 222ff05f..ca7e25af 100644
--- a/kwant/graph/tests/test_scotch.py
+++ b/kwant/graph/tests/test_scotch.py
@@ -17,32 +17,32 @@ def _DISABLED_test_bisect():
     size = 5
     graph = Graph()
 
-    for i in xrange(size-1):
+    for i in range(size-1):
         offset = i * size
-        for j in xrange(size-1):
+        for j in range(size-1):
             graph.add_edge(offset + j, offset + j + 1)
             graph.add_edge(offset + j + 1, offset + j)
         if i > 0:
-            for j in xrange(size):
+            for j in range(size):
                 graph.add_edge(offset + j, offset + j - size)
                 graph.add_edge(offset + j - size, offset + j)
     g = graph.compressed()
 
     parts = bisect(g)
-    for i in xrange(g.num_nodes):
+    for i in range(g.num_nodes):
         assert_true(parts[i] == 0 or parts[i] == 1)
 
 def _DISABLED_test_reset():
     size = 5
     graph = Graph()
 
-    for i in xrange(size-1):
+    for i in range(size-1):
         offset = i * size
-        for j in xrange(size-1):
+        for j in range(size-1):
             graph.add_edge(offset + j, offset + j + 1)
             graph.add_edge(offset + j + 1, offset + j)
         if i > 0:
-            for j in xrange(size):
+            for j in range(size):
                 graph.add_edge(offset + j, offset + j - size)
                 graph.add_edge(offset + j - size, offset + j)
     g = graph.compressed()
diff --git a/kwant/graph/tests/test_slicer.py b/kwant/graph/tests/test_slicer.py
index 29e549cb..2191310d 100644
--- a/kwant/graph/tests/test_slicer.py
+++ b/kwant/graph/tests/test_slicer.py
@@ -11,13 +11,13 @@ from kwant.graph import slicer
 
 def assert_sanity(graph, slices):
     # Slices must comprise all of the graph.
-    slclist = [slices[j][i] for j in xrange(len(slices))
-               for i in xrange(len(slices[j]))]
+    slclist = [slices[j][i] for j in range(len(slices))
+               for i in range(len(slices[j]))]
     slclist.sort()
-    assert slclist == [i for i in xrange(graph.num_nodes)]
+    assert slclist == [i for i in range(graph.num_nodes)]
 
     # Nodes may only have neighbors in neighboring slices.
-    for j in xrange(len(slices)):
+    for j in range(len(slices)):
         for node in slices[j]:
             for neigh in graph.out_neighbors(node):
                 if j > 0 and j < len(slices) - 1:
@@ -39,8 +39,8 @@ def test_rectangle():
         sys = kwant.Builder()
         lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
         lat = kwant.lattice.square()
-        lead[(lat(0, i) for i in xrange(w))] = 0
-        sys[(lat(j, i) for j in xrange(l) for i in xrange(w))] = 0
+        lead[(lat(0, i) for i in range(w))] = 0
+        sys[(lat(j, i) for j in range(l) for i in range(w))] = 0
         for s in [lead, sys]:
             for kind in [kwant.builder.HoppingKind((1, 0), lat),
                          kwant.builder.HoppingKind((0, 1), lat)]:
@@ -57,7 +57,7 @@ def test_rectangle():
         # we know that all slices must have the same shape.
         assert len(slices) == l
 
-        for j in xrange(l):
+        for j in range(l):
             assert len(slices[j]) == w
 
         assert_sanity(fsys.graph, slices)
diff --git a/kwant/graph/tests/test_utils.py b/kwant/graph/tests/test_utils.py
index bea187e5..ae7f3d22 100644
--- a/kwant/graph/tests/test_utils.py
+++ b/kwant/graph/tests/test_utils.py
@@ -83,7 +83,7 @@ def test_induced_subgraph():
     num_nodes = 6
 
     graph = Graph()
-    for i in xrange(num_nodes-1):
+    for i in range(num_nodes-1):
         graph.add_edge(i, i + 1)
     graph.add_edge(1, 0)
     g = graph.compressed()
diff --git a/kwant/lattice.py b/kwant/lattice.py
index 5b55b988..1f908473 100644
--- a/kwant/lattice.py
+++ b/kwant/lattice.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 
 __all__ = ['TranslationalSymmetry', 'general', 'Polyatomic', 'Monatomic',
            'chain', 'square', 'triangular', 'honeycomb', 'kagome']
@@ -617,7 +617,7 @@ class TranslationalSymmetry(builder.Symmetry):
 
         det_m = int(round(np.linalg.det(m)))
         if det_m == 0:
-            print m
+            print(m)
             raise RuntimeError('Adding site family failed.')
 
         det_x_inv_m = np.array(np.round(det_m * np.linalg.inv(m)), dtype=int)
diff --git a/kwant/linalg/__init__.py b/kwant/linalg/__init__.py
index ad60f34f..cd46cf5a 100644
--- a/kwant/linalg/__init__.py
+++ b/kwant/linalg/__init__.py
@@ -11,6 +11,6 @@ from . import lapack
 
 # Merge the public interface of the other submodules.
 for module in ['decomp_lu', 'decomp_ev', 'decomp_schur']:
-    exec 'from . import {0}'.format(module)
-    exec 'from .{0} import *'.format(module)
-    exec '__all__.extend({0}.__all__)'.format(module)
+    exec('from . import {0}'.format(module))
+    exec('from .{0} import *'.format(module))
+    exec('__all__.extend({0}.__all__)'.format(module))
diff --git a/kwant/linalg/decomp_lu.py b/kwant/linalg/decomp_lu.py
index 65bc0fd7..5f5f2ddc 100644
--- a/kwant/linalg/decomp_lu.py
+++ b/kwant/linalg/decomp_lu.py
@@ -61,7 +61,7 @@ def lu_factor(a, overwrite_a=False):
         return lapack.cgetrf(a)
 
 
-def lu_solve((lu, ipiv, singular), b):
+def lu_solve(xxx_todo_changeme, b):
     """Solve a linear system of equations, a x = b, given the LU
     factorization of a
 
@@ -77,7 +77,7 @@ def lu_solve((lu, ipiv, singular), b):
     x : array (vector or matrix)
         Solution to the system
     """
-
+    (lu, ipiv, singular) = xxx_todo_changeme
     if singular:
         raise RuntimeWarning("In lu_solve: the flag singular indicates "
                              "a singular matrix. Result of solve step "
@@ -102,7 +102,7 @@ def lu_solve((lu, ipiv, singular), b):
         return lapack.cgetrs(lu, ipiv, b)
 
 
-def rcond_from_lu((lu, ipiv, singular), norm_a, norm="1"):
+def rcond_from_lu(xxx_todo_changeme1, norm_a, norm="1"):
     """Compute the reciprocal condition number from the LU decomposition as
     returned from lu_factor(), given additionally the norm of the matrix a in
     norm_a.
@@ -126,7 +126,7 @@ def rcond_from_lu((lu, ipiv, singular), norm_a, norm="1"):
         reciprocal condition number of a with respect to the type of matrix
         norm specified in norm
     """
-
+    (lu, ipiv, singular) = xxx_todo_changeme1
     if not norm in ("1", "I"):
         raise ValueError("norm in rcond_from_lu must be either '1' or 'I'")
 
diff --git a/kwant/linalg/fortran_helpers.py b/kwant/linalg/fortran_helpers.py
index 2f82b26d..39ec639e 100644
--- a/kwant/linalg/fortran_helpers.py
+++ b/kwant/linalg/fortran_helpers.py
@@ -36,7 +36,7 @@ def prepare_for_fortran(overwrite, *args):
 
     # Make sure we have NumPy arrays
     mats = [None]*len(args)
-    for i in xrange(len(args)):
+    for i in range(len(args)):
         if args[i] is not None:
             arr = np.asanyarray(args[i])
             if not np.issubdtype(arr.dtype, np.number):
diff --git a/kwant/linalg/lll.py b/kwant/linalg/lll.py
index 17b353ca..3f170e38 100644
--- a/kwant/linalg/lll.py
+++ b/kwant/linalg/lll.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 
 __all__ = ['lll', 'cvp', 'voronoi']
 
@@ -68,7 +68,7 @@ def lll(basis, c=1.34):
     m = vecs.shape[0]
     u = np.identity(m)
     def ll_reduce(i):
-        for j in reversed(range(i)):
+        for j in reversed(list(range(i))):
             vecs[i] -= np.round(u[i, j]) * vecs[j]
             u[i] -= np.round(u[i, j]) * u[j]
 
diff --git a/kwant/linalg/mumps.py b/kwant/linalg/mumps.py
index cd28860a..956454e0 100644
--- a/kwant/linalg/mumps.py
+++ b/kwant/linalg/mumps.py
@@ -219,7 +219,7 @@ class MUMPSContext(object):
         if a.ndim != 2 or a.shape[0] != a.shape[1]:
             raise ValueError("Input matrix must be square!")
 
-        if not ordering in orderings.keys():
+        if not ordering in list(orderings.keys()):
             raise ValueError("Unknown ordering '"+ordering+"'!")
 
         dtype, row, col, data = _make_assembled_from_coo(a, overwrite_a)
@@ -470,7 +470,7 @@ def schur_complement(a, indices, ordering='auto', ooc=False, pivot_tol=0.01,
     if indices.ndim != 1:
         raise ValueError("Schur indices must be specified in a 1d array!")
 
-    if not ordering in orderings.keys():
+    if not ordering in list(orderings.keys()):
         raise ValueError("Unknown ordering '"+ordering+"'!")
 
     dtype, row, col, data = _make_assembled_from_coo(a, overwrite_a)
diff --git a/kwant/linalg/tests/_test_utils.py b/kwant/linalg/tests/_test_utils.py
index 8f76e815..5ada7637 100644
--- a/kwant/linalg/tests/_test_utils.py
+++ b/kwant/linalg/tests/_test_utils.py
@@ -43,16 +43,16 @@ class _Random:
         mat = np.empty((n, m), dtype = dtype)
 
         if issubclass(dtype, np.complexfloating):
-            for i in xrange(n):
-                for j in xrange(m):
+            for i in range(n):
+                for j in range(m):
                     mat[i,j] = self._randf() + 1j * self._randf()
         elif issubclass(dtype, np.floating):
-            for i in xrange(n):
-                for j in xrange(m):
+            for i in range(n):
+                for j in range(m):
                     mat[i,j] = self._randf()
         elif issubclass(dtype, np.integer):
-            for i in xrange(n):
-                for j in xrange(m):
+            for i in range(n):
+                for j in range(m):
                     mat[i,j] = self._randi()
 
         return mat
@@ -61,13 +61,13 @@ class _Random:
         vec = np.empty(n, dtype = dtype)
 
         if issubclass(dtype, np.complexfloating):
-            for i in xrange(n):
+            for i in range(n):
                 vec[i] = self._randf() + 1j * self._randf()
         elif issubclass(dtype, np.floating):
-            for i in xrange(n):
+            for i in range(n):
                 vec[i] = self._randf()
         elif issubclass(dtype, np.integer):
-            for i in xrange(n):
+            for i in range(n):
                 vec[i] = self._randi()
 
         return vec
diff --git a/kwant/linalg/tests/test_linalg.py b/kwant/linalg/tests/test_linalg.py
index f059580a..7b70728c 100644
--- a/kwant/linalg/tests/test_linalg.py
+++ b/kwant/linalg/tests/test_linalg.py
@@ -12,7 +12,7 @@ from kwant.linalg import (
     convert_r2c_gen_schur, order_gen_schur, evecs_from_gen_schur)
 from nose.tools import assert_equal, assert_true
 import numpy as np
-from _test_utils import _Random, assert_array_almost_equal
+from ._test_utils import _Random, assert_array_almost_equal
 
 def test_gen_eig():
     def _test_gen_eig(dtype):
diff --git a/kwant/linalg/tests/test_lll.py b/kwant/linalg/tests/test_lll.py
index e11627ae..cb048090 100644
--- a/kwant/linalg/tests/test_lll.py
+++ b/kwant/linalg/tests/test_lll.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 import numpy as np
 from kwant.linalg import lll
 
diff --git a/kwant/linalg/tests/test_mumps.py b/kwant/linalg/tests/test_mumps.py
index 8991a7d2..bfb5028a 100644
--- a/kwant/linalg/tests/test_mumps.py
+++ b/kwant/linalg/tests/test_mumps.py
@@ -17,7 +17,7 @@ from kwant.builder import Builder, HoppingKind
 from numpy.testing.decorators import skipif
 import numpy as np
 import scipy.sparse as sp
-from _test_utils import _Random, assert_array_almost_equal
+from ._test_utils import _Random, assert_array_almost_equal
 
 @skipif(no_mumps)
 def test_lu_with_dense():
@@ -53,7 +53,7 @@ def test_schur_complement_with_dense():
     def _test_schur_complement_with_dense(dtype):
         rand = _Random()
         a = rand.randmat(10, 10, dtype)
-        s = schur_complement(sp.coo_matrix(a), range(3))
+        s = schur_complement(sp.coo_matrix(a), list(range(3)))
         assert_array_almost_equal(dtype, np.linalg.inv(s),
                                   np.linalg.inv(a)[:3, :3])
 
diff --git a/kwant/physics/__init__.py b/kwant/physics/__init__.py
index 1c463828..10edc954 100644
--- a/kwant/physics/__init__.py
+++ b/kwant/physics/__init__.py
@@ -11,6 +11,6 @@
 # Merge the public interface of all submodules.
 __all__ = []
 for module in ['leads', 'dispersion', 'noise']:
-    exec 'from . import {0}'.format(module)
-    exec 'from .{0} import *'.format(module)
-    exec '__all__.extend({0}.__all__)'.format(module)
+    exec('from . import {0}'.format(module))
+    exec('from .{0} import *'.format(module))
+    exec('__all__.extend({0}.__all__)'.format(module))
diff --git a/kwant/physics/leads.py b/kwant/physics/leads.py
index 586eaaed..edacd0bf 100644
--- a/kwant/physics/leads.py
+++ b/kwant/physics/leads.py
@@ -6,10 +6,10 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 from math import sin, cos, sqrt, pi, copysign
 from collections import namedtuple
-from itertools import izip
+
 import numpy as np
 import numpy.linalg as npl
 import scipy.linalg as la
@@ -434,7 +434,7 @@ def make_proper_modes(lmbdainv, psi, extract, tol=1e6):
     if boundaries.shape == (0,) and len(angles):
         boundaries = np.array([0, len(angles)])
 
-    for interval in izip(boundaries[:-1], boundaries[1:]):
+    for interval in zip(boundaries[:-1], boundaries[1:]):
         if interval[1] > boundaries[0] + len(angles):
             break
 
@@ -661,8 +661,8 @@ def square_selfenergy(width, hopping, fermi_energy):
     psi_p_i = np.empty((width, width))
     factor = pi / (width + 1)
     prefactor = sqrt(2 / (width + 1))
-    for p in xrange(width):
-        for i in xrange(width):
+    for p in range(width):
+        for i in range(width):
             psi_p_i[p, i] = prefactor * sin(factor * (p + 1) * (i + 1))
 
     # Precalculate the integrals of the longitudinal wave functions.
@@ -672,15 +672,15 @@ def square_selfenergy(width, hopping, fermi_energy):
         else:
             return q/2 - copysign(sqrt((q / 2) ** 2 - 1), q)
     f_p = np.empty((width,), dtype=complex)
-    for p in xrange(width):
+    for p in range(width):
         e = 2 * hopping * (1 - cos(factor * (p + 1)))
         q = (fermi_energy - e) / hopping - 2
         f_p[p] = f(q)
 
     # Put everything together into the self energy and return it.
     result = np.empty((width, width), dtype=complex)
-    for i in xrange(width):
-        for j in xrange(width):
+    for i in range(width):
+        for j in range(width):
             result[i, j] = hopping * (
                 psi_p_i[:, i] * psi_p_i[:, j].conj() * f_p).sum()
     return result
diff --git a/kwant/physics/tests/test_leads.py b/kwant/physics/tests/test_leads.py
index fb7a5b33..15da9dc3 100644
--- a/kwant/physics/tests/test_leads.py
+++ b/kwant/physics/tests/test_leads.py
@@ -6,9 +6,9 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 import numpy as np
-from itertools import product, izip
+from itertools import product
 from numpy.testing import assert_almost_equal
 from kwant.physics import leads
 import kwant
@@ -273,14 +273,14 @@ def test_algorithm_equivalence():
         evan_vecs.append(full_vecs[:, 2 * result.nmodes :])
 
     msg = 'Stabilization {0} failed.'
-    for vecs, algo in izip(prop_vecs, algos):
+    for vecs, algo in zip(prop_vecs, algos):
         # Propagating modes should have identical ordering, and only vary
         # By a phase
         np.testing.assert_allclose(np.abs(np.sum(vecs/prop_vecs[0],
                                                  axis=0)), vecs.shape[0],
                                    err_msg=msg.format(algo))
 
-    for vecs, algo in izip(evan_vecs, algos):
+    for vecs, algo in zip(evan_vecs, algos):
         # Evanescent modes must span the same linear space.
         assert (np.linalg.matrix_rank(np.c_[vecs, evan_vecs[0]], tol=1e-12) ==
                 vecs.shape[1]), msg.format(algo)
diff --git a/kwant/plotter.py b/kwant/plotter.py
index 42ba2bfb..a2495d5d 100644
--- a/kwant/plotter.py
+++ b/kwant/plotter.py
@@ -69,7 +69,7 @@ if mpl_enabled:
 # Collections that allow for symbols and linewiths to be given in data space
 # (not for general use, only implement what's needed for plotter)
 def isarray(var):
-    if hasattr(var, '__getitem__') and not isinstance(var, basestring):
+    if hasattr(var, '__getitem__') and not isinstance(var, str):
         return True
     else:
         return False
@@ -717,18 +717,18 @@ def sys_leads_sites(sys, num_lead_cells=2):
             if hasattr(lead, 'builder') and len(lead.interface):
                 sites.extend(((site, leadnr, i) for site in
                               lead.builder.sites() for i in
-                              xrange(num_lead_cells)))
+                              range(num_lead_cells)))
             lead_cells.append(slice(start, len(sites)))
     elif isinstance(sys, system.FiniteSystem):
-        sites = [(i, None, 0) for i in xrange(sys.graph.num_nodes)]
+        sites = [(i, None, 0) for i in range(sys.graph.num_nodes)]
         for leadnr, lead in enumerate(sys.leads):
             start = len(sites)
             # We will only plot leads with a graph and with a symmetry.
             if (hasattr(lead, 'graph') and hasattr(lead, 'symmetry') and
                 len(sys.lead_interfaces[leadnr])):
                 sites.extend(((site, leadnr, i) for site in
-                              xrange(lead.cell_size) for i in
-                              xrange(num_lead_cells)))
+                              range(lead.cell_size) for i in
+                              range(num_lead_cells)))
             lead_cells.append(slice(start, len(sites)))
     else:
         raise TypeError('Unrecognized system type.')
@@ -796,10 +796,10 @@ def sys_leads_pos(sys, site_lead_nr):
         # Conversion to numpy array here useful for efficiency
         vec = np.array(sym.periods)[0]
         return vec, dom
-    vecs_doms = dict((i, get_vec_domain(i)) for i in xrange(len(sys.leads)))
+    vecs_doms = dict((i, get_vec_domain(i)) for i in range(len(sys.leads)))
     vecs_doms[None] = np.zeros((dim,)), 0
-    for k, v in vecs_doms.iteritems():
-        vecs_doms[k] = [v[0] * i for i in xrange(v[1], v[1] + num_lead_cells)]
+    for k, v in vecs_doms.items():
+        vecs_doms[k] = [v[0] * i for i in range(v[1], v[1] + num_lead_cells)]
     pos += [vecs_doms[i[1]][i[2]] for i in site_lead_nr]
     return pos
 
@@ -856,11 +856,11 @@ def sys_leads_hoppings(sys, num_lead_cells=2):
             if hasattr(lead, 'builder') and len(lead.interface):
                 hoppings.extend(((hop, leadnr, i) for hop in
                                  lead_hoppings(lead.builder) for i in
-                                 xrange(num_lead_cells)))
+                                 range(num_lead_cells)))
             lead_cells.append(slice(start, len(hoppings)))
     elif isinstance(sys, system.System):
         def ll_hoppings(sys):
-            for i in xrange(sys.graph.num_nodes):
+            for i in range(sys.graph.num_nodes):
                 for j in sys.graph.out_neighbors(i):
                     if i < j:
                         yield i, j
@@ -872,7 +872,7 @@ def sys_leads_hoppings(sys, num_lead_cells=2):
             if (hasattr(lead, 'graph') and hasattr(lead, 'symmetry') and
                 len(sys.lead_interfaces[leadnr])):
                 hoppings.extend(((hop, leadnr, i) for hop in ll_hoppings(lead)
-                                 for i in xrange(num_lead_cells)))
+                                 for i in range(num_lead_cells)))
             lead_cells.append(slice(start, len(hoppings)))
     else:
         raise TypeError('Unrecognized system type.')
@@ -942,10 +942,10 @@ def sys_leads_hopping_pos(sys, hop_lead_nr):
         vec = np.array(sym.periods)[0]
         return np.r_[vec, vec], dom
 
-    vecs_doms = dict((i, get_vec_domain(i)) for i in xrange(len(sys.leads)))
+    vecs_doms = dict((i, get_vec_domain(i)) for i in range(len(sys.leads)))
     vecs_doms[None] = np.zeros((dim,)), 0
-    for k, v in vecs_doms.iteritems():
-        vecs_doms[k] = [v[0] * i for i in xrange(v[1], v[1] + num_lead_cells)]
+    for k, v in vecs_doms.items():
+        vecs_doms[k] = [v[0] * i for i in range(v[1], v[1] + num_lead_cells)]
     pos += [vecs_doms[i[1]][i[2]] for i in hop_lead_nr]
     return np.copy(pos[:, : dim / 2]), np.copy(pos[:, dim / 2:])
 
@@ -1136,7 +1136,7 @@ def plot(sys, num_lead_cells=2, unit='nn',
         if name in ('site_size', 'site_lw') and isinstance(value, tuple):
             raise TypeError('{0} may not be a tuple, use list or '
                             'array instead.'.format(name))
-        if isinstance(value, (basestring, tuple)):
+        if isinstance(value, (str, tuple)):
             return
         try:
             if len(value) != n_sys_sites:
@@ -1195,7 +1195,7 @@ def plot(sys, num_lead_cells=2, unit='nn',
 
     # make all specs proper: either constant or lists/np.arrays:
     def make_proper_site_spec(spec, fancy_indexing=False):
-        if callable(spec):
+        if isinstance(spec, collections.Callable):
             spec = [spec(i[0]) for i in sites if i[1] is None]
         if (fancy_indexing and isarray(spec)
             and not isinstance(spec, np.ndarray)):
@@ -1206,7 +1206,7 @@ def plot(sys, num_lead_cells=2, unit='nn',
         return spec
 
     def make_proper_hop_spec(spec, fancy_indexing=False):
-        if callable(spec):
+        if isinstance(spec, collections.Callable):
             spec = [spec(*i[0]) for i in hops if i[1] is None]
         if (fancy_indexing and isarray(spec)
             and not isinstance(spec, np.ndarray)):
@@ -1226,7 +1226,7 @@ def plot(sys, num_lead_cells=2, unit='nn',
         for i, symbol in enumerate(site_symbol):
             symbol_dict[symbol].append(i)
         symbol_slcs = []
-        for symbol, indx in symbol_dict.iteritems():
+        for symbol, indx in symbol_dict.items():
             symbol_slcs.append((symbol, np.array(indx)))
         fancy_indexing = True
     else:
@@ -1285,7 +1285,7 @@ def plot(sys, num_lead_cells=2, unit='nn',
                        else defaults['hop_lw'][dim])
 
     hop_cmap = None
-    if not isinstance(cmap, basestring):
+    if not isinstance(cmap, str):
         try:
             cmap, hop_cmap = cmap
         except TypeError:
@@ -1537,7 +1537,7 @@ def map(sys, value, colorbar=True, cmap=None, vmin=None, vmax=None, a=None,
     if coords.shape[1] != 2:
         raise ValueError('Only 2D systems can be plotted this way.')
 
-    if callable(value):
+    if isinstance(value, collections.Callable):
         value = [value(site[0]) for site in sites]
     else:
         if not isinstance(sys, system.FiniteSystem):
diff --git a/kwant/rmt.py b/kwant/rmt.py
index cff30d4f..1d307f66 100644
--- a/kwant/rmt.py
+++ b/kwant/rmt.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 
 __all__ = ['gaussian', 'circular']
 
diff --git a/kwant/solvers/common.py b/kwant/solvers/common.py
index d74a9473..0d59ce55 100644
--- a/kwant/solvers/common.py
+++ b/kwant/solvers/common.py
@@ -15,6 +15,7 @@ import numpy as np
 import scipy.sparse as sp
 from .._common import ensure_isinstance
 from .. import system
+from functools import reduce
 
 # Currently, scipy.sparse does not support matrices with one dimension being
 # zero: http://projects.scipy.org/scipy/ticket/1602 We use NumPy dense matrices
@@ -28,7 +29,7 @@ from .. import system
 LinearSys = namedtuple('LinearSys', ['lhs', 'rhs', 'indices', 'num_orb'])
 
 
-class SparseSolver(object):
+class SparseSolver(object, metaclass=abc.ABCMeta):
     """Solver class for computing physical quantities based on solving
     a liner system of equations.
 
@@ -51,7 +52,6 @@ class SparseSolver(object):
       too avoid excessive memory usage, but for some solvers not too small for
       performance reasons.
     """
-    __metaclass__ = abc.ABCMeta
 
     @abc.abstractmethod
     def _factorized(self, a):
@@ -333,11 +333,11 @@ class SparseSolver(object):
 
         n = len(sys.lead_interfaces)
         if in_leads is None:
-            in_leads = range(n)
+            in_leads = list(range(n))
         else:
             in_leads = list(in_leads)
         if out_leads is None:
-            out_leads = range(n)
+            out_leads = list(range(n))
         else:
             out_leads = list(out_leads)
         if (np.any(np.diff(in_leads) <= 0) or np.any(np.diff(out_leads) <= 0)):
@@ -420,11 +420,11 @@ class SparseSolver(object):
 
         n = len(sys.lead_interfaces)
         if in_leads is None:
-            in_leads = range(n)
+            in_leads = list(range(n))
         else:
             in_leads = list(in_leads)
         if out_leads is None:
-            out_leads = range(n)
+            out_leads = list(range(n))
         else:
             out_leads = list(out_leads)
         if (np.any(np.diff(in_leads) <= 0) or np.any(np.diff(out_leads) <= 0)):
@@ -489,7 +489,7 @@ class SparseSolver(object):
                 raise NotImplementedError("ldos for leads with only "
                                           "self-energy is not implemented yet.")
 
-        linsys = self._make_linear_sys(sys, xrange(len(sys.leads)), energy,
+        linsys = self._make_linear_sys(sys, range(len(sys.leads)), energy,
                                        args, check_hermiticity)[0]
 
         ldos = np.zeros(linsys.num_orb, float)
@@ -503,7 +503,7 @@ class SparseSolver(object):
         # See comment about zero-shaped sparse matrices at the top of common.py.
         rhs = sp.bmat([[i for i in linsys.rhs if i.shape[1]]],
                       format=self.rhsformat)
-        for j in xrange(0, rhs.shape[1], self.nrhs):
+        for j in range(0, rhs.shape[1], self.nrhs):
             jend = min(j + self.nrhs, rhs.shape[1])
             psi = self._solve_linear_sys(factored, rhs[:, j:jend],
                                          slice(linsys.num_orb))
@@ -555,7 +555,7 @@ class WaveFunction(object):
                 msg = ('Wave functions for leads with only self-energy'
                        ' are not available yet.')
                 raise NotImplementedError(msg)
-        linsys = solver._make_linear_sys(sys, xrange(len(sys.leads)), energy,
+        linsys = solver._make_linear_sys(sys, range(len(sys.leads)), energy,
                                          args, check_hermiticity)[0]
         self.solve = solver._solve_linear_sys
         self.rhs = linsys.rhs
@@ -568,11 +568,10 @@ class WaveFunction(object):
         return result.transpose()
 
 
-class BlockResult(object):
+class BlockResult(object, metaclass=abc.ABCMeta):
     """
     ABC for a linear system solution with variable grouping.
     """
-    __metaclass__ = abc.ABCMeta
 
     def __init__(self, data, lead_info, out_leads, in_leads, sizes,
                  current_conserving=False):
@@ -676,7 +675,7 @@ class BlockResult(object):
         Section 2.4 of the book by S. Datta.
         """
         n = len(self.lead_info)
-        rn = xrange(n)
+        rn = range(n)
         result = np.array([[-self.transmission(i, j) if i != j else 0
                             for j in rn] for i in rn])
         # Set the diagonal elements such that the sums of columns are zero.
diff --git a/kwant/solvers/mumps.py b/kwant/solvers/mumps.py
index fc4b0e8a..d672c4a1 100644
--- a/kwant/solvers/mumps.py
+++ b/kwant/solvers/mumps.py
@@ -84,7 +84,7 @@ class Solver(common.SparseSolver):
             self.nrhs = nrhs
 
         if ordering is not None:
-            if ordering not in mumps.orderings.keys() + ['kwant_decides']:
+            if ordering not in list(mumps.orderings.keys()) + ['kwant_decides']:
                 raise ValueError("Invalid ordering: " + ordering)
             if ordering == 'kwant_decides':
                 # Choose what is considered to be the best ordering.
@@ -111,7 +111,7 @@ class Solver(common.SparseSolver):
         solve = factorized_a.solve
         sols = []
 
-        for j in xrange(0, b.shape[1], self.nrhs):
+        for j in range(0, b.shape[1], self.nrhs):
             tmprhs = b[:, j:min(j + self.nrhs, b.shape[1])]
 
             if not self.sparse_rhs:
diff --git a/kwant/solvers/sparse.py b/kwant/solvers/sparse.py
index 044ebc26..69f9a3a8 100644
--- a/kwant/solvers/sparse.py
+++ b/kwant/solvers/sparse.py
@@ -110,7 +110,7 @@ class Solver(common.SparseSolver):
 
         sols = []
         vec = np.empty(b.shape[0], complex)
-        for j in xrange(b.shape[1]):
+        for j in range(b.shape[1]):
             vec[:] = b[:, j].todense().flatten()
             sols.append(factorized_a(vec)[kept_vars])
 
diff --git a/kwant/solvers/tests/_test_sparse.py b/kwant/solvers/tests/_test_sparse.py
index 5eaa20b1..3c26d263 100644
--- a/kwant/solvers/tests/_test_sparse.py
+++ b/kwant/solvers/tests/_test_sparse.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 from math import cos, sin
 import numpy as np
 from nose.tools import assert_raises
@@ -263,18 +263,18 @@ def test_tricky_singular_hopping(smatrix):
     lead = kwant.Builder(kwant.TranslationalSymmetry((4, 0)))
 
     interface = []
-    for i in xrange(n):
+    for i in range(n):
         site = sq(-1, i)
         interface.append(site)
         system[site] = 0
-        for j in xrange(4):
+        for j in range(4):
             lead[sq(j, i)] = 0
-    for i in xrange(n-1):
+    for i in range(n-1):
         system[sq(-1, i), sq(-1, i+1)] = -1
-        for j in xrange(4):
+        for j in range(4):
             lead[sq(j, i), sq(j, i+1)] = -1
-    for i in xrange(n):
-        for j in xrange(4):
+    for i in range(n):
+        for j in range(4):
             lead[sq(j, i), sq(j+1, i)] = -1
     del lead[sq(1, 0), sq(2, 0)]
 
@@ -300,10 +300,10 @@ def test_many_leads(*factories):
 
     # Build a square system with four leads and a hole in the center.
     sys = kwant.Builder()
-    sys[(sq(x, y) for x in xrange(-4, 4) for y in xrange(-4, 4)
+    sys[(sq(x, y) for x in range(-4, 4) for y in range(-4, 4)
          if x**2 + y**2 >= 2)] = 3
     sys[sq.neighbors()] = phase
-    for r in [xrange(-4, -1), xrange(4)]:
+    for r in [range(-4, -1), range(4)]:
         lead = kwant.Builder(kwant.TranslationalSymmetry([-1, 0]))
         lead[(sq(0, y) for y in r)] = 4
         lead[sq.neighbors()] = phase
@@ -311,7 +311,7 @@ def test_many_leads(*factories):
         sys.attach_lead(lead.reversed())
     sys = sys.finalized()
 
-    r4 = range(4)
+    r4 = list(range(4))
     br = factories[0](sys, E, out_leads=r4, in_leads=r4)
     trans = np.array([[br._transmission(i, j) for j in r4] for i in r4])
     cmat = br.conductance_matrix()
@@ -480,7 +480,7 @@ def test_wavefunc_ldos_consistency(wave_function, ldos):
         for energy in [0, 1000]:
             wf = wave_function(sys, energy)
             ldos2 = np.zeros(wf.num_orb, float)
-            for lead in xrange(len(sys.leads)):
+            for lead in range(len(sys.leads)):
                 temp = abs(wf(lead))
                 temp **= 2
                 ldos2 += temp.sum(axis=0)
diff --git a/kwant/solvers/tests/test_mumps.py b/kwant/solvers/tests/test_mumps.py
index a185a04c..e07aa120 100644
--- a/kwant/solvers/tests/test_mumps.py
+++ b/kwant/solvers/tests/test_mumps.py
@@ -11,7 +11,7 @@ from numpy.testing.decorators import skipif
 try:
     from kwant.solvers.mumps import (
         smatrix, greens_function, ldos, wave_function, options, reset_options)
-    import _test_sparse
+    from . import _test_sparse
     no_mumps = False
 except ImportError:
     no_mumps = True
diff --git a/kwant/solvers/tests/test_sparse.py b/kwant/solvers/tests/test_sparse.py
index c9920f9d..f93d7771 100644
--- a/kwant/solvers/tests/test_sparse.py
+++ b/kwant/solvers/tests/test_sparse.py
@@ -9,7 +9,7 @@
 from nose.plugins.skip import SkipTest
 from  kwant.solvers.sparse import smatrix, greens_function, ldos, wave_function
 import kwant.solvers.sparse
-import _test_sparse
+from . import _test_sparse
 
 def test_output():
     _test_sparse.test_output(smatrix)
diff --git a/kwant/system.py b/kwant/system.py
index a323eebe..ec68b9bf 100644
--- a/kwant/system.py
+++ b/kwant/system.py
@@ -8,7 +8,7 @@
 
 """Low-level interface of systems"""
 
-from __future__ import division
+
 __all__ = ['System', 'FiniteSystem', 'InfiniteSystem']
 
 import abc
@@ -17,7 +17,7 @@ from copy import copy
 from . import _system
 
 
-class System(object):
+class System(object, metaclass=abc.ABCMeta):
     """Abstract general low-level system.
 
     Attributes
@@ -33,7 +33,6 @@ class System(object):
     Optionally, a class derived from `System` can provide a method `pos` which
     is assumed to return the real-space position of a site given its index.
     """
-    __metaclass__ = abc.ABCMeta
 
     @abc.abstractmethod
     def hamiltonian(self, i, j, *args):
@@ -53,7 +52,7 @@ System.hamiltonian_submatrix = types.MethodType(
     _system.hamiltonian_submatrix, None, System)
 
 
-class FiniteSystem(System):
+class FiniteSystem(System, metaclass=abc.ABCMeta):
     """Abstract finite low-level system, possibly with leads.
 
     Attributes
@@ -80,7 +79,6 @@ class FiniteSystem(System):
     the first ``len(lead_interfaces[n])`` sites of the InfiniteSystem.
 
     """
-    __metaclass__ = abc.ABCMeta
 
     def precalculate(self, energy=0, args=(), leads=None,
                      what='modes'):
@@ -123,7 +121,7 @@ class FiniteSystem(System):
 
         result = copy(self)
         if leads is None:
-            leads = range(len(self.leads))
+            leads = list(range(len(self.leads)))
         new_leads = []
         for nr, lead in enumerate(self.leads):
             if nr not in leads:
@@ -141,7 +139,7 @@ class FiniteSystem(System):
         result.leads = new_leads
         return result
 
-class InfiniteSystem(System):
+class InfiniteSystem(System, metaclass=abc.ABCMeta):
     """
     Abstract infinite low-level system.
 
@@ -183,18 +181,17 @@ class InfiniteSystem(System):
     infinite system.  The other scheme has the numbers of site 0 and 1
     exchanged, as well as of site 3 and 4.
     """
-    __metaclass__ = abc.ABCMeta
 
     def cell_hamiltonian(self, args=(), sparse=False):
         """Hamiltonian of a single cell of the infinite system."""
-        cell_sites = xrange(self.cell_size)
+        cell_sites = range(self.cell_size)
         return self.hamiltonian_submatrix(args, cell_sites, cell_sites,
                                           sparse=sparse)
 
     def inter_cell_hopping(self, args=(), sparse=False):
         """Hopping Hamiltonian between two cells of the infinite system."""
-        cell_sites = xrange(self.cell_size)
-        interface_sites = xrange(self.cell_size, self.graph.num_nodes)
+        cell_sites = range(self.cell_size)
+        interface_sites = range(self.cell_size, self.graph.num_nodes)
         return self.hamiltonian_submatrix(args, cell_sites, interface_sites,
                                           sparse=sparse)
 
diff --git a/kwant/tests/test_builder.py b/kwant/tests/test_builder.py
index d60d0884..6b18541d 100644
--- a/kwant/tests/test_builder.py
+++ b/kwant/tests/test_builder.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 import warnings
 from random import Random
 from nose.tools import assert_raises
@@ -84,7 +84,7 @@ def test_bad_keys():
                     try:
                         assert_raises(error, func, key)
                     except AssertionError:
-                        print func, error, key
+                        print(func, error, key)
                         raise
 
 
@@ -259,14 +259,14 @@ def random_hopping_integral(rng):
 
 def check_onsite(fsys, sites, subset=False, check_values=True):
     freq = {}
-    for node in xrange(fsys.graph.num_nodes):
+    for node in range(fsys.graph.num_nodes):
         site = fsys.sites[node].tag
         freq[site] = freq.get(site, 0) + 1
         if check_values and site in sites:
             assert fsys.onsite_hamiltonians[node] is sites[site]
     if not subset:
         # Check that all sites of `fsys` are in `sites`.
-        for site in freq.iterkeys():
+        for site in freq.keys():
             assert site in sites
     # Check that all sites of `sites` are in `fsys`.
     for site in sites:
@@ -327,7 +327,7 @@ def test_finalization():
     set_hops(lead_hops, lead_sites)
     lead_sites_list = list(lead_sites)
     neighbors = set()
-    for i in xrange(n_hops):
+    for i in range(n_hops):
         while True:
             a = rng.choice(lead_sites_list)
             b = rng.choice(possible_neighbors)
@@ -343,9 +343,9 @@ def test_finalization():
     # Build scattering region from blueprint and test it.
     sys = builder.Builder()
     fam = kwant.lattice.general(ta.identity(2))
-    for site, value in sr_sites.iteritems():
+    for site, value in sr_sites.items():
         sys[fam(*site)] = value
-    for hop, value in sr_hops.iteritems():
+    for hop, value in sr_hops.items():
         sys[fam(*hop[0]), fam(*hop[1])] = value
     fsys = sys.finalized()
     check_onsite(fsys, sr_sites)
@@ -353,7 +353,7 @@ def test_finalization():
 
     # Build lead from blueprint and test it.
     lead = builder.Builder(kwant.TranslationalSymmetry((size, 0)))
-    for site, value in lead_sites.iteritems():
+    for site, value in lead_sites.items():
         shift = rng.randrange(-5, 6) * size
         site = site[0] + shift, site[1]
         lead[fam(*site)] = value
@@ -363,7 +363,7 @@ def test_finalization():
         assert_equal(len(w), 1)
         assert issubclass(w[0].category, RuntimeWarning)
         assert "disconnected" in str(w[0].message)
-    for (a, b), value in lead_hops.iteritems():
+    for (a, b), value in lead_hops.items():
         shift = rng.randrange(-5, 6) * size
         a = a[0] + shift, a[1]
         b = b[0] + shift, b[1]
@@ -645,21 +645,21 @@ def test_ModesLead_and_SelfEnergyLead():
     energies = [0.9, 1.7]
 
     sys = builder.Builder()
-    for x in xrange(L):
-        for y in xrange(L):
+    for x in range(L):
+        for y in range(L):
             sys[lat(x, y)] = 4 * t + rng.random() - 0.5
     sys[hoppings] = -t
 
     # Attach a lead from the left.
     lead = builder.Builder(VerySimpleSymmetry(-1))
-    for y in xrange(L):
+    for y in range(L):
         lead[lat(0, y)] = 4 * t
     lead[hoppings] = -t
     sys.attach_lead(lead)
 
     # Make the right lead and attach it.
     lead = builder.Builder(VerySimpleSymmetry(1))
-    for y in xrange(L):
+    for y in range(L):
         lead[lat(0, y)] = 4 * t
     lead[hoppings] = -t
     sys.attach_lead(lead)
@@ -669,7 +669,7 @@ def test_ModesLead_and_SelfEnergyLead():
 
     # Replace lead with it's finalized copy.
     lead = fsys.leads[1]
-    interface = [lat(L-1, lead.sites[i].tag[1]) for i in xrange(L)]
+    interface = [lat(L-1, lead.sites[i].tag[1]) for i in range(L)]
 
     # Re-attach right lead as ModesLead.
     sys.leads[1] = builder.ModesLead(lead.modes, interface)
diff --git a/kwant/tests/test_lattice.py b/kwant/tests/test_lattice.py
index 5b389d37..a9f8a94a 100644
--- a/kwant/tests/test_lattice.py
+++ b/kwant/tests/test_lattice.py
@@ -6,7 +6,7 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
-from __future__ import division
+
 from math import sqrt
 import numpy as np
 import tinyarray as ta
@@ -63,15 +63,15 @@ def test_shape():
     sites = list(lat.shape(in_circle, (0, 0))())
     sites_alt = list()
     sl0, sl1 = lat.sublattices
-    for x in xrange(-2, 3):
-        for y in xrange(-2, 3):
+    for x in range(-2, 3):
+        for y in range(-2, 3):
             tag = (x, y)
             for site in (sl0(*tag), sl1(*tag)):
                 if in_circle(site.pos):
                     sites_alt.append(site)
     assert len(sites) == len(sites_alt)
     assert_equal(set(sites), set(sites_alt))
-    assert_raises(ValueError, lat.shape(in_circle, (10, 10))().next)
+    assert_raises(ValueError, lat.shape(in_circle, (10, 10))().__next__)
 
     # Check if narrow ribbons work.
     for period in (0, 1), (1, 0), (1, -1):
diff --git a/kwant/tests/test_plotter.py b/kwant/tests/test_plotter.py
index d3074b0c..e34d1aeb 100644
--- a/kwant/tests/test_plotter.py
+++ b/kwant/tests/test_plotter.py
@@ -31,7 +31,7 @@ def test_importable_without_matplotlib():
 
     with warnings.catch_warnings(record=True) as w:
         warnings.simplefilter("always")
-        exec code               # Trigger the warning.
+        exec(code)               # Trigger the warning.
         nose.tools.assert_equal(len(w), 1)
         assert issubclass(w[0].category, RuntimeWarning)
         assert "only iterator-providing functions" in str(w[0].message)
@@ -103,7 +103,7 @@ def test_plot():
             for sys in (sys2d, sys3d):
                 fig = plot(sys, site_color=color, cmap='binary', file=out)
                 if (color != 'k' and
-                    isinstance(color(iter(sys2d.sites()).next()), float)):
+                    isinstance(color(next(iter(sys2d.sites()))), float)):
                     assert fig.axes[0].collections[0].get_array() is not None
                 assert len(fig.axes[0].collections) == (8 if sys is sys2d else
                                                         6)
@@ -114,7 +114,7 @@ def test_plot():
             for sys in (sys2d, sys3d):
                 fig = plot(sys2d, hop_color=color, cmap='binary', file=out,
                            fig_size=(2, 10), dpi=30)
-                if color != 'k' and isinstance(color(iter(sys2d.sites()).next(),
+                if color != 'k' and isinstance(color(next(iter(sys2d.sites())),
                                                           None), float):
                     assert fig.axes[0].collections[1].get_array() is not None
 
@@ -150,10 +150,10 @@ def test_map():
                                  pos_transform=bad_transform, file=out)
         with warnings.catch_warnings():
             warnings.simplefilter("ignore")
-            plotter.map(sys.finalized(), xrange(len(sys.sites())),
+            plotter.map(sys.finalized(), range(len(sys.sites())),
                               file=out)
         nose.tools.assert_raises(ValueError, plotter.map, sys,
-                                 xrange(len(sys.sites())), file=out)
+                                 range(len(sys.sites())), file=out)
 
 
 def test_mask_interpolate():
diff --git a/kwant/tests/test_system.py b/kwant/tests/test_system.py
index 29af26c2..3eb1e15b 100644
--- a/kwant/tests/test_system.py
+++ b/kwant/tests/test_system.py
@@ -14,9 +14,9 @@ import kwant
 def test_hamiltonian_submatrix():
     sys = kwant.Builder()
     chain = kwant.lattice.chain()
-    for i in xrange(3):
+    for i in range(3):
         sys[chain(i)] = 0.5 * i
-    for i in xrange(2):
+    for i in range(2):
         sys[chain(i), chain(i + 1)] = 1j * (i + 1)
 
     sys2 = sys.finalized()
@@ -87,8 +87,8 @@ def test_hamiltonian_submatrix():
         return p1 - p2
 
     sys = kwant.Builder()
-    sys[(chain(i) for i in xrange(3))] = onsite
-    sys[((chain(i), chain(i + 1)) for i in xrange(2))] = hopping
+    sys[(chain(i) for i in range(3))] = onsite
+    sys[((chain(i), chain(i + 1)) for i in range(2))] = hopping
     sys2 = sys.finalized()
     mat = sys2.hamiltonian_submatrix((2, 1))
     mat_should_be = [[3, 1, 0], [1, 4, 1], [0, 1, 5]]
-- 
GitLab