0

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'])
Sample run:
D:\Project> dir /ad /b
code

D:\Project> dir *.py /b
test.py

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? I want to change the system environment variable only for the execution of the current script

wovano
  • 4,543
  • 5
  • 22
  • 49
Tonechas
  • 13,398
  • 16
  • 46
  • 80
  • Are you wanting to change the value in `os.environ` or the system environment variable? If it's the latter, should it be a permanent change or temporary (i.e. only for the execution of the current script)? – martineau Sep 26 '21 at 23:35
  • 1
    I want to change the system environment variable only for the execution of the current script – Tonechas Sep 26 '21 at 23:38

3 Answers3

3

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])
martineau
  • 119,623
  • 25
  • 170
  • 301
1

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"}
)
Tonechas
  • 13,398
  • 16
  • 46
  • 80
Peter Badida
  • 11,310
  • 10
  • 44
  • 90
  • 1
    A.) This is not an answer and B.) the OP is using Windows. – martineau Sep 26 '21 at 23:06
  • Updated for Windows. The rest doesn't really change. Manipulating it programatically was fine with sys or os, though you are correct when it's about preserving the value in the parent process - explained further. – Peter Badida Sep 26 '21 at 23:19
  • @Tonechas check the update on the answer and especially the linked part as Unix StackExchange. Same applies for Windows. – Peter Badida Sep 26 '21 at 23:26
  • 1
    Thank you for your help. I found the command `python -c "print('set PYTHONPATH=%PYTHONPATH%;world')" > out.bat` to be particularly insighful for figuring out the issue. – Tonechas Sep 27 '21 at 16:47
0

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

xonxt
  • 363
  • 1
  • 2
  • 13