From 35af43352b9d9f609c2cd4cfed8e4455d957d6e2 Mon Sep 17 00:00:00 2001
From: Joseph Weston <joseph.weston@cea.fr>
Date: Fri, 7 Aug 2015 19:43:00 +0200
Subject: [PATCH] add workaround for Python 3's lack of unbound methods

Unbound methods are not longer a thing in Python 3 [1].  Instead,
functions use the descriptor protocol [2] to properly bind the `self`
argument if they are being called as a method. Cython functions do not
have a `__get__` attribute and so don't satisfy the descriptor
protocol. They therefore can't be used as methods. As a workaround we
create a wrapper class with the proper __get__ method. The advantage of
this over creating a Python wrapper is that the function signature is
preserved.

[1]: https://docs.python.org/3.0/whatsnew/3.0.html
[2]: https://docs.python.org/3/howto/descriptor.html
---
 kwant/_system.pyx | 11 +++++++++++
 kwant/system.py   |  3 +--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/kwant/_system.pyx b/kwant/_system.pyx
index dc3e665d..396b9175 100644
--- a/kwant/_system.pyx
+++ b/kwant/_system.pyx
@@ -11,6 +11,7 @@ import tinyarray as ta
 import numpy as np
 from scipy import sparse as sp
 from itertools import chain
+import types
 
 from .graph.core cimport CGraph, gintArraySlice
 from .graph.defs cimport gint
@@ -327,3 +328,13 @@ def hamiltonian_submatrix(self, args=(), to_sites=None, from_sites=None,
         mat = func(ham, args, self.graph, diag, from_sites,
                    n_by_to_site, to_norb, to_off, from_norb, from_off)
     return (mat, to_norb, from_norb) if return_norb else mat
+
+# workaround for Cython functions not having __get__ and
+# Python 3 getting rid of unbound methods
+cdef class HamiltonianSubmatrix:
+
+    def __get__(self, obj, objtype):
+        if obj is None:
+            return hamiltonian_submatrix
+        else:
+            return types.MethodType(hamiltonian_submatrix, obj)
diff --git a/kwant/system.py b/kwant/system.py
index ec68b9bf..45d0b473 100644
--- a/kwant/system.py
+++ b/kwant/system.py
@@ -48,8 +48,7 @@ class System(object, metaclass=abc.ABCMeta):
         pass
 
 # Add a C-implemented function as an unbound method to class System.
-System.hamiltonian_submatrix = types.MethodType(
-    _system.hamiltonian_submatrix, None, System)
+System.hamiltonian_submatrix = _system.HamiltonianSubmatrix()
 
 
 class FiniteSystem(System, metaclass=abc.ABCMeta):
-- 
GitLab