[med-svn] [Git][med-team/python-leidenalg][master] 5 commits: New upstream version 0.8.6

Nilesh Patra (@nilesh) gitlab at salsa.debian.org
Sat Jul 3 15:01:46 BST 2021



Nilesh Patra pushed to branch master at Debian Med / python-leidenalg


Commits:
47869354 by Nilesh Patra at 2021-07-03T19:03:00+05:30
New upstream version 0.8.6
- - - - -
b5d3a03a by Nilesh Patra at 2021-07-03T19:03:03+05:30
Update upstream source from tag 'upstream/0.8.6'

Update to upstream version '0.8.6'
with Debian dir 6aeb293a61121a59ddc0152fee2445bb18d47926
- - - - -
9abc669c by Nilesh Patra at 2021-07-03T19:22:46+05:30
d/rules: Specify IGRAPH_EXTRA_INCLUDE_PATH for setup.py to pick up env variable

- - - - -
557c411f by Nilesh Patra at 2021-07-03T19:27:22+05:30
d/tests/run-unit-test: Do not run autopkgtests in project root

- - - - -
6961a5fd by Nilesh Patra at 2021-07-03T19:28:41+05:30
Upload to unstable

- - - - -


21 changed files:

- .github/workflows/build.yml
- CHANGELOG
- README.rst
- build-doc.yml
- debian/changelog
- debian/rules
- debian/tests/run-unit-test
- include/pynterface.h
- include/python_optimiser_interface.h
- include/python_partition_interface.h
- setup.py
- src/leidenalg/MutableVertexPartition.cpp
- src/leidenalg/Optimiser.cpp
- src/leidenalg/Optimiser.py
- src/leidenalg/SignificanceVertexPartition.cpp
- src/leidenalg/VertexPartition.py
- src/leidenalg/functions.py
- src/leidenalg/python_optimiser_interface.cpp
- src/leidenalg/python_partition_interface.cpp
- tests/test_Optimiser.py
- tests/test_VertexPartition.py


Changes:

=====================================
.github/workflows/build.yml
=====================================
@@ -8,9 +8,10 @@ on:
     branches:
       - master
 
+
 env:
   CIBW_TEST_REQUIRES: ddt
-  CIBW_TEST_COMMAND: "cd {project} && python -m unittest"
+  CIBW_TEST_COMMAND: "cd {project} && python -m unittest -v"
   CIBW_SKIP: "cp27-* pp27-* cp35-*"
 
 jobs:
@@ -119,7 +120,7 @@ jobs:
           CIBW_BEFORE_BUILD: "python setup.py build_c_core"
           CIBW_BUILD: "*-${{ matrix.wheel_arch }}"
           IGRAPH_CMAKE_EXTRA_ARGS: -DCMAKE_BUILD_TYPE=Release -A ${{ matrix.cmake_arch }}
-          CIBW_TEST_COMMAND: "cd /d {project} && python -m unittest"
+          CIBW_TEST_COMMAND: "cd /d {project} && python -m unittest -v"
 
       - uses: actions/upload-artifact at v2
         with:
@@ -163,7 +164,7 @@ jobs:
       - name: Test
         run: |
           pip install ddt
-          python -m unittest
+          python -m unittest -v
 
       - uses: actions/upload-artifact at v2
         with:
@@ -174,7 +175,6 @@ jobs:
     runs-on: ubuntu-latest
     # upload to PyPI on every push from the master branch
     if: github.event_name == 'push' &&
-        github.ref == 'refs/heads/master' &&
         startsWith(github.ref, 'refs/tags')
     steps:
       - uses: actions/download-artifact at v2


=====================================
CHANGELOG
=====================================
@@ -1,3 +1,11 @@
+0.8.6
+- Removed accidentally left DEBUG statement
+
+0.8.5
+- Corrected iterating over nodes (PR #70).
+- Fixed segfault with move_nodes_constrained (issue #68)
+- Fixed problem with initial_membership (issue #66)
+
 0.8.4
 - Update C core to 0.9.1
 - Fixed caching problem (issue #62)


=====================================
README.rst
=====================================
@@ -18,13 +18,14 @@ assignments remain fixed [10]_. It also provides some support for community
 detection on bipartite graphs. See the `documentation
 <http://leidenalg.readthedocs.io/en/latest/>`_ for more information.
 
+
 .. image:: https://readthedocs.org/projects/leidenalg/badge
                 :target: http://leidenalg.readthedocs.io/en/latest/
                 :alt: Leiden documentation status
 
-.. image:: https://ci.appveyor.com/api/projects/status/26au75vj8iwq32qp?svg=true
-                :target: https://ci.appveyor.com/project/vtraag/leidenalg
-                :alt: Leiden build status (AppVeyor)
+.. image:: https://github.com/vtraag/leidenalg/actions/workflows/build.yml/badge.svg?branch=master
+                :target: https://github.com/vtraag/leidenalg/actions/workflows/build.yml
+                :alt: Leiden build status (GitHub Actions)
 
 .. image:: https://zenodo.org/badge/146722095.svg
                 :target: https://zenodo.org/badge/latestdoi/146722095
@@ -38,7 +39,7 @@ Installation
 ------------
 
 In short: ``pip install leidenalg``. All major platforms are supported on
-Python>=3.5, earlier versions of Python are no longer supported. Alternatively,
+Python>=3.6, earlier versions of Python are no longer supported. Alternatively,
 you can install from Anaconda (channel ``conda-forge``).
 
 For Unix like systems it is possible to install from source. For Windows this is
@@ -84,9 +85,18 @@ sure to then install the ``C`` core library from source before. Make sure you
 Usage
 -----
 
-There is no standalone version of ``leidenalg``, and you will always need
-python to access it. There are no plans for developing a standalone version or
-R support. So, use python. Please refer to the documentation for more details
+There is no standalone version of ``leidenalg``, and you will always need python
+to access it. There are no plans at the moment for developing a standalone
+version or R support. However, there have been various efforts to port the
+package to R. These typically do not offer all available functionality or have
+some other limitations, but nonetheless may be very useful. The available ports
+are:
+
+- https://github.com/cole-trapnell-lab/leidenbase
+- https://github.com/TomKellyGenetics/leiden
+- https://github.com/kharchenkolab/leidenAlg
+
+Please refer to the documentation for more details
 on function calls and parameters.
 
 This implementation is made for flexibility, but ``igraph`` nowadays also


=====================================
build-doc.yml
=====================================
@@ -11,4 +11,5 @@ dependencies:
   - automake
   - flex
   - bison
-  - libtool
\ No newline at end of file
+  - libtool
+  - cmake
\ No newline at end of file


=====================================
debian/changelog
=====================================
@@ -1,3 +1,12 @@
+python-leidenalg (0.8.6-1) unstable; urgency=medium
+
+  * New upstream version 0.8.6
+  * d/rules: Specify IGRAPH_EXTRA_INCLUDE_PATH
+    for setup.py to pick up env variable
+  * d/tests/run-unit-test: Do not run autopkgtests in project root
+
+ -- Nilesh Patra <nilesh at debian.org>  Sat, 03 Jul 2021 19:28:17 +0530
+
 python-leidenalg (0.8.4-2) unstable; urgency=medium
 
   [ Shruti Sridhar ]


=====================================
debian/rules
=====================================
@@ -5,6 +5,7 @@ DH_VERBOSE := 1
 export PYBUILD_NAME=leidenalg
 
 export DEB_BUILD_MAINT_OPTIONS=hardening=+all
+export IGRAPH_EXTRA_INCLUDE_PATH=/usr/include/igraph
 
 %:
 	dh $@ --with python3 --buildsystem=pybuild


=====================================
debian/tests/run-unit-test
=====================================
@@ -1,7 +1,17 @@
 #!/bin/bash
 set -e
 
-for py in $(py3versions -r 2> /dev/null)
+CUR_DIR=`pwd`
+if [ "$AUTOPKGTEST_TMP" = "" ] ; then
+  AUTOPKGTEST_TMP=`mktemp -d /tmp/${pkg}-test.XXXXXX`
+  trap "rm -rf $AUTOPKGTEST_TMP" 0 INT QUIT ABRT PIPE TERM
+fi
+
+cp -a ${CUR_DIR}/tests/ $AUTOPKGTEST_TMP
+
+cd $AUTOPKGTEST_TMP
+
+for py in $(py3versions -s 2> /dev/null)
 do 
 	
 	$py -m pytest -v


=====================================
include/pynterface.h
=====================================
@@ -1,10 +1,6 @@
 #ifndef PYNTERFACE_H_INCLUDED
 #define PYNTERFACE_H_INCLUDED
 
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
 #include <Python.h>
 #include <igraph.h>
 #include "GraphHelper.h"
@@ -90,14 +86,7 @@ extern "C"
       PyObject *error;
   };
 
-  #if PY_MAJOR_VERSION >= 3
   #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
-  #else
-  #define GETSTATE(m) (&_state)
-  static struct module_state _state;
-  #endif
-
-  #if PY_MAJOR_VERSION >= 3
 
   static int leiden_traverse(PyObject *m, visitproc visit, void *arg) {
       Py_VISIT(GETSTATE(m)->error);
@@ -125,19 +114,8 @@ extern "C"
 
   PyObject *
   PyInit__c_leiden(void)
-
-  #else
-  #define INITERROR return
-
-  void
-  init_c_leiden(void)
-  #endif
   {
-  #if PY_MAJOR_VERSION >= 3
       PyObject* module = PyModule_Create(&leidendef);
-  #else
-      PyObject *module = Py_InitModule3("_c_leiden", leiden_funcs, "Leiden extension using igraph.");
-  #endif
 
       PyModule_AddIntConstant(module, "ALL_COMMS", Optimiser::ALL_COMMS);
       PyModule_AddIntConstant(module, "ALL_NEIGH_COMMS", Optimiser::ALL_NEIGH_COMMS);
@@ -157,9 +135,7 @@ extern "C"
           INITERROR;
       }
 
-  #if PY_MAJOR_VERSION >= 3
       return module;
-  #endif
   }
 
 #ifdef __cplusplus


=====================================
include/python_optimiser_interface.h
=====================================
@@ -1,10 +1,6 @@
 #ifndef PYNTERFACE_OPTIMISER_H_INCLUDED
 #define PYNTERFACE_OPTIMISER_H_INCLUDED
 
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
 #include <Python.h>
 #include <igraph.h>
 #include "GraphHelper.h"


=====================================
include/python_partition_interface.h
=====================================
@@ -1,10 +1,6 @@
 #ifndef PYNTERFACE_PARTITION_H_INCLUDED
 #define PYNTERFACE_PARTITION_H_INCLUDED
 
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
 #include <Python.h>
 #include <igraph.h>
 #include "GraphHelper.h"
@@ -31,6 +27,8 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes);
 Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights);
 Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights, int check_positive_weight);
 
+vector<size_t> create_size_t_vector(PyObject* py_list);
+
 PyObject* capsule_MutableVertexPartition(MutableVertexPartition* partition);
 MutableVertexPartition* decapsule_MutableVertexPartition(PyObject* py_partition);
 


=====================================
setup.py
=====================================
@@ -35,13 +35,6 @@ from time import sleep
 
 ###########################################################################
 
-LIBIGRAPH_FALLBACK_INCLUDE_DIRS = ["/usr/include/igraph", "/usr/local/include/igraph"]
-LIBIGRAPH_FALLBACK_LIBRARIES = ["igraph"]
-LIBIGRAPH_FALLBACK_LIBRARY_DIRS = []
-
-###########################################################################
-
-
 is_windows = platform.system() == "windows"
 
 
@@ -300,6 +293,7 @@ class BuildConfiguration(object):
         self.define_macros = []
         self.extra_objects = []
         self.static_extension = False
+        self.external = False
         self.use_pkgconfig = False
         self._has_pkgconfig = None
         self.excluded_include_dirs = []
@@ -369,13 +363,16 @@ class BuildConfiguration(object):
                 # Check whether the user asked us to discover a pre-built igraph
                 # with pkg-config
                 detected = False
-                if buildcfg.use_pkgconfig:
-                    detected = buildcfg.detect_from_pkgconfig()
-                    if not detected:
-                        print(
-                            "Cannot find the C core of igraph on this system using pkg-config."
-                        )
-                        sys.exit(1)
+                if buildcfg.external:
+                    if buildcfg.use_pkgconfig:
+                        detected = buildcfg.detect_from_pkgconfig()
+                        if not detected:
+                            print(
+                                "Cannot find the C core of igraph on this system using pkg-config."
+                            )
+                            sys.exit(1)
+                    else:
+                        buildcfg.use_educated_guess()
                 else:
                     # Build the C core from the vendored igraph source
                     self.run_command("build_c_core")
@@ -384,6 +381,14 @@ class BuildConfiguration(object):
                         if not detected:
                             buildcfg.use_educated_guess()
 
+                # Add any extra include paths if needed; this is needed for the
+                # Appveyor CI build
+                if "IGRAPH_EXTRA_INCLUDE_PATH" in os.environ:
+                    buildcfg.include_dirs = (
+                        list(os.environ["IGRAPH_EXTRA_INCLUDE_PATH"].split(os.pathsep))
+                        + buildcfg.include_dirs
+                    )
+
                 # Add any extra library paths if needed; this is needed for the
                 # Appveyor CI build
                 if "IGRAPH_EXTRA_LIBRARY_PATH" in os.environ:
@@ -649,6 +654,9 @@ class BuildConfiguration(object):
             elif option == "--no-wait":
                 opts_to_remove.append(idx)
                 self.wait = False
+            elif option == "--external":
+                opts_to_remove.append(idx)
+                self.external = True
             elif option == "--use-pkg-config":
                 opts_to_remove.append(idx)
                 self.use_pkgconfig = True
@@ -709,34 +717,25 @@ class BuildConfiguration(object):
             buildcfg.libraries = eval(buildcfg_file.open("r").read())
 
     def use_educated_guess(self):
-        """Tries to guess the proper library names, include and library paths
-        if everything else failed."""
-
-        global LIBIGRAPH_FALLBACK_LIBRARIES
-        global LIBIGRAPH_FALLBACK_INCLUDE_DIRS
-        global LIBIGRAPH_FALLBACK_LIBRARY_DIRS
-
-        print("WARNING: we were not able to detect where igraph is installed on")
-        print("your machine (if it is installed at all). We will use the fallback")
-        print("library and include paths hardcoded in setup.py and hope that the")
-        print("C core of igraph is installed there.")
-        print("")
-        print("If the compilation fails and you are sure that igraph is installed")
-        print("on your machine, adjust the following two variables in setup.py")
-        print("accordingly and try again:")
-        print("")
-        print("- LIBIGRAPH_FALLBACK_INCLUDE_DIRS")
-        print("- LIBIGRAPH_FALLBACK_LIBRARY_DIRS")
-        print("")
-
-        if self.wait:
-            wait_for_keypress(seconds=10)
-
-        self.libraries = LIBIGRAPH_FALLBACK_LIBRARIES[:]
-        if self.static_extension:
-            self.libraries.extend(["xml2", "z", "m", "stdc++"])
-        self.include_dirs = LIBIGRAPH_FALLBACK_INCLUDE_DIRS[:]
-        self.library_dirs = LIBIGRAPH_FALLBACK_LIBRARY_DIRS[:]
+        """Tries to guess the proper library names, include and library paths."""
+
+        print("""WARNING: You are trying to install with an external igraph library.
+No include dirs or library dirs are specified, so they need to be set externally.
+If compilation fails you may adjust the following environment variables to adjust
+the required paths.
+- IGRAPH_EXTRA_INCLUDE_PATH
+- IGRAPH_EXTRA_LIBRARY_PATH
+- IGRAPH_EXTRA_LIBRARIES
+- IGRAPH_EXTRA_DYNAMIC_LIBRARIES
+
+If a static build extension is used, we try to statically link to igraph. The extra
+libraries that are specified are then also assumed to be statically linked. If, in
+addition, some libraries need to be explicitly dynamically linked, you can specify this.
+        """)
+
+        self.libraries = ['igraph']
+        self.include_dirs = []
+        self.library_dirs = []
 
 
 ###########################################################################


=====================================
src/leidenalg/MutableVertexPartition.cpp
=====================================
@@ -373,7 +373,7 @@ vector<size_t> MutableVertexPartition::rank_order_communities(vector<MutableVert
 
   #ifdef DEBUG
     size_t n = partitions[0]->graph->vcount();
-    for (size_t layer; layer < nb_layers; layer++)
+    for (size_t layer = 0; layer < nb_layers; layer++)
     {
       for (size_t v = 0; v < n; v++)
       {


=====================================
src/leidenalg/Optimiser.cpp
=====================================
@@ -31,7 +31,7 @@ Optimiser::Optimiser()
   this->max_comm_size = 0;
 
   igraph_rng_init(&rng, &igraph_rngtype_mt19937);
-  igraph_rng_seed(&rng, rand());
+  igraph_rng_seed(&rng, time(NULL));
 }
 
 Optimiser::~Optimiser()
@@ -563,8 +563,6 @@ double Optimiser::move_nodes(vector<MutableVertexPartition*> partitions, vector<
   {
     size_t v = vertex_order.front(); vertex_order.pop_front();
 
-    Graph* graph = NULL;
-    MutableVertexPartition* partition = NULL;
     // What is the current community of the node (this should be the same for all layers)
     size_t v_comm = partitions[0]->membership(v);
 
@@ -623,17 +621,15 @@ double Optimiser::move_nodes(vector<MutableVertexPartition*> partitions, vector<
     // Check if we should move to an empty community
     if (consider_empty_community)
     {
-      graph = graphs[0];
-      partition = partitions[0];
-      if ( partition->cnodes(v_comm) > 1 )  // We should not move a node when it is already in its own empty community (this may otherwise create more empty communities than nodes)
+      if ( partitions[0]->cnodes(v_comm) > 1 )  // We should not move a node when it is already in its own empty community (this may otherwise create more empty communities than nodes)
       {
-        size_t n_comms = partition->n_communities();
-        size_t comm = partition->get_empty_community();
+        size_t n_comms = partitions[0]->n_communities();
+        size_t comm = partitions[0]->get_empty_community();
         #ifdef DEBUG
-          cerr << "Checking empty community (" << comm << ") for partition " << partition << endl;
+          cerr << "Checking empty community (" << comm << ") for partition " << partitions[0] << endl;
         #endif
         comms.push_back(comm);
-        if (partition->n_communities() > n_comms)
+        if (partitions[0]->n_communities() > n_comms)
         {
           // If the empty community has just been added, we need to make sure
           // that is has also been added to the other layers
@@ -726,15 +722,18 @@ double Optimiser::move_nodes(vector<MutableVertexPartition*> partitions, vector<
         #endif
 
         // Mark neighbours as unstable (if not in new community and not fixed)
-        for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
+        for (Graph* graph : graphs)
         {
-          // If the neighbour was stable and is not in the new community, we
-          // should mark it as unstable, and add it to the queue, skipping
-          // fixed nodes
-          if (is_node_stable[u] && partition->membership(v) != max_comm && !is_membership_fixed[u])
+          for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
           {
-            vertex_order.push_back(u);
-            is_node_stable[u] = false;
+            // If the neighbour was stable and is not in the new community, we
+            // should mark it as unstable, and add it to the queue, skipping
+            // fixed nodes
+            if (is_node_stable[u] && partitions[0]->membership(u) != max_comm && !is_membership_fixed[u])
+            {
+              vertex_order.push_back(u);
+              is_node_stable[u] = false;
+            }
           }
         }
         // Keep track of number of moves
@@ -1050,8 +1049,6 @@ double Optimiser::move_nodes_constrained(vector<MutableVertexPartition*> partiti
       comm_added[comm] = false;
     comms.clear();
 
-    Graph* graph = NULL;
-    MutableVertexPartition* partition = NULL;
     // What is the current community of the node (this should be the same for all layers)
     size_t v_comm = partitions[0]->membership(v);
 
@@ -1192,15 +1189,19 @@ double Optimiser::move_nodes_constrained(vector<MutableVertexPartition*> partiti
         }
       #endif
 
-      // Mark neighbours as unstable (if not in new community)
-      for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
+      // Mark neighbours as unstable (if not in new community and not fixed)
+      for (Graph* graph : graphs)
       {
-        // If the neighbour was stable and is not in the new community, we
-        // should mark it as unstable, and add it to the queue
-        if (is_node_stable[u] && partition->membership(v) != max_comm)
+        for (size_t u : graph->get_neighbours(v, IGRAPH_ALL))
         {
-          vertex_order.push_back(u);
-          is_node_stable[u] = false;
+          // If the neighbour was stable and is not in the new community, we
+          // should mark it as unstable, and add it to the queue, skipping
+          // fixed nodes
+          if (is_node_stable[u] && partitions[0]->membership(u) != max_comm && constrained_partition->membership(u) == constrained_partition->membership(v))
+          {
+            vertex_order.push_back(u);
+            is_node_stable[u] = false;
+          }
         }
       }
 


=====================================
src/leidenalg/Optimiser.py
=====================================
@@ -2,10 +2,6 @@ from . import _c_leiden
 from .VertexPartition import LinearResolutionParameterVertexPartition
 from collections import namedtuple
 from math import log, sqrt
-import sys
-
-# Check if working with Python 3
-PY3 = (sys.version > '3')
 
 class Optimiser(object):
   """ Class for doing community detection using the Leiden algorithm.


=====================================
src/leidenalg/SignificanceVertexPartition.cpp
=====================================
@@ -110,8 +110,12 @@ double SignificanceVertexPartition::diff_move(size_t v, size_t new_comm)
 
     // Calculate actual diff
 
-    diff =   (double)N_oldx*KLL(q_oldx, p) + (double)N_newx*KLL(q_newx, p)
-           - (double)N_old *KLL(q_old,  p) - (double)N_new *KLL(q_new,  p);
+    if (N_oldx != N_new || q_oldx != q_new)
+      diff +=  (double)N_oldx*KLL(q_oldx, p) - (double)N_new*KLL(q_new,  p);
+
+    if (N_newx != N_old || q_newx != q_old)
+      diff += (double)N_newx*KLL(q_newx, p) - (double)N_old*KLL(q_old,  p);
+
     #ifdef DEBUG
       cerr << "\t" << "diff: " << diff << "." << endl;
     #endif


=====================================
src/leidenalg/VertexPartition.py
=====================================
@@ -1,9 +1,6 @@
 import igraph as _ig
 from . import _c_leiden
 from .functions import _get_py_capsule
-import sys
-# Check if working with Python 3
-PY3 = (sys.version > '3')
 
 class MutableVertexPartition(_ig.VertexClustering):
   """ Contains a partition of graph, derives from :class:`ig.VertexClustering`.


=====================================
src/leidenalg/functions.py
=====================================
@@ -11,14 +11,9 @@ from ._c_leiden import MERGE_NODES
 
 from collections import Counter
 
-# Check if working with Python 3
-PY3 = (sys.version > '3')
 
 def _get_py_capsule(graph):
-  if PY3:
-    return graph.__graph_as_capsule()
-  else:
-    return graph.__graph_as_cobject()
+  return graph.__graph_as_capsule()
 
 from .VertexPartition import *
 from .Optimiser import *


=====================================
src/leidenalg/python_optimiser_interface.cpp
=====================================
@@ -404,11 +404,11 @@ extern "C"
     #endif
 
     #ifdef DEBUG
-      cerr << "Capsule constrained partition at address " << py_partition << endl;
+      cerr << "Capsule constrained partition at address " << py_constrained_partition << endl;
     #endif
     MutableVertexPartition* constrained_partition = decapsule_MutableVertexPartition(py_constrained_partition);
     #ifdef DEBUG
-      cerr << "Using constrained partition at address " << partition << endl;
+      cerr << "Using constrained partition at address " << constrained_partition << endl;
     #endif
 
     if (consider_comms < 0)
@@ -545,11 +545,7 @@ extern "C"
       cerr << "Using optimiser at address " << optimiser << endl;
     #endif
 
-    #ifdef IS_PY3K
     return PyLong_FromLong(optimiser->consider_comms);
-    #else
-    return PyInt_FromLong(optimiser->consider_comms);
-    #endif
   }
 
   PyObject* _Optimiser_set_refine_consider_comms(PyObject *self, PyObject *args, PyObject *keywds)
@@ -609,11 +605,7 @@ extern "C"
       cerr << "Using optimiser at address " << optimiser << endl;
     #endif
 
-    #ifdef IS_PY3K
     return PyLong_FromLong(optimiser->refine_consider_comms);
-    #else
-    return PyInt_FromLong(optimiser->refine_consider_comms);
-    #endif
   }
 
   PyObject* _Optimiser_set_optimise_routine(PyObject *self, PyObject *args, PyObject *keywds)
@@ -673,11 +665,7 @@ extern "C"
       cerr << "Using optimiser at address " << optimiser << endl;
     #endif
 
-    #ifdef IS_PY3K
     return PyLong_FromLong(optimiser->optimise_routine);
-    #else
-    return PyInt_FromLong(optimiser->optimise_routine);
-    #endif
   }
 
   PyObject* _Optimiser_set_refine_routine(PyObject *self, PyObject *args, PyObject *keywds)
@@ -737,11 +725,7 @@ extern "C"
       cerr << "Using optimiser at address " << optimiser << endl;
     #endif
 
-    #ifdef IS_PY3K
     return PyLong_FromLong(optimiser->refine_routine);
-    #else
-    return PyInt_FromLong(optimiser->refine_routine);
-    #endif
   }
 
   PyObject* _Optimiser_set_consider_empty_community(PyObject *self, PyObject *args, PyObject *keywds)


=====================================
src/leidenalg/python_partition_interface.cpp
=====================================
@@ -1,9 +1,5 @@
 #include "python_partition_interface.h"
 
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#endif
-
 Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes)
 {
   return create_graph_from_py(py_obj_graph, py_node_sizes, NULL, true);
@@ -20,11 +16,7 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyO
     cerr << "create_graph_from_py" << endl;
   #endif
 
-  #ifdef IS_PY3K
-    igraph_t* py_graph = (igraph_t*) PyCapsule_GetPointer(py_obj_graph, NULL);
-  #else
-    igraph_t* py_graph = (igraph_t*) PyCObject_AsVoidPtr(py_obj_graph);
-  #endif
+  igraph_t* py_graph = (igraph_t*) PyCapsule_GetPointer(py_obj_graph, NULL);
   #ifdef DEBUG
     cerr << "Got igraph_t " << py_graph << endl;
   #endif
@@ -55,13 +47,10 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyO
     for (size_t v = 0; v < n; v++)
     {
       PyObject* py_item = PyList_GetItem(py_node_sizes, v);
-      #ifdef IS_PY3K
-      if (PyLong_Check(py_item))
-      #else
-      if (PyInt_Check(py_item) || PyLong_Check(py_item))
-      #endif
+      if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
       {
-        node_sizes[v] = PyLong_AsLong(py_item);
+        size_t e = PyLong_AsSize_t(PyNumber_Long(py_item));
+        node_sizes[v] = e;
       }
       else
       {
@@ -135,6 +124,27 @@ Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyO
   return graph;
 }
 
+vector<size_t> create_size_t_vector(PyObject* py_list)
+{
+    size_t n = PyList_Size(py_list);
+    vector<size_t> result(n);
+    for (size_t i = 0; i < n; i++)
+    {
+      PyObject* py_item = PyList_GetItem(py_list, i);
+      if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
+      {
+        size_t e = PyLong_AsSize_t(PyNumber_Long(py_item));
+        if (e >= n)
+          throw Exception("Value cannot exceed length of list.");
+        else
+          result[i] = e;
+      }
+      else
+        throw Exception("Value cannot exceed length of list.");
+    }
+    return result;
+}
+
 PyObject* capsule_MutableVertexPartition(MutableVertexPartition* partition)
 {
   PyObject* py_partition = PyCapsule_New(partition, "leidenalg.VertexPartition.MutableVertexPartition", del_MutableVertexPartition);
@@ -180,34 +190,7 @@ extern "C"
       // If necessary create an initial partition
       if (py_initial_membership != NULL && py_initial_membership != Py_None)
       {
-
-        vector<size_t> initial_membership;
-
-        #ifdef DEBUG
-          cerr << "Reading initial membership." << endl;
-        #endif
-        size_t n = PyList_Size(py_initial_membership);
-        initial_membership.resize(n);
-        for (size_t v = 0; v < n; v++)
-        {
-          PyObject* py_item = PyList_GetItem(py_initial_membership, v);
-          if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-          {
-            size_t m = PyLong_AsSize_t(py_item);
-            if (m >= n)
-            {
-              PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-              return NULL;
-            }
-            else
-              initial_membership[v] = m;
-          }
-          else
-          {
-            PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-            return NULL;
-          }
-        }
+        vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
 
         partition = new ModularityVertexPartition(graph, initial_membership);
       }
@@ -255,34 +238,7 @@ extern "C"
       // If necessary create an initial partition
       if (py_initial_membership != NULL && py_initial_membership != Py_None)
       {
-
-        vector<size_t> initial_membership;
-
-        #ifdef DEBUG
-          cerr << "Reading initial membership." << endl;
-        #endif
-        size_t n = PyList_Size(py_initial_membership);
-        initial_membership.resize(n);
-        for (size_t v = 0; v < n; v++)
-        {
-          PyObject* py_item = PyList_GetItem(py_initial_membership, v);
-          if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-          {
-            size_t m = PyLong_AsSize_t(py_item);
-            if (m >= n)
-            {
-              PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-              return NULL;
-            }
-            else
-              initial_membership[v] = m;
-          }
-          else
-          {
-            PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-            return NULL;
-          }
-        }
+        vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
 
         partition = new SignificanceVertexPartition(graph, initial_membership);
       }
@@ -330,34 +286,7 @@ extern "C"
       // If necessary create an initial partition
       if (py_initial_membership != NULL && py_initial_membership != Py_None)
       {
-
-        vector<size_t> initial_membership;
-
-        #ifdef DEBUG
-          cerr << "Reading initial membership." << endl;
-        #endif
-        size_t n = PyList_Size(py_initial_membership);
-        initial_membership.resize(n);
-        for (size_t v = 0; v < n; v++)
-        {
-          PyObject* py_item = PyList_GetItem(py_initial_membership, v);
-          if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-          {
-            size_t m = PyLong_AsSize_t(py_item);
-            if (m >= n)
-            {
-              PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-              return NULL;
-            }
-            else
-              initial_membership[v] = m;
-          }
-          else
-          {
-            PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-            return NULL;
-          }
-        }
+        vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
 
         partition = new SurpriseVertexPartition(graph, initial_membership);
       }
@@ -406,37 +335,7 @@ extern "C"
       // If necessary create an initial partition
       if (py_initial_membership != NULL && py_initial_membership != Py_None)
       {
-
-        vector<size_t> initial_membership;
-
-        #ifdef DEBUG
-          cerr << "Reading initial membership." << endl;
-        #endif
-        size_t n = PyList_Size(py_initial_membership);
-        #ifdef DEBUG
-          cerr << "Size " << n << endl;
-        #endif
-        initial_membership.resize(n);
-        for (size_t v = 0; v < n; v++)
-        {
-          PyObject* py_item = PyList_GetItem(py_initial_membership, v);
-          if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-          {
-            size_t m = PyLong_AsSize_t(py_item);
-            if (m >= n)
-            {
-              PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-              return NULL;
-            }
-            else
-              initial_membership[v] = m;
-          }
-          else
-          {
-            PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-            return NULL;
-          }
-        }
+        vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
 
         partition = new CPMVertexPartition(graph, initial_membership, resolution_parameter);
       }
@@ -485,34 +384,7 @@ extern "C"
       // If necessary create an initial partition
       if (py_initial_membership != NULL && py_initial_membership != Py_None)
       {
-
-        vector<size_t> initial_membership;
-
-        #ifdef DEBUG
-          cerr << "Reading initial membership." << endl;
-        #endif
-        size_t n = PyList_Size(py_initial_membership);
-        initial_membership.resize(n);
-        for (size_t v = 0; v < n; v++)
-        {
-          PyObject* py_item = PyList_GetItem(py_initial_membership, v);
-          if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-          {
-            size_t m = PyLong_AsSize_t(py_item);
-            if (m >= n)
-            {
-              PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-              return NULL;
-            }
-            else
-              initial_membership[v] = m;
-          }
-          else
-          {
-            PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-            return NULL;
-          }
-        }
+        vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
 
         partition = new RBERVertexPartition(graph, initial_membership, resolution_parameter);
       }
@@ -561,34 +433,7 @@ extern "C"
       // If necessary create an initial partition
       if (py_initial_membership != NULL && py_initial_membership != Py_None)
       {
-
-        vector<size_t> initial_membership;
-
-        #ifdef DEBUG
-          cerr << "Reading initial membership." << endl;
-        #endif
-        size_t n = PyList_Size(py_initial_membership);
-        initial_membership.resize(n);
-        for (size_t v = 0; v < n; v++)
-        {
-          PyObject* py_item = PyList_GetItem(py_initial_membership, v);
-          if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-          {
-            size_t m = PyLong_AsSize_t(py_item);
-            if (m >= n)
-            {
-              PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-              return NULL;
-            }
-            else
-              initial_membership[v] = m;
-          }
-          else
-          {
-            PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-            return NULL;
-          }
-        }
+        vector<size_t> initial_membership = create_size_t_vector(py_initial_membership);
 
         partition = new RBConfigurationVertexPartition(graph, initial_membership, resolution_parameter);
       }
@@ -663,11 +508,7 @@ extern "C"
     PyObject* node_sizes = PyList_New(n);
     for (size_t v = 0; v < n; v++)
     {
-      #ifdef IS_PY3K
-        PyObject* item = PyLong_FromSize_t(graph->node_size(v));
-      #else
-        PyObject* item = PyInt_FromSize_t(graph->node_size(v));
-      #endif
+      PyObject* item = PyLong_FromSize_t(graph->node_size(v));
       PyList_SetItem(node_sizes, v, item);
     }
 
@@ -695,30 +536,19 @@ extern "C"
       cerr << "from_coarse_partition();" << endl;
     #endif
 
-    size_t n = PyList_Size(py_membership);
     vector<size_t> membership;
-    membership.resize(n);
-    for (size_t v = 0; v < n; v++)
+    try
     {
-      PyObject* py_item = PyList_GetItem(py_membership, v);
-      if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-      {
-        size_t m = PyLong_AsSize_t(py_item);
-        if (m >= n)
-        {
-          PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-          return NULL;
-        }
-        else
-          membership[v] = m;
-      }
-      else
-      {
-        PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-        return NULL;
-      }
+      membership = create_size_t_vector(py_membership);
+    }
+    catch (std::exception& e )
+    {
+      string s = "Could not create membership vector: " + string(e.what());
+      PyErr_SetString(PyExc_BaseException, s.c_str());
+      return NULL;
     }
 
+
     #ifdef DEBUG
       cerr << "Capsule partition at address " << py_partition << endl;
     #endif
@@ -731,33 +561,18 @@ extern "C"
 
     if (py_coarse_node != NULL && py_coarse_node != Py_None)
     {
-      cerr << "Get coarse node list" << endl;
-      size_t n = PyList_Size(py_coarse_node);
       vector<size_t> coarse_node;
-      coarse_node.resize(n);
-      for (size_t v = 0; v < n; v++)
+      try
       {
-        PyObject* py_item = PyList_GetItem(py_coarse_node, v);
-
-        if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-        {
-          size_t m = PyLong_AsSize_t(py_item);
-          if (m >= n)
-          {
-            PyErr_SetString(PyExc_TypeError, "Coarse node cannot exceed number of nodes.");
-            return NULL;
-          }
-          else
-            coarse_node[v] = m;
-        }
-        else
-        {
-          PyErr_SetString(PyExc_TypeError, "Expected integer value for coarse vector.");
-          return NULL;
-        }
+        coarse_node = create_size_t_vector(py_coarse_node);
+      }
+      catch (std::exception& e )
+      {
+        string s = "Could not create coarse node vector: " + string(e.what());
+        PyErr_SetString(PyExc_BaseException, s.c_str());
+        return NULL;
       }
 
-    cerr << "Got coarse node list" << endl;
       partition->from_coarse_partition(membership, coarse_node);
     }
     else
@@ -1257,11 +1072,7 @@ extern "C"
     PyObject* py_membership = PyList_New(n);
     for (size_t v = 0; v < n; v++)
     {
-      #ifdef IS_PY3K
-        PyObject* item = PyLong_FromSize_t(partition->membership(v));
-      #else
-        PyObject* item = PyInt_FromSize_t(partition->membership(v));
-      #endif
+      PyObject* item = PyLong_FromSize_t(partition->membership(v));
       PyList_SetItem(py_membership, v, item);
     }
     return py_membership;
@@ -1296,32 +1107,16 @@ extern "C"
       cerr << "Using partition at address " << partition << endl;
     #endif
 
-    size_t n = PyList_Size(py_membership);
-    vector<size_t> membership;
-    membership.resize(n);
-    for (size_t v = 0; v < n; v++)
+    try
     {
-      PyObject* py_item = PyList_GetItem(py_membership, v);
-
-      if (PyNumber_Check(py_item) && PyIndex_Check(py_item))
-      {
-          size_t m = PyLong_AsSize_t(py_item);
-          if (m >= n)
-          {
-            PyErr_SetString(PyExc_TypeError, "Membership cannot exceed number of nodes.");
-            return NULL;
-          }
-          else
-            membership[v] = m;
-      }
-      else
-      {
-        PyErr_SetString(PyExc_TypeError, "Expected integer value for membership vector.");
-        return NULL;
-      }
+      partition->set_membership(create_size_t_vector(py_membership));
+    }
+    catch (std::exception& e )
+    {
+      string s = "Could not set membership: " + string(e.what());
+      PyErr_SetString(PyExc_BaseException, s.c_str());
+      return NULL;
     }
-
-    partition->set_membership(membership);
 
     #ifdef DEBUG
       cerr << "Exiting set_membership();" << endl;


=====================================
tests/test_Optimiser.py
=====================================
@@ -2,33 +2,29 @@ import unittest
 import igraph as ig
 import leidenalg
 
-import sys
-PY3 = (sys.version > '3');
-
-if PY3:
-  from functools import reduce
+from functools import reduce
 
 class OptimiserTest(unittest.TestCase):
 
   def setUp(self):
-    self.optimiser = leidenalg.Optimiser();
+    self.optimiser = leidenalg.Optimiser()
 
   def test_move_nodes(self):
-    G = ig.Graph.Full(100);
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
-    self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+    G = ig.Graph.Full(100)
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
+    self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
     self.assertListEqual(
         partition.sizes(), [100],
-        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes incorrect.");
+        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes incorrect.")
 
   def test_move_nodes_with_max_comm_size(self):
-    G = ig.Graph.Full(100);
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
+    G = ig.Graph.Full(100)
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
     self.optimiser.max_comm_size = 17
-    self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+    self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
     self.assertListEqual(
         partition.sizes(), [17, 17, 17, 17, 17, 15],
-        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes (max_comm_size=17) incorrect.");
+        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes (max_comm_size=17) incorrect.")
 
   def test_move_nodes_with_fixed(self):
     # One edge plus singleton, but the two connected nodes are fixed
@@ -36,76 +32,76 @@ class OptimiserTest(unittest.TestCase):
     is_membership_fixed = [True, False, True]
     partition = leidenalg.CPMVertexPartition(
             G,
-            resolution_parameter=0.1);
-    self.optimiser.move_nodes(partition, is_membership_fixed=is_membership_fixed, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+            resolution_parameter=0.1)
+    self.optimiser.move_nodes(partition, is_membership_fixed=is_membership_fixed, consider_comms=leidenalg.ALL_NEIGH_COMMS)
     self.assertListEqual(
         partition.sizes(), [1, 1, 1],
-        msg="CPMVertexPartition(resolution_parameter=0.1) of one edge plus singleton after move nodes with fixed nodes is incorrect.");
+        msg="CPMVertexPartition(resolution_parameter=0.1) of one edge plus singleton after move nodes with fixed nodes is incorrect.")
 
   def test_merge_nodes(self):
-    G = ig.Graph.Full(100);
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
-    self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+    G = ig.Graph.Full(100)
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
+    self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
     self.assertListEqual(
         partition.sizes(), [100],
-        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.");
+        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.")
     self.assertEqual(
         partition.total_weight_in_all_comms(),
         G.ecount(),
-        msg="total_weight_in_all_comms not equal to ecount of graph.");
+        msg="total_weight_in_all_comms not equal to ecount of graph.")
 
   def test_merge_nodes_with_max_comm_size(self):
-    G = ig.Graph.Full(100);
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
+    G = ig.Graph.Full(100)
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
     self.optimiser.max_comm_size = 17
-    self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+    self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
     self.assertListEqual(
         partition.sizes(), [17, 17, 17, 17, 17, 15],
-        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes (max_comm_size=17) incorrect.");
+        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes (max_comm_size=17) incorrect.")
 
   def test_diff_move_node_optimality(self):
-    G = ig.Graph.Erdos_Renyi(100, p=5./100, directed=False, loops=False);
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.1);
+    G = ig.Graph.Erdos_Renyi(100, p=5./100, directed=False, loops=False)
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.1)
     while 0 < self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS):
-      pass;
+      pass
     for v in G.vs:
-      neigh_comms = set(partition.membership[u.index] for u in v.neighbors());
+      neigh_comms = set(partition.membership[u.index] for u in v.neighbors())
       for c in neigh_comms:
         self.assertLessEqual(
           partition.diff_move(v.index, c), 1e-10, # Allow for a small difference up to rounding error.
-          msg="Was able to move a node to a better community, violating node optimality.");
+          msg="Was able to move a node to a better community, violating node optimality.")
 
   def test_optimiser(self):
-    G = reduce(ig.Graph.disjoint_union, (ig.Graph.Tree(10, 3, mode=ig.TREE_UNDIRECTED) for i in range(10)));
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0);
-    self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS;
-    self.optimiser.optimise_partition(partition);
+    G = reduce(ig.Graph.disjoint_union, (ig.Graph.Tree(10, 3, mode=ig.TREE_UNDIRECTED) for i in range(10)))
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0)
+    self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS
+    self.optimiser.optimise_partition(partition)
     self.assertListEqual(
         partition.sizes(), 10*[10],
-        msg="After optimising partition failed to find different components with CPMVertexPartition(resolution_parameter=0)");
+        msg="After optimising partition failed to find different components with CPMVertexPartition(resolution_parameter=0)")
 
   def test_optimiser_with_max_comm_size(self):
-    G = ig.Graph.Full(100);
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0);
-    self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS;
+    G = ig.Graph.Full(100)
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0)
+    self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS
     self.optimiser.max_comm_size = 10
-    self.optimiser.optimise_partition(partition);
+    self.optimiser.optimise_partition(partition)
     self.assertListEqual(
         partition.sizes(), 10*[10],
-        msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0)");
+        msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0)")
 
   def test_optimiser_split_with_max_comm_size(self):
-    G = ig.Graph.Full(100);
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5);
-    self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS);
+    G = ig.Graph.Full(100)
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5)
+    self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS)
     self.assertListEqual(
         partition.sizes(), [100],
-        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.");
+        msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.")
     self.optimiser.max_comm_size = 10
-    self.optimiser.optimise_partition(partition);
+    self.optimiser.optimise_partition(partition)
     self.assertListEqual(
         partition.sizes(), 10*[10],
-        msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0.5)");
+        msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0.5)")
 
   def test_optimiser_with_is_membership_fixed(self):
       G = ig.Graph.Full(3)
@@ -148,28 +144,28 @@ class OptimiserTest(unittest.TestCase):
 
 
   def test_neg_weight_bipartite(self):
-    G = ig.Graph.Full_Bipartite(50, 50);
-    G.es['weight'] = -0.1;
-    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=-0.1, weights='weight');
-    self.optimiser.consider_comms=leidenalg.ALL_COMMS;
-    self.optimiser.optimise_partition(partition);
+    G = ig.Graph.Full_Bipartite(50, 50)
+    G.es['weight'] = -0.1
+    partition = leidenalg.CPMVertexPartition(G, resolution_parameter=-0.1, weights='weight')
+    self.optimiser.consider_comms=leidenalg.ALL_COMMS
+    self.optimiser.optimise_partition(partition)
     self.assertListEqual(
         partition.sizes(), 2*[50],
-        msg="After optimising partition failed to find bipartite structure with CPMVertexPartition(resolution_parameter=-0.1)");
+        msg="After optimising partition failed to find bipartite structure with CPMVertexPartition(resolution_parameter=-0.1)")
 
   def test_resolution_profile(self):
-    G = ig.Graph.Famous('Zachary');
-    profile = self.optimiser.resolution_profile(G, leidenalg.CPMVertexPartition, resolution_range=(0,1));
+    G = ig.Graph.Famous('Zachary')
+    profile = self.optimiser.resolution_profile(G, leidenalg.CPMVertexPartition, resolution_range=(0,1))
     self.assertListEqual(
       profile[0].sizes(), [G.vcount()],
-      msg="Resolution profile incorrect: at resolution 0, not equal to a single community for CPM.");
+      msg="Resolution profile incorrect: at resolution 0, not equal to a single community for CPM.")
     self.assertListEqual(
       profile[-1].sizes(), [1]*G.vcount(),
-      msg="Resolution profile incorrect: at resolution 1, not equal to a singleton partition for CPM.");
+      msg="Resolution profile incorrect: at resolution 1, not equal to a singleton partition for CPM.")
 
 #%%
 if __name__ == '__main__':
   #%%
-  unittest.main(verbosity=3);
-  suite = unittest.TestLoader().discover('.');
-  unittest.TextTestRunner(verbosity=1).run(suite);
+  unittest.main(verbosity=3)
+  suite = unittest.TestLoader().discover('.')
+  unittest.TextTestRunner(verbosity=1).run(suite)


=====================================
tests/test_VertexPartition.py
=====================================
@@ -6,13 +6,11 @@ from copy import deepcopy
 
 from ddt import ddt, data, unpack
 
-import sys
-PY3 = (sys.version > '3');
 #%%
 
 def name_object(obj, name):
-  obj.__name__ = name;
-  return obj;
+  obj.__name__ = name
+  return obj
 
 graphs = [
     ###########################################################################
@@ -58,7 +56,7 @@ graphs = [
                 'Lattice_undirected'),
     name_object(ig.Graph.Lattice([100], nei=3, directed=True, mutual=False, circular=True),
                 'Lattice_directed')
-    ];
+    ]
 
 bipartite_graph = name_object(
     ig.Graph.Bipartite([0, 0, 0, 0, 1, 1, 1, 1],
@@ -75,91 +73,88 @@ bipartite_graph = name_object(
               'bipartite_example')
 
 def make_weighted(G):
-  m = G.ecount();
-  if PY3:
-    G.es['weight'] = [random.random() for i in range(G.ecount())];
-  else:
-    G.es['weight'] = [random.random() for i in xrange(G.ecount())];
-  G.__name__ += '_weighted';
-  return G;
+  m = G.ecount()
+  G.es['weight'] = [random.random() for i in range(G.ecount())]
+  G.__name__ += '_weighted'
+  return G
 
-graphs += [make_weighted(H) for H in graphs];
+graphs += [make_weighted(H) for H in graphs]
 
 class BaseTest:
   @ddt
   class MutableVertexPartitionTest(unittest.TestCase):
 
     def setUp(self):
-      self.optimiser = leidenalg.Optimiser();
+      self.optimiser = leidenalg.Optimiser()
 
     @data(*graphs)
     def test_move_nodes(self, graph):
       if 'weight' in graph.es.attributes() and self.partition_type == leidenalg.SignificanceVertexPartition:
-        raise unittest.SkipTest('Significance doesn\'t handle weighted graphs');
+        raise unittest.SkipTest('Significance doesn\'t handle weighted graphs')
 
       if 'weight' in graph.es.attributes():
-        partition = self.partition_type(graph, weights='weight');
+        partition = self.partition_type(graph, weights='weight')
       else:
-        partition = self.partition_type(graph);
+        partition = self.partition_type(graph)
       for v in range(graph.vcount()):
         if graph.degree(v) >= 1:
-          u = graph.neighbors(v)[0];
-          diff = partition.diff_move(v, partition.membership[u]);
-          q1 = partition.quality();
-          partition.move_node(v, partition.membership[u]);
-          q2 = partition.quality();
+          u = graph.neighbors(v)[0]
+          diff = partition.diff_move(v, partition.membership[u])
+          q1 = partition.quality()
+          partition.move_node(v, partition.membership[u])
+          q2 = partition.quality()
           self.assertAlmostEqual(
               q2 - q1,
               diff,
               places=5,
               msg="Difference in quality ({0}) not equal to calculated difference ({1})".format(
-              q2 - q1, diff));
+              q2 - q1, diff))
 
     @data(*graphs)
     def test_aggregate_partition(self, graph):
       if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition:
-        partition = self.partition_type(graph, weights='weight');
+        partition = self.partition_type(graph, weights='weight')
       else:
-        partition = self.partition_type(graph);
-      self.optimiser.move_nodes(partition);
-      aggregate_partition = partition.aggregate_partition();
+        partition = self.partition_type(graph)
+      self.optimiser.move_nodes(partition)
+      aggregate_partition = partition.aggregate_partition()
       self.assertAlmostEqual(
           partition.quality(),
           aggregate_partition.quality(),
           places=5,
-          msg='Quality not equal for aggregate partition.');
-      self.optimiser.move_nodes(aggregate_partition);
-      partition.from_coarse_partition(aggregate_partition);
+          msg='Quality not equal for aggregate partition.')
+      self.optimiser.move_nodes(aggregate_partition)
+      partition.from_coarse_partition(aggregate_partition)
       self.assertAlmostEqual(
           partition.quality(),
           aggregate_partition.quality(),
           places=5,
-          msg='Quality not equal from coarser partition.');
+          msg='Quality not equal from coarser partition.')
 
     @data(*graphs)
     def test_total_weight_in_all_comms(self, graph):
       if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition:
-        partition = self.partition_type(graph, weights='weight');
+        partition = self.partition_type(graph, weights='weight')
       else:
-        partition = self.partition_type(graph);
-      self.optimiser.optimise_partition(partition);
-      s = sum([partition.total_weight_in_comm(c) for c,_ in enumerate(partition)]);
+        partition = self.partition_type(graph)
+      self.optimiser.optimise_partition(partition)
+      s = sum([partition.total_weight_in_comm(c) for c,_ in enumerate(partition)])
       self.assertAlmostEqual(
         s,
         partition.total_weight_in_all_comms(),
         places=5,
         msg='Total weight in all communities ({0}) not equal to the sum of the weight in all communities ({1}).'.format(
           s, partition.total_weight_in_all_comms())
-        );
+        )
 
     @data(*graphs)
     def test_copy(self, graph):
       if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition:
-        partition = self.partition_type(graph, weights='weight');
+        partition = self.partition_type(graph, weights='weight')
       else:
-        partition = self.partition_type(graph);
+        partition = self.partition_type(graph)
 
-      self.optimiser.optimise_partition(partition);
+      self.optimiser.optimise_partition(partition)
 
       partition2 = deepcopy(partition)
 
@@ -186,23 +181,23 @@ class BaseTest:
 
 class ModularityVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
   def setUp(self):
-    super(ModularityVertexPartitionTest, self).setUp();
-    self.partition_type = leidenalg.ModularityVertexPartition;
+    super(ModularityVertexPartitionTest, self).setUp()
+    self.partition_type = leidenalg.ModularityVertexPartition
 
 class RBERVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
   def setUp(self):
-    super(RBERVertexPartitionTest, self).setUp();
-    self.partition_type = leidenalg.RBERVertexPartition;
+    super(RBERVertexPartitionTest, self).setUp()
+    self.partition_type = leidenalg.RBERVertexPartition
 
 class RBConfigurationVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
   def setUp(self):
-    super(RBConfigurationVertexPartitionTest, self).setUp();
-    self.partition_type = leidenalg.RBConfigurationVertexPartition;
+    super(RBConfigurationVertexPartitionTest, self).setUp()
+    self.partition_type = leidenalg.RBConfigurationVertexPartition
 
 class CPMVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
   def setUp(self):
-    super(CPMVertexPartitionTest, self).setUp();
-    self.partition_type = leidenalg.CPMVertexPartition;
+    super(CPMVertexPartitionTest, self).setUp()
+    self.partition_type = leidenalg.CPMVertexPartition
 
   def test_Bipartite(self):
     graph = bipartite_graph
@@ -215,17 +210,17 @@ class CPMVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
 
 class SurpriseVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
   def setUp(self):
-    super(SurpriseVertexPartitionTest, self).setUp();
-    self.partition_type = leidenalg.SurpriseVertexPartition;
+    super(SurpriseVertexPartitionTest, self).setUp()
+    self.partition_type = leidenalg.SurpriseVertexPartition
 
 class SignificanceVertexPartitionTest(BaseTest.MutableVertexPartitionTest):
   def setUp(self):
-    super(SignificanceVertexPartitionTest, self).setUp();
-    self.partition_type = leidenalg.SignificanceVertexPartition;
+    super(SignificanceVertexPartitionTest, self).setUp()
+    self.partition_type = leidenalg.SignificanceVertexPartition
 
 #%%
 if __name__ == '__main__':
   #%%
-  unittest.main(verbosity=3);
-  suite = unittest.TestLoader().discover('.');
-  unittest.TextTestRunner(verbosity=1).run(suite);
+  unittest.main(verbosity=3)
+  suite = unittest.TestLoader().discover('.')
+  unittest.TextTestRunner(verbosity=1).run(suite)



View it on GitLab: https://salsa.debian.org/med-team/python-leidenalg/-/compare/d8851a3c61c3ab166e7137e7aa1bec8aba8bb2ac...6961a5fd4911492de35b798dfb9459cb870ce91d

-- 
View it on GitLab: https://salsa.debian.org/med-team/python-leidenalg/-/compare/d8851a3c61c3ab166e7137e7aa1bec8aba8bb2ac...6961a5fd4911492de35b798dfb9459cb870ce91d
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20210703/64d16d19/attachment-0001.htm>


More information about the debian-med-commit mailing list