Python
PYTHONPATH
environment variables
programming
scripting

In Python script, how do I set PYTHONPATH?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When Python cannot find one of your modules, the first impulse is often to set PYTHONPATH. That can work, but it is important to understand whether you need a shell environment change, a process-local sys.path change, or a packaging fix instead.

PYTHONPATH Versus sys.path

PYTHONPATH is an environment variable read when the interpreter starts. Python uses it to build sys.path, which is the list of directories searched during imports. That means changing os.environ["PYTHONPATH"] inside a running script does not retroactively rebuild the active import path.

If you need the current process to import from an extra directory, modify sys.path directly:

python
1from pathlib import Path
2import sys
3
4project_root = Path(__file__).resolve().parent.parent
5sys.path.insert(0, str(project_root / "shared"))
6
7import helpers
8
9print(helpers.__file__)

This works immediately because import uses the current value of sys.path.

If you need child processes launched later to inherit a custom PYTHONPATH, then setting the environment variable can make sense:

python
1import os
2import subprocess
3from pathlib import Path
4
5extra_dir = Path(__file__).resolve().parent / "plugins"
6os.environ["PYTHONPATH"] = str(extra_dir)
7
8subprocess.run(["python", "-c", "import sys; print(sys.path)"])

In that example, the child process sees the updated variable. The current process still uses the already-initialized sys.path unless you edit it directly.

Temporary Shell Setup

If the goal is to run a script from the command line with one additional import directory, set PYTHONPATH in the shell before starting Python.

On macOS or Linux:

bash
export PYTHONPATH="/opt/myapp/lib"
python run_report.py

On Windows PowerShell:

powershell
$env:PYTHONPATH = 'C:\projects\shared'
python .\run_report.py

You can also prepend the new directory while keeping any existing value:

bash
export PYTHONPATH="/opt/myapp/lib:${PYTHONPATH}"
python run_report.py

This is useful for one-off runs, local experiments, or CI jobs where the environment is created fresh for each execution.

Better Long-Term Options

Many import problems should not be solved with PYTHONPATH at all. In production code, the more stable choices are usually these:

  1. Install your package into a virtual environment with pip install -e . during development.
  2. Run modules from the project root with python -m package.module.
  3. Use a .pth file only when you control the interpreter environment and need a fixed extension to the import path.

A minimal package layout avoids most path hacks:

text
1myapp/
2  pyproject.toml
3  src/
4    myapp/
5      __init__.py
6      cli.py

Then you can install and run it cleanly:

bash
1python -m venv .venv
2source .venv/bin/activate
3pip install -e .
4python -m myapp.cli

That approach is easier to reproduce across developers, CI, and deployment systems because imports no longer depend on an external shell setting.

When an In-Script Change Is Reasonable

Editing sys.path in code is acceptable when the script is explicitly a bootstrapper. For example, a repository might have a tools/ folder with helper scripts that need to import application code before the package is installed.

In that case, keep the change narrow and predictable:

python
1from pathlib import Path
2import sys
3
4ROOT = Path(__file__).resolve().parents[1]
5SRC = ROOT / "src"
6
7if str(SRC) not in sys.path:
8    sys.path.insert(0, str(SRC))
9
10from myapp.cli import main
11
12main()

Use absolute paths derived from __file__ rather than relative strings such as "../src". Relative strings depend on the current working directory and fail easily when the script is launched from a different location.

Common Pitfalls

The most common mistake is setting os.environ["PYTHONPATH"] and expecting the current interpreter to re-scan imports. It will not. If the process is already running, update sys.path.

Another problem is appending paths instead of prepending them. If an older package with the same module name appears earlier in sys.path, Python imports that one first. Use sys.path.insert(0, path) when you need your directory to win.

A third issue is using PYTHONPATH as a permanent project dependency. That makes local machines, editors, test runners, and deployment environments drift apart. If imports only work after custom shell setup, the project is usually under-packaged.

Finally, be careful with virtual environments. A venv already manages import locations. Adding broad directories through PYTHONPATH can hide packaging mistakes and accidentally import code from outside the environment.

Summary

  • 'PYTHONPATH is read when Python starts and contributes to sys.path'
  • Changing os.environ["PYTHONPATH"] inside a running script does not update current imports
  • Use sys.path.insert(0, path) for process-local import fixes
  • Prefer packaging, virtual environments, and python -m for long-term maintainability
  • Reserve PYTHONPATH for shell-level configuration and child-process inheritance

Course illustration
Course illustration

All Rights Reserved.