neOn
neOn

Reputation: 21

How python36 initialise PYTHONPATH?

Two newly installed from the same scratch VMs with the same python36 versions have different values for sys.path:

1st VM

[root@vm1 ~]# python36 -m site
sys.path = [
    '/root',
    '/usr/lib64/python36.zip',
    '/usr/lib64/python3.6',
    '/usr/lib64/python3.6/lib-dynload',
    '/usr/lib64/python3.6/site-packages',
    '/usr/lib/python3.6/site-packages',
]
USER_BASE: '/root/.local' (doesn't exist)
USER_SITE: '/root/.local/lib/python3.6/site-packages' (doesn't exist)
ENABLE_USER_SITE: True

2nd VM

[root@vm2 ~]# python36 -m site
sys.path = [
    '/root',
    '/usr/lib64/python36.zip',
    '/usr/lib64/python3.6',
    '/usr/lib64/python3.6/lib-dynload',
    '/usr/local/lib64/python3.6/site-packages',
    '/usr/local/lib/python3.6/site-packages',
    '/usr/lib64/python3.6/site-packages',
    '/usr/lib/python3.6/site-packages',
]
USER_BASE: '/root/.local' (doesn't exist)
USER_SITE: '/root/.local/lib/python3.6/site-packages' (doesn't exist)
ENABLE_USER_SITE: True

2nd VM has /usr/local/lib* paths for some reasons.

os.environ on both machines shows the same values for variables:

How python36 initialise PYTHONPATH(sys.path) during initial installation, when no custom values at OS side for PYTHONPATH are configured?

Upvotes: 1

Views: 1391

Answers (1)

abarnert
abarnert

Reputation: 365587

A normal installation is expected to be able to run without any PYTHONPATH environment variable at all. As explained in the docs, PYTHONPATH is there for the user, to…

Augment the default search path for module files. The format is the same as the shell’s PATH: one or more directory pathnames separated by os.pathsep (e.g. colons on Unix or semicolons on Windows). Non-existent directories are silently ignored.

So, none of the standard Python installers (that includes building locally and running make install, and the Windows and macOS binary installers available under Downloads at python.org) do anything at all to create a PYTHONPATH value or get it set up in your environment. And most semi-official and third-party packages (like the Pythons includes or packaged by Linux distros and by Apple, the less-common-platforms installers under Downloads/Other, "batteries plus" Python distributions like Anaconda, etc.) will work the same way.


Notice that the PYTHONPATH directories are added to the default search path. As noted in the same docs:

The default search path is installation dependent, but generally begins with prefix/lib/pythonversion (see PYTHONHOME above). It is always appended to PYTHONPATH.

An additional directory will be inserted in the search path in front of PYTHONPATH as described above under Interface options. The search path can be manipulated from within a Python program as the variable sys.path.

This is also explained in sys.path:

A list of strings that specifies the search path for modules. Initialized from the environment variable PYTHONPATH, plus an installation-dependent default.

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

See also Module site This describes how to use .pth files to extend sys.path.

Unlike PYTHONPATH, this site mechanism is sometimes used by third-party and semi-official installs. For example, Apple uses it to add its Extras library of pre-installed packages like pyobjc to the builtin Python 2.7 on macOS.


If you're wondering how that "installation-dependent default" is loaded by the sys module in CPython, it ultimately comes down to a public C API function, Py_GetPath:

Return the default module search path; this is computed from the program name (set by Py_SetProgramName() above) and some environment variables. The returned string consists of a series of directory names separated by a platform dependent delimiter character. The delimiter character is ':' on Unix and Mac OS X, ';' on Windows. The returned string points into static storage; the caller should not modify its value. The list sys.path is initialized with this value on interpreter startup; it can be (and usually is) modified later to change the search path for loading modules.

If you want to see how the C code works, you probably want to start at _PyPathConfig_Init, because the actual Py_GetPath just calls a function that makes sure this has been called and then pulls the value out of the struct that it sets.

Upvotes: 2

Related Questions