diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml
index 7bf0902c54be06d4bde8180bbb3f31ceb134c949..cc862780005bb4f4ad452224d8e23198002777ad 100644
--- a/.github/workflows/basic.yml
+++ b/.github/workflows/basic.yml
@@ -74,7 +74,7 @@ jobs:
         run: |
           mkdir build
           cd build
-          cmake .. -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_PYTHON=ON -DPYTHON_EXECUTABLE=`which python` -DARB_WITH_MPI=${{ matrix.mpi }}
+          cmake .. -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_PYTHON=ON -DPython3_EXECUTABLE=`which python` -DARB_WITH_MPI=${{ matrix.mpi }}
           make -j4 tests examples pyarb html
           cd -
       - name: Run unit tests
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6ecf73b038f200afc419bd0210b34664ded7e908..e8c755ad103a2246cdcce9cb99923be0e75c2d88 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -231,12 +231,28 @@ endif()
 
 # Python bindings
 #----------------------------------------------------------
+
+# The minimum version of Python supported by Arbor.
+set(arb_py_version 3.6.0)
 if(ARB_WITH_PYTHON)
+    find_package(Python3 ${arb_py_version} COMPONENTS Interpreter Development REQUIRED)
+    set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}")
+    message(STATUS "PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}")
+
     # Required to link the dynamic libraries for python modules.
     # Effectively adds '-fpic' flag to CXX_FLAGS.
     set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+else()
+    # If not building the Python module, the interpreter is still required
+    # to build some targets, e.g. when building the documentation.
+    find_package(Python3 ${arb_py_version} COMPONENTS Interpreter)
+    if(Python3_FOUND)
+        set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}")
+        message(STATUS "PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}")
+    endif()
 endif()
 
+
 # Threading model
 #-----------------
 
diff --git a/doc/conf.py b/doc/conf.py
index 4857f8765a7aa703ab3e7c05d1515c16a18796b8..05d6fe4500788c28175b393d3f8a56ca13ef6a2a 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -45,18 +45,13 @@ this_path=os.path.split(os.path.abspath(__file__))[0]
 script_path=this_path+'/scripts'
 sys.path.append(script_path)
 
+# Output path for generated images
 # Dump inputs.py into tmpdir
-with TemporaryDirectory() as tmp:
-    sp.run([sys.executable, this_path + '/scripts/gen-labels.py', tmp])
-    sys.path.append(tmp)
+img_path=this_path+'/gen-images'
+if not os.path.exists(img_path):
+    os.mkdir(img_path)
 
-    import make_images
-
-    # Output path for generated images
-    img_path=this_path+'/gen-images'
-    if not os.path.exists(img_path):
-        os.mkdir(img_path)
-
-    make_images.generate(img_path)
+import make_images
+make_images.generate(img_path)
 
 print("-------------------------")
diff --git a/doc/install/build_install.rst b/doc/install/build_install.rst
index 0dc51f899638589d0d6b1399a70d231a1af70e7b..2319d0cbbf2fe912f4f31c22ad95fa954db3226e 100644
--- a/doc/install/build_install.rst
+++ b/doc/install/build_install.rst
@@ -414,18 +414,19 @@ CMake ``ARB_WITH_PYTHON`` option:
 By default ``ARB_WITH_PYTHON=OFF``. When this option is turned on, a Python module called :py:mod:`arbor` is built.
 
 A specific version of Python can be set when configuring with CMake using the
-``PYTHON_EXECUTABLE`` variable. For example, to use Python 3.8 installed on a Linux
+``Python3_EXECUTABLE`` variable. For example, to use Python 3.8 installed on a Linux
 system with the executable in ``/usr/bin/python3.8``:
 
 .. code-block:: bash
 
-    cmake .. -DARB_WITH_PYTHON=ON -DPYTHON_EXECUTABLE=/usr/bin/python3.8
+    cmake .. -DARB_WITH_PYTHON=ON -DPython3_EXECUTABLE=/usr/bin/python3.8
 
 By default the Python module will be installed in the directory returned by
-``${PYTHON_EXECUTABLE} -c "import sysconfig; print(sysconfig.get_path('platlib'))"``.
-This returns the directory where the supplied or found PYTHON_EXECUTABLE looks for system packages.
+``${Python3_EXECUTABLE} -c "import sysconfig; print(sysconfig.get_path('platlib'))"``.
+This returns the directory where the supplied or found ``Python3_EXECUTABLE`` looks for system packages.
 `See Python's sysconfig documentation <https://docs.python.org/3/library/sysconfig.html#installation-paths>`_.
-If CMake is run in a `venv` or Conda environment, this should pick up on the appropriate package directory. To install the module in a different location, set ``ARB_PYTHON_LIB_PATH`` to a custom path.
+If CMake is run in a `venv` or Conda environment, this should pick up on the appropriate package directory.
+To install the module in a different location, set ``ARB_PYTHON_LIB_PATH`` to a custom path.
 For example, the CMake configuration for targeting Python 3.8 and install as a
 user site package might look like the following:
 
@@ -433,20 +434,11 @@ user site package might look like the following:
 
     cmake .. -DARB_WITH_PYTHON=ON                                              \
              -DARB_PYTHON_LIB_PATH=${HOME}/.local/lib/python3.8/site-packages/ \
-             -DPYTHON_EXECUTABLE=/usr/bin/python3.8
+             -DPython3_EXECUTABLE=/usr/bin/python3.8
 
 On the target LINUX system, the Arbor package was installed in
 ``/home/$USER/.local/lib/python3.8/site-packages``.
 
-.. Note::
-    By default CMake sets ``CMAKE_INSTALL_PREFIX`` to ``/usr/local`` on Linux and OS X.
-    The compiled libraries are installed in ``/usr/local/lib``, headers are installed in
-    ``/usr/local/include``, and the Python module will be installed in a path like
-    ``/usr/local/lib/python3.8/site-packages``.
-    Because ``/usr/local`` is a system path, the installation phase needs to be run as root,
-    i.e. ``sudo make install``, even if ``ARB_PYTHON_LIB_PATH`` is set to a user path
-    that does not require root to install.
-
 The Arbor Python wrapper has optional support for the mpi4py, though
 it is not required to use Arbor with Python and MPI.
 CMake will attempt to automatically detect ``mpi4py`` if configured
diff --git a/doc/install/python.rst b/doc/install/python.rst
index d515bf12df85843d097b9b9f47b95fcb61a9f6a8..051836fa1c06044de38c9132728252b50b4ca303 100644
--- a/doc/install/python.rst
+++ b/doc/install/python.rst
@@ -3,8 +3,10 @@
 Python Installation
 ===================
 
-Arbor's Python API will be the most convenient interface for most users. Note that we support Python 3.6 and later.
-Any instruction hereafter assumes you're using `python` and `pip` no older than that.
+Arbor's Python API will be the most convenient interface for most users.
+
+.. note::
+    Arbor requires Python version 3.6 and later.
 
 Getting Arbor
 -------------
diff --git a/doc/scripts/inputs.py b/doc/scripts/inputs.py
new file mode 100644
index 0000000000000000000000000000000000000000..11d7da670fcc6d3953217df3ba4eef1d8d50095e
--- /dev/null
+++ b/doc/scripts/inputs.py
@@ -0,0 +1,165 @@
+import representation
+from representation import Segment
+
+############# morphologies
+
+tmp = [
+    [[Segment((0.0, 0.0, 2.0), (4.0, 0.0, 2.0), 1), Segment((4.0, 0.0, 0.8), (8.0, 0.0, 0.8), 3), Segment((8.0, 0.0, 0.8), (12.0, -0.5, 0.8), 3)]],
+    [[Segment((12.0, -0.5, 0.8), (20.0, 4.0, 0.4), 3), Segment((20.0, 4.0, 0.4), (26.0, 6.0, 0.2), 3)]],
+    [[Segment((12.0, -0.5, 0.5), (19.0, -3.0, 0.5), 3)]],
+    [[Segment((19.0, -3.0, 0.5), (24.0, -7.0, 0.2), 3)]],
+    [[Segment((19.0, -3.0, 0.5), (23.0, -1.0, 0.2), 3), Segment((23.0, -1.0, 0.2), (26.0, -2.0, 0.2), 3)]],
+    [[Segment((0.0, 0.0, 2.0), (-7.0, 0.0, 0.4), 2), Segment((-7.0, 0.0, 0.4), (-10.0, 0.0, 0.4), 2)]],]
+label_morph = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 2.0), (4.0, 0.0, 2.0), 1)], [Segment((5.0, 0.0, 0.8), (8.0, 0.0, 0.8), 3), Segment((8.0, 0.0, 0.8), (12.0, -0.5, 0.8), 3)]],
+    [[Segment((12.0, -0.5, 0.8), (20.0, 4.0, 0.4), 3), Segment((20.0, 4.0, 0.4), (26.0, 6.0, 0.2), 3)]],
+    [[Segment((12.0, -0.5, 0.5), (19.0, -3.0, 0.5), 3)]],
+    [[Segment((19.0, -3.0, 0.5), (24.0, -7.0, 0.2), 3)]],
+    [[Segment((19.0, -3.0, 0.5), (23.0, -1.0, 0.2), 3), Segment((23.0, -1.0, 0.2), (26.0, -2.0, 0.2), 3)]],
+    [[Segment((-2.0, 0.0, 0.4), (-10.0, 0.0, 0.4), 2)]],]
+detached_morph = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 0.5), (1.0, 0.0, 1.5), 1), Segment((1.0, 0.0, 1.5), (2.0, 0.0, 2.5), 1), Segment((2.0, 0.0, 2.5), (3.0, 0.0, 2.5), 1), Segment((3.0, 0.0, 2.5), (4.0, 0.0, 1.2), 1), Segment((4.0, 0.0, 0.8), (8.0, 0.0, 0.8), 3), Segment((8.0, 0.0, 0.8), (12.0, -0.5, 0.8), 3)]],
+    [[Segment((12.0, -0.5, 0.8), (20.0, 4.0, 0.4), 3), Segment((20.0, 4.0, 0.4), (26.0, 6.0, 0.2), 3)]],
+    [[Segment((12.0, -0.5, 0.5), (19.0, -3.0, 0.5), 3)]],
+    [[Segment((19.0, -3.0, 0.5), (24.0, -7.0, 0.2), 3)]],
+    [[Segment((19.0, -3.0, 0.5), (23.0, -1.0, 0.2), 3), Segment((23.0, -1.0, 0.2), (26.0, -2.0, 0.2), 3)]],
+    [[Segment((0.0, 0.0, 0.4), (-7.0, 0.0, 0.4), 2), Segment((-7.0, 0.0, 0.4), (-10.0, 0.0, 0.4), 2)]],]
+stacked_morph = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((-2.0, 0.0, 2.0), (2.0, 0.0, 2.0), 1)]],]
+sphere_morph = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 1.0), (10.0, 0.0, 0.5), 3)]],]
+branch_morph1 = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 1.0), (3.0, 0.2, 0.8), 1), Segment((3.0, 0.2, 0.8), (5.0, -0.1, 0.7), 2), Segment((5.0, -0.1, 0.7), (8.0, 0.0, 0.6), 2), Segment((8.0, 0.0, 0.6), (10.0, 0.0, 0.5), 3)]],]
+branch_morph2 = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 1.0), (3.0, 0.2, 0.8), 1), Segment((3.0, 0.2, 0.8), (5.0, -0.1, 0.7), 2)], [Segment((6.0, -0.1, 0.7), (9.0, 0.0, 0.6), 2), Segment((9.0, 0.0, 0.6), (11.0, 0.0, 0.5), 3)]],]
+branch_morph3 = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 1.0), (3.0, 0.2, 0.8), 1), Segment((3.0, 0.2, 0.8), (5.0, -0.1, 0.7), 2), Segment((5.0, -0.1, 0.7), (8.0, 0.0, 0.5), 2), Segment((8.0, 0.0, 0.3), (10.0, 0.0, 0.5), 3)]],]
+branch_morph4 = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 1.0), (10.0, 0.0, 0.5), 3)]],
+    [[Segment((10.0, 0.0, 0.5), (15.0, 3.0, 0.2), 3)]],
+    [[Segment((10.0, 0.0, 0.5), (15.0, -3.0, 0.2), 3)]],]
+yshaped_morph = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((-3.0, 0.0, 3.0), (3.0, 0.0, 3.0), 1)], [Segment((4.0, -1.0, 0.6), (10.0, -2.0, 0.5), 3), Segment((10.0, -2.0, 0.5), (15.0, -1.0, 0.5), 3)]],
+    [[Segment((15.0, -1.0, 0.5), (18.0, -5.0, 0.3), 3)]],
+    [[Segment((15.0, -1.0, 0.5), (20.0, 2.0, 0.3), 3)]],]
+ysoma_morph1 = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((-3.0, 0.0, 3.0), (3.0, 0.0, 3.0), 1)]],
+    [[Segment((4.0, -1.0, 0.6), (10.0, -2.0, 0.5), 3), Segment((10.0, -2.0, 0.5), (15.0, -1.0, 0.5), 3)]],
+    [[Segment((15.0, -1.0, 0.5), (18.0, -5.0, 0.3), 3)]],
+    [[Segment((15.0, -1.0, 0.5), (20.0, 2.0, 0.3), 3)]],
+    [[Segment((2.0, 1.0, 0.6), (12.0, 4.0, 0.5), 3)]],
+    [[Segment((12.0, 4.0, 0.5), (18.0, 4.0, 0.3), 3)]],
+    [[Segment((12.0, 4.0, 0.5), (16.0, 9.0, 0.1), 3)]],
+    [[Segment((-3.5, 0.0, 1.5), (-6.0, -0.2, 0.5), 2), Segment((-6.0, -0.2, 0.5), (-15.0, -0.1, 0.5), 2)]],]
+ysoma_morph2 = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((-3.0, 0.0, 3.0), (3.0, 0.0, 3.0), 1)]],
+    [[Segment((3.0, 0.0, 0.6), (9.0, -1.0, 0.5), 3), Segment((9.0, -1.0, 0.5), (14.0, 0.0, 0.5), 3)]],
+    [[Segment((14.0, 0.0, 0.5), (17.0, -4.0, 0.3), 3)]],
+    [[Segment((14.0, 0.0, 0.5), (19.0, 3.0, 0.3), 3)]],
+    [[Segment((3.0, 0.0, 0.6), (13.0, 3.0, 0.5), 3)]],
+    [[Segment((13.0, 3.0, 0.5), (19.0, 3.0, 0.3), 3)]],
+    [[Segment((13.0, 3.0, 0.5), (17.0, 8.0, 0.1), 3)]],
+    [[Segment((-3.0, 0.0, 1.5), (-5.5, -0.2, 0.5), 2), Segment((-5.5, -0.2, 0.5), (-14.5, -0.1, 0.5), 2)]],]
+ysoma_morph3 = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 2.0), (4.0, 0.0, 2.0), 1), Segment((4.0, 0.0, 0.8), (8.0, 0.0, 0.8), 3), Segment((8.0, 0.0, 0.8), (12.0, -0.5, 0.8), 3)]],
+    [[Segment((12.0, -0.5, 0.8), (20.0, 4.0, 0.4), 3), Segment((20.0, 4.0, 0.4), (26.0, 6.0, 0.2), 3)]],
+    [[Segment((12.0, -0.5, 0.5), (19.0, -3.0, 0.5), 3)]],
+    [[Segment((19.0, -3.0, 0.5), (24.0, -7.0, 0.2), 4)]],
+    [[Segment((19.0, -3.0, 0.5), (23.0, -1.0, 0.2), 4), Segment((23.0, -1.0, 0.2), (36.0, -2.0, 0.2), 4)]],
+    [[Segment((0.0, 0.0, 2.0), (-7.0, 0.0, 0.4), 2), Segment((-7.0, 0.0, 0.4), (-10.0, 0.0, 0.4), 2)]],]
+tutorial_morph = representation.make_morph(tmp)
+
+tmp = [
+    [[Segment((0.0, 0.0, 1.0), (2.0, 0.0, 1.0), 1), Segment((2.0, 0.0, 1.0), (20.0, 0.0, 1.0), 3)]],
+    [[Segment((0.0, 0.0, 1.0), (-3.0, 0.0, 0.7), 2)]],]
+swc_morph = representation.make_morph(tmp)
+
+
+############# locsets (label_morph)
+
+ls_root  = {'type': 'locset', 'value': [(0, 0.0)]}
+ls_term  = {'type': 'locset', 'value': [(1, 1.0), (3, 1.0), (4, 1.0), (5, 1.0)]}
+ls_rand_dend  = {'type': 'locset', 'value': [(0, 0.5547193370156588), (0, 0.5841758202819731), (0, 0.607192003545501), (0, 0.6181091003428546), (0, 0.6190845627201184), (0, 0.7027325639263277), (0, 0.7616129092226993), (0, 0.9645150497869694), (1, 0.15382287505908834), (1, 0.2594719824047551), (1, 0.28087652335178354), (1, 0.3729681478609085), (1, 0.3959560134241004), (1, 0.4629424550242548), (1, 0.47346867377446744), (1, 0.5493486883630476), (1, 0.6227685370674116), (1, 0.6362196581003494), (1, 0.6646511214508091), (1, 0.7157318936458146), (1, 0.7464198558822775), (1, 0.77074507802833), (1, 0.7860238136304932), (1, 0.8988928261704698), (1, 0.9581259332943499), (2, 0.12773985425987294), (2, 0.3365926476076694), (2, 0.44454300804769703), (2, 0.5409466695719178), (2, 0.5767511435223905), (2, 0.6340206909931745), (2, 0.6354772583375223), (2, 0.6807941995943213), (2, 0.774655947503608), (3, 0.05020708596877571), (3, 0.25581431877212274), (3, 0.2958305460715556), (3, 0.296698184761692), (3, 0.509669134988683), (3, 0.7662305637426007), (3, 0.8565839889923518), (3, 0.8889077221517746), (4, 0.24311286693286885), (4, 0.4354361205546333), (4, 0.4467752481260171), (4, 0.5308169153994543), (4, 0.5701465671464049), (4, 0.670081739879954), (4, 0.6995486862583797), (4, 0.8186709628604206), (4, 0.9141224600171143)]}
+ls_loc15  = {'type': 'locset', 'value': [(1, 0.5)]}
+ls_uniform0  = {'type': 'locset', 'value': [(0, 0.5841758202819731), (1, 0.6362196581003494), (1, 0.7157318936458146), (1, 0.7464198558822775), (2, 0.6340206909931745), (2, 0.6807941995943213), (3, 0.296698184761692), (3, 0.509669134988683), (3, 0.7662305637426007), (4, 0.5701465671464049)]}
+ls_uniform1  = {'type': 'locset', 'value': [(0, 0.9778060763285382), (1, 0.19973428495790843), (1, 0.8310607916260988), (2, 0.9210229159315735), (2, 0.9244292525837472), (2, 0.9899772550845479), (3, 0.9924233395972087), (4, 0.3641426305909531), (4, 0.4787812247064867), (4, 0.5138656268861914)]}
+ls_branchmid  = {'type': 'locset', 'value': [(0, 0.5), (1, 0.5), (2, 0.5), (3, 0.5), (4, 0.5), (5, 0.5)]}
+ls_distal  = {'type': 'locset', 'value': [(1, 0.796025976329944), (3, 0.6666666666666667), (4, 0.39052429175127), (5, 1.0)]}
+ls_proximal  = {'type': 'locset', 'value': [(1, 0.29602597632994393), (2, 0.0), (5, 0.6124999999999999)]}
+ls_distint_in  = {'type': 'locset', 'value': [(1, 0.5), (2, 0.7), (5, 0.1)]}
+ls_proxint_in  = {'type': 'locset', 'value': [(1, 0.8), (2, 0.3)]}
+ls_loctest  = {'type': 'locset', 'value': [(1, 1.0), (2, 0.0), (5, 0.0)]}
+ls_restrict  = {'type': 'locset', 'value': [(1, 1.0), (3, 1.0), (4, 1.0)]}
+
+############# regions (label_morph)
+
+reg_empty = {'type': 'region', 'value': []}
+reg_all = {'type': 'region', 'value': [(0, 0.0, 1.0), (1, 0.0, 1.0), (2, 0.0, 1.0), (3, 0.0, 1.0), (4, 0.0, 1.0), (5, 0.0, 1.0)]}
+reg_tag1 = {'type': 'region', 'value': [(0, 0.0, 0.3324708796524168)]}
+reg_tag2 = {'type': 'region', 'value': [(5, 0.0, 1.0)]}
+reg_tag3 = {'type': 'region', 'value': [(0, 0.3324708796524168, 1.0), (1, 0.0, 1.0), (2, 0.0, 1.0), (3, 0.0, 1.0), (4, 0.0, 1.0)]}
+reg_tag4 = {'type': 'region', 'value': []}
+reg_soma = {'type': 'region', 'value': [(0, 0.0, 0.3324708796524168)]}
+reg_axon = {'type': 'region', 'value': [(5, 0.0, 1.0)]}
+reg_dend = {'type': 'region', 'value': [(0, 0.3324708796524168, 1.0), (1, 0.0, 1.0), (2, 0.0, 1.0), (3, 0.0, 1.0), (4, 0.0, 1.0)]}
+reg_radlt5 = {'type': 'region', 'value': [(1, 0.44403896449491587, 1.0), (3, 0.0, 1.0), (4, 0.0, 1.0), (5, 0.65625, 1.0)]}
+reg_radle5 = {'type': 'region', 'value': [(1, 0.44403896449491587, 1.0), (2, 0.0, 1.0), (3, 0.0, 1.0), (4, 0.0, 1.0), (5, 0.65625, 1.0)]}
+reg_radgt5 = {'type': 'region', 'value': [(0, 0.0, 1.0), (1, 0.0, 0.44403896449491587), (5, 0.0, 0.65625)]}
+reg_radge5 = {'type': 'region', 'value': [(0, 0.0, 1.0), (1, 0.0, 0.44403896449491587), (2, 0.0, 1.0), (3, 0.0, 0.0), (4, 0.0, 0.0), (5, 0.0, 0.65625)]}
+reg_rad36 = {'type': 'region', 'value': [(1, 0.29602597632994393, 0.796025976329944), (2, 0.0, 1.0), (3, 0.0, 0.6666666666666667), (4, 0.0, 0.39052429175127), (5, 0.6124999999999999, 1.0)]}
+reg_branch0 = {'type': 'region', 'value': [(0, 0.0, 1.0)]}
+reg_branch3 = {'type': 'region', 'value': [(3, 0.0, 1.0)]}
+reg_segment0 = {'type': 'region', 'value': [(0, 0.0, 0.3324708796524168)]}
+reg_segment3 = {'type': 'region', 'value': [(1, 0.0, 0.5920519526598877)]}
+reg_cable_1_01 = {'type': 'region', 'value': [(1, 0.0, 1.0)]}
+reg_cable_1_31 = {'type': 'region', 'value': [(1, 0.3, 1.0)]}
+reg_cable_1_37 = {'type': 'region', 'value': [(1, 0.3, 0.7)]}
+reg_proxint = {'type': 'region', 'value': [(0, 0.7697564611867647, 1.0), (1, 0.4774887508467626, 0.8), (2, 0.0, 0.3)]}
+reg_proxintinf = {'type': 'region', 'value': [(0, 0.0, 1.0), (1, 0.0, 0.8), (2, 0.0, 0.3)]}
+reg_distint = {'type': 'region', 'value': [(1, 0.5, 0.8225112491532374), (2, 0.7, 1.0), (3, 0.0, 0.432615327328525), (4, 0.0, 0.3628424955125098), (5, 0.1, 0.6)]}
+reg_distintinf = {'type': 'region', 'value': [(1, 0.5, 1.0), (2, 0.7, 1.0), (3, 0.0, 1.0), (4, 0.0, 1.0), (5, 0.1, 1.0)]}
+reg_lhs = {'type': 'region', 'value': [(0, 0.5, 1.0), (1, 0.0, 0.5)]}
+reg_rhs = {'type': 'region', 'value': [(1, 0.0, 1.0)]}
+reg_and = {'type': 'region', 'value': [(1, 0.0, 0.5)]}
+reg_or = {'type': 'region', 'value': [(0, 0.5, 1.0), (1, 0.0, 1.0)]}
+
+############# locsets (tutorial_morph)
+
+tut_ls_root  = {'type': 'locset', 'value': [(0, 0.0)]}
+tut_ls_terminal  = {'type': 'locset', 'value': [(1, 1.0), (3, 1.0), (4, 1.0), (5, 1.0)]}
+tut_ls_custom_terminal  = {'type': 'locset', 'value': [(3, 1.0), (4, 1.0)]}
+tut_ls_axon_terminal  = {'type': 'locset', 'value': [(5, 1.0)]}
+
+############# regions (tutorial_morph)
+
+tut_reg_all = {'type': 'region', 'value': [(0, 0.0, 1.0), (1, 0.0, 1.0), (2, 0.0, 1.0), (3, 0.0, 1.0), (4, 0.0, 1.0), (5, 0.0, 1.0)]}
+tut_reg_soma = {'type': 'region', 'value': [(0, 0.0, 0.3324708796524168)]}
+tut_reg_axon = {'type': 'region', 'value': [(5, 0.0, 1.0)]}
+tut_reg_dend = {'type': 'region', 'value': [(0, 0.3324708796524168, 1.0), (1, 0.0, 1.0), (2, 0.0, 1.0)]}
+tut_reg_last = {'type': 'region', 'value': [(3, 0.0, 1.0), (4, 0.0, 1.0)]}
+tut_reg_rad_gt = {'type': 'region', 'value': [(0, 0.0, 0.3324708796524168), (5, 0.0, 0.21875)]}
+tut_reg_custom = {'type': 'region', 'value': [(0, 0.0, 0.3324708796524168), (3, 0.0, 1.0), (4, 0.0, 1.0), (5, 0.0, 0.21875)]}
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index f20ffe2dc0eca971060a13a3c39f9648c6f97b36..de34bf4786fd12518164e0787260dd70c38f5228 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -79,5 +79,6 @@ file(COPY "${PROJECT_SOURCE_DIR}/VERSION" DESTINATION "${python_mod_path}")
 execute_process (COMMAND ${PYTHON_EXECUTABLE} -c "import sysconfig; print(sysconfig.get_path('platlib'))" OUTPUT_VARIABLE ARB_PYTHON_LIB_PATH_DEFAULT OUTPUT_STRIP_TRAILING_WHITESPACE)
 # Default to installing in that path, override with user specified ARB_PYTHON_LIB_PATH
 set(ARB_PYTHON_LIB_PATH ${ARB_PYTHON_LIB_PATH_DEFAULT} CACHE PATH "path for installing Python module for Arbor.")
+message(STATUS "Python module installation path: ${ARB_PYTHON_LIB_PATH}")
 
 install(DIRECTORY ${python_mod_path} DESTINATION ${ARB_PYTHON_LIB_PATH})
diff --git a/setup.py b/setup.py
index 5bd2338b7081188faf6cb78806a9c13af2bcdc4b..02c16f0db4350685d541553315312c2b756c7653 100644
--- a/setup.py
+++ b/setup.py
@@ -101,7 +101,7 @@ class cmake_build(build_ext):
         opt = cl_opt()
         cmake_args = [
             '-DARB_WITH_PYTHON=on',
-            '-DPYTHON_EXECUTABLE=' + sys.executable,
+            '-DPython3_EXECUTABLE=' + sys.executable,
             '-DARB_WITH_MPI={}'.format( 'on' if opt['mpi'] else 'off'),
             '-DARB_VECTORIZE={}'.format('on' if opt['vec'] else 'off'),
             '-DARB_ARCH={}'.format(opt['arch']),