Python site: Understand Package Paths

Published on: August 14, 2026
Reading time: 6 minutes
Directory diagram representing site-packages paths and Python site module configuration

The Python site module participates in interpreter startup and configures installation-specific import paths. It adds site-packages directories to sys.path, processes .pth files, attempts to import sitecustomize and usercustomize, and helps configure history and completion in interactive sessions.

These actions explain why installed distributions become importable and why two executions of the same Python version may have different paths. They also create a sensitive startup surface: executable lines in .pth files run on every interpreter launch, while customization modules can execute arbitrary code before the application starts.

Automatic import during startup

Python normally imports site automatically. The -S option disables that step.

python -S -c "import sys; print(sys.path)"

With -S, site-specific directories and helper builtins are not added. Since Python 3.14, virtual-environment values for sys.prefix and sys.exec_prefix are configured during path initialization and no longer depend on the site module.

Call site.main() explicitly

If Python started with -S, importing site does not automatically apply the normal modifications. Call site.main() to request them.

import site
site.main()

Libraries should not do this. Changing sys.path at runtime is global and may surprise unrelated components. The application’s entry point should own that decision.

How site directories are built

The module combines heads such as sys.prefix and sys.exec_prefix with platform-specific tails. On Unix, a typical directory is lib/pythonX.Y/site-packages; on Windows, it is usually Lib/site-packages.

Free-threaded builds may include a t suffix, such as python3.13t. Do not build these paths manually. Use site functions or Python sysconfig.

Read global site-packages paths

getsitepackages() returns recognized global site directories.

import site

for path in site.getsitepackages():
    print(path)

Embedded or unusual installations may behave differently. Portable tools should handle empty or unavailable results and respect the active virtual environment.

Read the user site path

getusersitepackages() returns the user-specific package directory.

import site

print(site.getusersitepackages())
print(site.ENABLE_USER_SITE)

A computed path does not prove that it was added to sys.path. Inspect ENABLE_USER_SITE.

Interpret ENABLE_USER_SITE

The flag has three meaningful states:

  • True: enabled and added to the search path.
  • False: disabled by the user through -s or PYTHONNOUSERSITE.
  • None: disabled for security reasons or by an administrator.

Do not collapse the value with bool() when you need to distinguish user preference from security policy.

Disable user packages

The -s option disables the user site:

python -s -c "import site; print(site.ENABLE_USER_SITE)"

PYTHONNOUSERSITE provides similar behavior. Services, scheduled jobs, and reproducible environments often benefit from excluding personal packages.

USER_BASE and PYTHONUSERBASE

getuserbase() returns the base used by the user installation scheme. PYTHONUSERBASE can override the default.

import site

print(site.getuserbase())
print(site.USER_BASE)

Changing this variable affects where installers place user scripts, modules, and data. Set it before Python starts and document it in build pipelines.

Use python -m site

The command-line interface prints sys.path, the user base, user site, and enablement state.

python -m site
python -m site --user-base
python -m site --user-site

When user-directory options are supplied, the exit code indicates whether the user site is enabled, disabled by the user, or blocked for security or administrative reasons.

Path configuration files

Files ending in .pth inside site directories are processed in alphabetical order. Ordinary lines add existing paths to sys.path. Blank lines and comments are ignored.

# example.pth
/opt/my_app/libs
/opt/my_app/plugins

Nonexistent paths are skipped and duplicates are avoided. The module does not require an entry to be a directory; an existing file can also be added.

Alphabetical order affects imports

File names determine processing order, which can affect module precedence. If the same import name exists in two locations, the final sys.path order determines which one wins.

Avoid undocumented naming tricks such as 00-first.pth. Prefer clean virtual environments and ordinary package installation.

Executable lines in .pth files

A line beginning with import or import is executed on every interpreter startup.

import my_startup_hook

This happens even when the application never uses the related package. The one-line restriction is deliberate and discourages complex startup logic.

Security risk of .pth execution

Anyone able to write into a site-packages directory can potentially gain persistent code execution in every Python process using that environment. Protect permissions and treat .pth files as executable configuration.

from pathlib import Path
import site

for directory in site.getsitepackages():
    for file in Path(directory).glob('*.pth'):
        print(file)
        for line in file.read_text(errors='replace').splitlines():
            if line.startswith(('import ', 'import\t')):
                print('  executes:', line)

.pth file encoding

Since Python 3.13, site first decodes .pth files as UTF-8 and falls back to the locale encoding. Use UTF-8 for predictability and avoid unnecessary non-ASCII characters in infrastructure paths.

Add a site directory programmatically

addsitedir() adds a directory and processes its .pth files.

import site

site.addsitedir('/opt/my_app/site-packages')

This changes global import state and may execute startup lines. Never pass an untrusted path. Plugin systems should prefer controlled installation and process restarts.

sitecustomize

After path processing, Python tries to import sitecustomize. Administrators can use it for small global policies, audit hooks, encoding choices, or corporate startup configuration.

A missing module is silently ignored, but other exceptions can produce confusing startup failures. Keep the module small, tested, and independent of fragile external services.

usercustomize

When the user site is enabled, Python attempts to import usercustomize from the user site-packages directory.

It can customize trusted interactive sessions, but applications should not depend on it. Production services often disable user site to prevent personal preferences from altering behavior.

Avoid printing during startup

Output from customization modules may corrupt protocols, JSON-producing tools, and command-line programs. With pythonw.exe, output may be silently discarded.

Log only when explicitly enabled and send messages to an appropriate protected destination.

Automatic readline configuration

In interactive mode without -S, site configures rlcompleter and history when readline is available. The history file is commonly ~/.python_history.

For completion behavior and dynamic-attribute side effects, see Python rlcompleter.

Disable the interactive hook

sys.__interactivehook__ controls this setup. A customization module can remove it.

import sys

if hasattr(sys, '__interactivehook__'):
    del sys.__interactivehook__

Do this only when you own the interactive experience. A library should not modify the hook globally.

Virtual environments and pyvenv.cfg

pyvenv.cfg may contain include-system-site-packages = true. When false, the environment excludes global packages.

For reproducible projects, keep it false and install every dependency into the venv. Global packages can hide undeclared requirements.

Inspect virtual-environment prefixes

import sys

print('prefix:', sys.prefix)
print('base_prefix:', sys.base_prefix)
print('venv:', sys.prefix != sys.base_prefix)

In Python 3.14, these values remain correct even with -S.

site or sysconfig?

Use site to inspect active directories, user-site status, and startup customization. Use sysconfig for structured installation and build schemes.

Do not infer cross-platform rules from one observed path on one machine.

Diagnose an unexpected import

import module
import sys

print(module.__file__)
print('\n'.join(sys.path))

Then inspect .pth files, PYTHONPATH, user site, virtual-environment settings, and customization modules. Python pkgutil can list available modules.

PYTHONPATH interaction

PYTHONPATH influences startup search paths before several site operations. A global value can affect every Python environment.

Avoid setting it permanently system-wide. Prefer a controlled editable installation or virtual-environment configuration.

Isolated mode with -I

The -I option ignores PYTHON* environment variables and disables user site, among other protections.

python -I -c "import sys; print(sys.path)"

It is useful for administrative tools that should be less influenced by a user’s environment, although installation-level customizations still need review.

Test sitecustomize safely

Use a temporary virtual environment, place the module in its site-packages directory, and launch a subprocess.

import subprocess

result = subprocess.run(
    ['.venv/bin/python', '-c', 'print("ok")'],
    text=True,
    capture_output=True,
    check=True,
)
assert result.stdout.strip() == 'ok'

Test normal startup, -S, -s, errors, and missing output streams. Never experiment in global Python.

Audit startup differences

python -m site
python -s -m site
python -S -c "import sys; print(sys.path)"
python -I -m site

The differences reveal the effects of user site, the site module, and isolated mode.

Common mistakes

  • Adding user-controlled paths with addsitedir().
  • Putting complex logic in a .pth import line.
  • Using sitecustomize as a plugin system.
  • Printing to stdout during startup.
  • Depending on global packages inside a venv.
  • Confusing an existing user-site directory with an enabled one.
  • Building site-packages paths manually.

Best practices

  • Use clean reproducible virtual environments.
  • Protect site-packages permissions.
  • Audit executable .pth lines.
  • Keep customization modules minimal.
  • Disable user site in services.
  • Use sysconfig for structured paths.
  • Test startup in subprocesses.

Conclusion

The Python site module explains much of automatic import configuration: site-packages directories, .pth files, user packages, and customization hooks.

This convenience runs before the application and demands strict control. Protect directories, avoid complex startup logic, and use virtual environments. Consult the official site documentation and the sys.path initialization documentation.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Installer icon representing offline pip bootstrap with Python ensurepip
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python ensurepip: Restore pip Offline

    Learn Python ensurepip to install or restore pip offline, choose the environment, script names, upgrade behavior, and avoid system conflicts.

    Ler mais

    Tempo de leitura: 5 minutos
    14/08/2026
    Software package representing package metadata inspected with Python importlib.metadata
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python importlib.metadata: Package Data

    Learn Python importlib.metadata to inspect installed versions, dependencies, files, metadata, entry points, and import-to-distribution mappings.

    Ler mais

    Tempo de leitura: 5 minutos
    14/08/2026
    Executing code representing modules and paths run with Python runpy
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python runpy: Execute Modules and Paths

    Learn Python runpy to execute modules, scripts, directories, and ZIP files, control namespaces, and avoid security and thread-safety problems.

    Ler mais

    Tempo de leitura: 5 minutos
    13/08/2026
    Software package representing module discovery with Python pkgutil
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python pkgutil: Discover Packages

    Learn Python pkgutil to discover modules, walk packages, resolve objects, extend package paths, and access resources safely.

    Ler mais

    Tempo de leitura: 5 minutos
    13/08/2026
    Binary code network representing the import graph analyzed with Python modulefinder
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python modulefinder: Analyze Imports

    Learn Python modulefinder to map imports, detect missing modules, customize search paths, and audit dependencies with clear limitations.

    Ler mais

    Tempo de leitura: 5 minutos
    13/08/2026
    Organized binders representing applications packaged as executable .pyz files with Python zipapp
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python zipapp: Build Executable .pyz Files

    Learn Python zipapp to package applications as executable .pyz files, define entry points, bundle dependencies, and distribute safely.

    Ler mais

    Tempo de leitura: 5 minutos
    13/08/2026