If you are trying to debug something like:

  ImportError: No module named ntp

or:

  ImportError: No module named gps

you have come to the right place.

Warning: Every distribution handles Python slightly differently.  It
also varies a lot by distribution version.  So grab your distribution
documentation as you read this.  Expect the examples here to differ
from what you see on your system.

When building NTPSec for installation, the install procedure asks the
current python for the proper location to install the python modules.
On most distributions the default location where we install our python
libraries is:

  /usr/local/lib/pythonX.Y/site-packages/

where X and Y are the python version numbers.  Y may be suffixed with
't' for threaded python versions.

Why does NTPSec install into /usr/local?

Look at the Filesystem Hierarchy Standard [FHS].  Specifically Version
3, Chapter 4:

    4.9.1. Purpose

    The /usr/local hierarchy is for use by the system administrator
    when installing software locally. It needs to be safe from being
    overwritten when the system software is updated. It may be used for
    programs and data that are shareable amongst a group of hosts, but
    not found in /usr.

The NTPSec build procedure, by default, is for "installing software
locally", so we install into /usr/local, not /usr. /usr is reserved for
the "system software".

Unfortunately, that's not on the default search path of several
OSes/distros, in particular Fedora, NetBSD, Gentoo, etc..
(Fixed in Fedora 39, Sep-2023, ??)

Python has search paths [PATHS] that are used to find library modules
when you import them.  You can see your search paths for Python 2 with:

    alice ~ # python2 -m site
    sys.path = [
        '/root',
        '/usr/local/lib/python3.12/site-packages',
        '/usr/lib64/python27.zip',
        '/usr/lib64/python2.7',
        '/usr/lib64/python2.7/plat-linux2',
        '/usr/lib64/python2.7/lib-tk',
        '/usr/lib64/python2.7/lib-old',
        '/usr/lib64/python2.7/lib-dynload',
        '/usr/lib64/python2.7/site-packages',
    ]
    USER_BASE: '/root/.local' (doesn't exist)
    USER_SITE: '/root/.local/lib64/python2.7/site-packages' (doesn't exist)
    ENABLE_USER_SITE: True

Or for Python 3:

    kong ~ # python3 -m site
    sys.path = [
        '/root',
        '/usr/local/lib/python3.13t/site-packages',
        '/usr/lib/python313t.zip',
        '/usr/lib/python3.13t',
        '/usr/lib/python3.13t/lib-dynload',
        '/usr/lib/python3.13t/site-packages',
    ]
    USER_BASE: '/root/.local' (exists)
    USER_SITE: '/root/.local/lib/python3.13t/site-packages' (doesn't exist)
    ENABLE_USER_SITE: True

What is the difference between 'site-packages' and 'dist-packages'?

This is where pip enters the discussion.  Some (Debian derived) distros
have the system installed (apt) call pip to install some system python
modules.  In that case:

1. Drectly installed (apt) system python packages go in:

     /usr/lib/pythonX.Y/

2. Indirectly installed (apt called pip)  python packages go in

    /usr/lib/pythonX.Y/dist-packages/

3. User installed (user called pip) python packages go in

    /usr/local/lib/pythonX.Y/dist-packages/

4. User installed (user compiled) python packages go in

    /usr/local/lib/pythonX.Y/site-packages/

So dist-packages means the package is managed by pip.  Split into
when the system installed using pip, or the user installed using pip.

And site-packages means the package is not managed by the system (apt)
or by pip.  That would be user compilef NTPSec and gpsd.

More detail at [DEVIANT]

There are several ways to make user compiled and installed packages
work.

1: You can modify the location where waf will install the libraries.
For NetBSD, something like this should work:

  ./waf configure \
    --pythondir=/usr/pkg/lib/python2.7/site-packages \
    --pythonarchdir=/usr/pkg/lib/python2.7/site-packages \
    ...

You need to specify it at configure time.  Install time is too late.

Note: Distros do not want users installing modules in the
distro reserved areas.  It violates the FHS.

2: You can setup your PYTHONPATH with something like this:

  export PYTHONPATH=/usr/local/lib/python3.13t/site-packages

See [PATHS].

For bash, you can add that line to your .bashrc or the system
/etc/bashrc If you don't put it in the system file, all users will have
to do this, every time they login login.  Including root if root uses
any ntp scripts.

3: You can add to the default search path by setting up a .pth file
with something like this:

  echo /usr/local/lib64/python3.11/site-packages > \
    /usr/lib/python3.11/site-packages/ntpsec.pth

This works for all users, including root.
Note that the pth file must be on the default Python search path.

OTOH if you run into something like:

    Traceback (most recent call last):
      File "/usr/bin/ntpdig", line 419, in <module>
        timeout=timeout)
      File "/usr/bin/ntpdig", line 109, in queryhost
        keyid, keytype, passwd)
      File "/usr/lib/python3/dist-packages/ntp/packet.py", line 1747, in compute_mac
        if not ntp.ntpc.checkname(keytype):
    AttributeError: module 'ntp.ntpc' has no attribute 'checkname'

Then you probably want to either uninstall the previous Python extension, or
install one after 1.1.9 (798b93) by adding the '--enable-pylib ext' option
without quotes.

OTOH if you are running into something like:

    Traceback (most recent call last):
    File "/usr/bin/ntpdig", line 19, in <module>
        import ntp.packet
    File "/usr/lib/python3/dist-packages/ntp/packet.py", line 219, in <module>
        import ntp.ntpc
    File "/usr/lib/python3/dist-packages/ntp/ntpc.py", line 52, in <module>
        _ntpc = _importado()
    File "/usr/lib/python3/dist-packages/ntp/ntpc.py", line 38, in _importado
        return _dlo(ntpc_paths)
    File "/usr/lib/python3/dist-packages/ntp/ntpc.py", line 49, in _dlo
        raise OSError("Can't find %s library" % LIB)
    OSError: Can't find ntpc library

That means that ntpc.py looked for libntpc.so in the usual places and could
not find it.  If it is being installed to the wrong location on your platform,
you can correct the install location using: waf configure --libdir=  If you
are intentionally installing to a non-default location, you can modify the
dynamic linker's search path globally (e.g. /etc/ld.so.conf or
/etc/ld.so.conf.d/) or in your environment (e.g. LD_LIBRARY_PATH).

On some platforms, it is necessary to run ldconfig after installing libraries.
This is normally done by the waf install step, but it may have failed.  When
using a temporary --destdir (e.g. as part of package builds), ldconfig must be
run manually after the library is installed to its final location.

What about "virtual environments"?

Virtual Environments (venv) [VENV] are a way for a user to install
python version 3 modules for a specific user, and specific use, without
interfering with other modules installed by the specific user, or the
system wide python.  Since NTPSec, and gpsd, are intended to be used by
root, and all users, on a system, it is not appropriate to use install
them into a venv.

How do 'python', 'python2' and 'python3' differ?

Upstream tackles this issue in Python Enhancement Proposal (PEP) 394,
named 'The “python” Command on Unix-Like Systems'[PEP394].  Be
careful to use the latest PEP 394 version, they keep changing their
minds.

    "Depending on a distribution or system configuration, python may or
    may not be installed. If python is installed its target interpreter
    may refer to python2 or python3. "

So, no help at all.  But well worth reading the entire PEP.  You need to
refer to your distributions documentation, if you can find it.

When in doubt, since python2 is, still, almost dead, use python3.

Sadly, every distribution has a slightly different answer to changing the
python linkage.  Changing an existing python link often has unintended
consequences.

Ubuntu: Ubuntu does not trust the sysadmin to understand symlinks.
To point python to python3:

    apt install python-is-python3

To point python to python2:

    apt install python-is-python2

Gentoo: Gentoo allows the user to configure what Python version the
'python' command points to with this command:

    eselect python list


TODO: 

Look into using .pth files to avoid much of this mess.

References:

[FHS] Filesystem Hierarchy Standard Version 3.0
      https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html

[DEVIANT]  Debian Python Wiki -- Deviations from upstream
           https://wiki.debian.org/Python#Deviations_from_upstream

[PATHS] The Module Search Path
        https://docs.python.org/2/tutorial/modules.html#the-module-search-path
        https://docs.python.org/3/tutorial/modules.html#the-module-search-path

[VENV] venv — Creation of virtual environments¶
       https://docs.python.org/3/library/venv.html

[PEP394] PEP 394 – The “python” Command on Unix-Like Systems
         https://peps.python.org/pep-0394/
