1

The following code allows me to dynamically identify and load the custom module if it is not located in any of the directory of sys.path variable

import sys
sys.path.append("/lib")

But, this gives me OSError

import subprocess
x = subprocess.Popen(["export", "PYTHONPATH=/lib"], stdout=subprocess.PIPE)

Not just this, even simple Linux/Unix variable declaration setting fails in subprocess.Popen()

import subprocess
x = subprocess.Popen("x=y", stdout=subprocess.PIPE)

I wanted to check subprocess as I tried setting PYTHONPATH via os.system(), os.popen() etc., and the variable did not set (may be it is set in the child process shell)

Ibrahim Quraish
  • 3,889
  • 2
  • 31
  • 39
  • `export` is a built-in shell command, not a program. Anyway, setting it in a child process will not affect the current python process. You need `os.environ` https://docs.python.org/3/library/os.html?highlight=environ#os.environ. – cdarke Dec 17 '16 at 13:44
  • os.environ["PYTHONPATH"] = "/dir" and subprocess.call(["export PYTHONPATH=/dir"], shell=True) both code helps me to set the environment variable PYTHONPATH, but even after setting it I could not load the module present under that directory and I dont see injection of this directory entry into the sys.path variable – Ibrahim Quraish Dec 17 '16 at 17:43
  • 1
    `subprocess.call(["export PYTHONPATH=/dir"], shell=True) ` will only affect that one child process -- environment variables are not global, they are not shared, they are *copied* from parent to child. Setting `os.environ["PYTHONPATH"] = "/dir"` will not set the current process's `sys.path` because PYTHONPATH is read at process start-up, not later. – cdarke Dec 17 '16 at 18:37

2 Answers2

2

Try this:

>>> subprocess.call(["export foo=bar && echo foo=$foo"], shell=True)
foo=bar
0
>>> 
Sharad
  • 9,282
  • 3
  • 19
  • 36
1

There are several things that are going on here and are probably confusing you a little. One thing is, that whatever instructions given to Popen will be executed in the child process and will not affect your main process. You can merely Pipe or retrieve results from it.

First to comment on your second use case, where you use string as an argument. From the docs you can read:

class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=())

...

args should be a sequence of program arguments or else a single string. By default, the program to execute is the first item in args if args is a sequence. If args is a string, the interpretation is platform-dependent and described below. See the shell and executable arguments for additional differences from the default behavior. Unless otherwise stated, it is recommended to pass args as a sequence.

On POSIX, if args is a string, the string is interpreted as the name or path of the program to execute. However, this can only be done if not passing arguments to the program.

So in your second case, you are trying to execute a file or program x=y which doesn't go.

Even if you use list, like in your first use case, you must be aware, that this isn't equivalent to passing code to the bash shell. If you want this, you can use shell=True as an keyword argument, but this has other issues as indicated by the docs. But your code will execute with shell=True.

If your sole purpose is to set environmental variable, then you should consider the option to use os.environ variable that maps your environmental variables to values (as indicated by @cdarke first).

LynxLike
  • 391
  • 5
  • 10