For several years the Python world has been in a state of transition from
version 2.x to 3.x.  Much code still exists for Python2 in the form of
applications, modules, and packages and will likely be supported for some
time to come.  Python3 is gaining acceptance, especially with new
development and many modules and packages are now available for Python3.

The Python developers have taken care to ensure that Python2 and Python3
and their respective modules and packages can be installed concurrently.
The steps below take advantage of this feature to install Hamlib.py modules
for both Python versions.  Complete installation of each Python version
including their respective development files are required for successful
generation of the bindings by SWIG.

At this time the GNU Autotools do not offer a clean method of building SWIG
bindings for multiple versions of Python.  Some hacks can be found on the
Web but until a clean native solution is offered the steps in this document
should prove adequate.  With the wealth of Python2 programs, modules, and
packages still in use, it isn't likely to disappear from distributions
anytime soon.  Python3 is becoming more popular for new development with a
complete standard library and many modules and packages being ported over
and available.  It's time that we offer a means to generate bindings for
either version.  This document will provide the steps for doing so.

NOTE:  Developers and testers building from a Git clone/checkout will need
to bootstrap the build system by running the (appropriately named) 'bootstrap'
script.  Source releases and source daily snapshots already have this step
completed.

NOTE:  The commands assume an out of tree build in a sibling directory to
the main source directory.  Adjust your paths accordingly.  Adjust your
--prefix option as needed (installation to the user's home directory is
shown to avoid root privileges).

Assuming that Python2 is the default installed Python interpreter, build
its bindings first:

    ../hamlib/configure --with-python-binding --prefix=$HOME/local
    make
    make install

NOTE: Over time Python3 will become the default Python interpreter on most
distributions and the extra step will be needed for Python2 as detailed below.

At this point the Hamlib binaries, development files, and Python2 bindings
will be installed to their customary locations under $HOME/local.

Examination of the configure script's output will confirm that Python2 is
found and used as this extract shows:

checking whether to build python binding and demo... yes
checking for python... /usr/bin/python
checking for a version of Python >= '2.1.0'... yes
checking for the distutils Python package... yes
checking for Python include path... -I/usr/include/python2.7
checking for Python library path... -L/usr/lib64 -lpython2.7
checking for Python site-packages path... /usr/lib64/python2.7/site-packages
checking python extra libraries... -lpthread -ldl  -lutil -lm
checking python extra linking flags... -Xlinker -export-dynamic
checking consistency of all components of python development environment... yes
checking whether /usr/bin/python version is >= 2.1... yes
checking for /usr/bin/python version... 2.7
checking for /usr/bin/python platform... linux2
checking for /usr/bin/python script directory... ${prefix}/lib64/python2.7/site-packages
checking for /usr/bin/python extension module directory... ${exec_prefix}/lib64/python2.7/site-packages

At this point the file pytest.py in the source bindings directory may be
run as a test.  If an error is given that the Hamlib module cannot be
found, see below.

The next step is to configure and build for Python3:

    ../hamlib/configure --with-python-binding PYTHON_VERSION='3.6' --prefix=$HOME/local

If that doesn't work try:

    ../hamlib/configure --with-python-binding PYTHON=$(which python3) --prefix=$HOME/local

then do the build:

    cd bindings
    make

NOTE: By changing the current directory to 'bindings', only the new Python3
module will be compiled, which speeds things up considerably.

Here the PYTHON_VERSION environment variable is set to the Major.minor version
of Python we wish to build against.  The build system should be able to set
everything correctly from this environment variable.  If not, try the second
example line which sets the PYTHON environment variable to the first python3
executable found in the path (python3 may be a symbolic link, which is fine).
This may be unwanted behavior if multiple versions of Python are installed so
a specific version with the full path may also be provided.

Python3 was found as shown in this configure output extract:

checking whether to build python binding and demo... yes
checking for python3.6... /usr/bin/python3.6
checking for a version of Python >= '2.1.0'... yes
checking for the distutils Python package... yes
checking for Python include path... -I/usr/include/python3.6m
checking for Python library path... -L/usr/lib64 -lpython3.6m
checking for Python site-packages path... /usr/lib64/python3.6/site-packages
checking python extra libraries... -lpthread -ldl  -lutil -lm
checking python extra linking flags... -Xlinker -export-dynamic
checking consistency of all components of python development environment... yes
checking whether /usr/bin/python3.6 version is >= 2.1... yes
checking for /usr/bin/python3.6 version... 3.6
checking for /usr/bin/python3.6 platform... linux
checking for /usr/bin/python3.6 script directory... ${prefix}/lib64/python3.6/site-packages
checking for /usr/bin/python3.6 extension module directory... ${exec_prefix}/lib64/python3.6/site-packages

Since all the Makefiles were regenerated by the second run of configure,
hamlib will be compiled again.

Next install only the Python3 bindings (still in 'bindings' as the current
directory):

    make install

In this case, only the generated files in 'bindings' will be installed
which will be the new Python3 bindings.

Test that the Hamlib Python3 bindings are found by running the
bindings/py3test.py script.

At this point working bindings are installed and have been tested.

Running 'make uninstall' will only remove the version of the bindings that
was last configured.  To uninstall the other version the respective options
will need to be passed to 'configure' and 'make uninstall' run again.

What to do if Python complains the module cannot be found.

There are various ways that a specific path can be provided to Python.
Perhaps the easiest is to provide an environment variable to your script.

Since Python will not have $HOME/local/... in its search path, here is an
example:

    $ py3test.py
    Traceback (most recent call last):
      File "./py3test.py", line 9, in <module>
        import Hamlib
    ModuleNotFoundError: No module named 'Hamlib'

This isn't good!  Let's set an environment variable for the running script:

     PYTHONPATH=$HOME/local/lib64/python3.6/site-packages:$PYTHONPATH ./py3test.py

Success!

Like the standard PATH environment variable PYTHONPATH can contain multiple
paths separated by colons.  In this case, if PYTHONPATH was already set the
new path is prepended to its prior setting.

While setting the environment variable is good for a one-off run, a more
permanent solution can be achieved by placing a file that ends in .pth in a
directory that Python will process when starting.  The special place is:

    ~/.local/lib64/python3.6/site-packages

A .pth file must be set for each major.minor version of Python.  Here is an
example for Python 2.7:

    $HOME/.local/lib64/python2.7/site-packages/home.pth

Its content is simple:

    /home/username/local/lib64/python2.7/site-packages

(These examples are from a Slackware box which installs Python modules into
the 'lib64' directory.  Other distributions may simply use 'lib' or another
name.)

To verify the path, start the Python interpreter in interactive mode,
import the sys module, and check the value of sys.path.  It will show a
number of paths in the list including the ones above and the directory the
interpreter was started from and various system directories.

Far more information than this is available in the relevant Python
documentation, but this should get your scripts working.

Removing (uninstalling) the bindings can be done from the 'bindings'
directory.  Just be sure that 'configure' is run with the options for either
Python2 or Python3 first so that 'bindings/Makefile' will generated for the
version to be removed.

As always, feedback is welcome:

   Hamlib Developers <hamlib-developer@lists.sourceforge.net>

73, Nate, N0NB
