Home > Enterprise >  Add folder to PYTHONPATH programmatically
Add folder to PYTHONPATH programmatically

Time:09-27

The environment variable PYTHONPATH is set to C:\Users\Me. I'd like to add to PYTHONPATH a folder named code which is located in the same directory as my script (D:\Project). This is what I tried:

test.py

import os
from pathlib import Path

print('BEFORE:', os.environ['PYTHONPATH'])

folder = Path(__file__).resolve().parent.joinpath('code')
print('FOLDER:', folder)

os.system(f'set PYTHONPATH={folder};%PYTHONPATH%')
print('AFTER:', os.environ['PYTHONPATH'])

Output:

D:\Project> python test.py
BEFORE: C:\Users\Me
FOLDER: D:\Project\code
AFTER: C:\Users\Me   <<< should be D:\Project\code;C:\Users\Me

I also tried this:

import subprocess
subprocess.run(["set", f"PYTHONPATH={folder};%PYTHONPATH%"])

And this is what I got:

FileNotFoundError: [WinError 2] The system cannot find the file specified

How can I add a folder to PYTHONPATH programmatically?

CodePudding user response:

I believe sys.path.append(...) should work. Don't forget to import sys.

CodePudding user response:

sys.path as well as os.environ do set the thing you want. You are just missing two things:

  • an environment variable is set per process, thus not accessible from outside of the process except after the process ends
  • os.system executes in a new subshell, thus the env var isn't affected for your process. It's affected in the subshell which then exits.
C:\> set PYTHONPATH=hello; python
>>> from os import environ
>>> environ["PYTHONPATH"]
'hello'
>>> environ["PYTHONPATH"] = environ["PYTHONPATH"]   ":world"
>>> environ["PYTHONPATH"]
'hello:world'
>>> 
C:\> echo %PYTHONPATH%
# empty or "%PYTHONPATH%" string

For preserving the value you need to utilize the shell which is the thing that manipulates the environment. For example with export (or set on Windows):

set PYTHONPATH=hello
echo %PYTHONPATH%
# hello
python -c "print('set PYTHONPATH=%PYTHONPATH%;world')" > out.bat
out.bat
echo %PYTHONPATH%
# hello;world

Alternatively, utilize subprocess.Popen(["command"], env={"PYTHONPATH": environ["PYTHONPATH"] <separator> new path}) which will basically open a new process - i.e. you can create a Python launcher for some other program and prepare the environment for it this way. The environment in it will be affected, yet the environment outside still won't as for that you still need to have access to the shell from the shell's process context, not from the child (python process).

More on that here and here.

Example:

# launcher.py
from subprocess import Popen

Popen(["python", "-c", "import os;print(os.environ.get('PYTHONPATH'))"])

Popen(
    ["python", "-c", "import os;print(os.environ.get('PYTHONPATH'))"],
    env={"PYTHONPATH": "hello"}
)

CodePudding user response:

If you only want to change it for the execution of the current script, you can do it simply by assigning (or changing an existing) value in the os.environ mapping. The code below is complicated a bit by the fact that I made it work even if os.environ[PYTHONPATH] isn't initially set to anything (as is the case on my own system).

import os
from pathlib import Path

PYTHONPATH = 'PYTHONPATH'

try:
    pythonpath = os.environ[PYTHONPATH]
except KeyError:
    pythonpath = ''

print('BEFORE:', pythonpath)

folder = Path(__file__).resolve().parent.joinpath('code')
print(f'{folder=}')

pathlist = [str(folder)]
if pythonpath:
    pathlist.extend(pythonpath.split(os.pathsep))
print(f'{pathlist=}')

os.environ[PYTHONPATH] = os.pathsep.join(pathlist)
print('AFTER:', os.environ[PYTHONPATH])

CodePudding user response:

You can set environment variables using os.environ as noted in this past question.

For your code:

os.environ['PYTHONPATH'] == f'{folder};%PYTHONPATH%'
  • Related