0

I'm on Windows. I am trying to write a Python 2.x script (let's call it setup.py) which would enable the following scenario:

  1. User runs cmd to open a console window
  2. In that console window, user runs setup.py
  3. User finds themselves in the same console window, but now the cmd running there has had its environment (env. variables) modified by setup.py

setup.py modifies the environment by adding a new environment variable FOO with value foo, and by preneding something to PATH.

On Linux, I would simply use os.exec*e to replace the Python process with a shell with the environment configured.

I tried the same approach on Windows (like os.exec*e(os.environ['ComSpec'])), but it doesn't work, the environment of the newly executed cmd is messed up like this:

  • Running just set doesn't list FOO and doesn't show the effect on PATH. Running set FOO, however, shows FOO=foo, and echo %FOO% echoes foo.

  • Running set PATH or echo %PATH% shows the modified PATH variable. Running set path or echo %path% shows the value without the modification (even though env. vars are normally case insensitive on Windows).

  • If I type exit, the conole remains hanging in some state not accepting input, until I hit Ctrl+C. After that, it apparently returns to the cmd which originally called setup.py.

So clearly, os.exec*e doesn't work for this scenario on Windows. Is there a different way to achieve what I want? Is there a combination of subprocess.Popen() flags which would enable me to exit the calling Python process and leave the called cmd runnig, ideally in the same console? Or would accessing CreateProcess through ctypes help?

If necessary, I would settle for launching a new console window and closing the old one, but I certainly can't afford having the old console window hang in frozen state, waiting for a newly created one to close.

1
  • Would the downvoter explain themselves? Commented Dec 26, 2013 at 19:53

1 Answer 1

2

There's a much simpler solution if it's acceptable to use a Windows batch file in addition to your script, since the batch file runs in the calling process, and can therefore modify its environment.

Given a file setup.bat, which looks like this...

@echo off
for /f "tokens=*" %%a in ('python setup.py') do %%a

...and a file setup.py which looks like this...

import os
print 'set FOO=foo'
print 'set PATH=%s;%s' % ('C:\\my_path_dir', os.environ['PATH'])

...and assuming python.exe in in the PATH, then calling setup.bat from the command line will set the environment variables in the calling process, while still allowing you to make the setup.py script as complicated as you like, as long as it prints the commands you want to execute to stdout.

Update based on comments

If your setup.py has multiple modes of operation, you could make the setup.bat a generic wrapper for it. Suppose instead setup.bat looks like this...

@echo off
if "%1" == "setenv" (
    for /f "tokens=*" %%a in ('python setup.py %1') do %%a
) else (
    python setup.py %*
)

...and setup.py looks like this...

import sys
import os

if len(sys.argv) > 1 and sys.argv[1] == 'setenv':
    print 'set FOO=foo'
    print 'set PATH=%s;%s' % ('C:\\my_path_dir', os.environ['PATH'])
else:
    print "I'm gonna do something else with argv=%r" % sys.argv

...would that not suffice?

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer. I was actually considering falling back to something like this if I don't find a more direct way. The problem with this is that my real setup.py actually has several modes of operation (based on commandline arguments), only one of which is what I described in the question.
Updated answer. My batch file programming skills are pretty limited, so it might not be 100% correct, but it seems to work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.