how to re-invoke python script within itself
I am trying to find the best way of re-invoking a Python script within itself. Currently it is working like http://github.com/benoitc/gunicorn/blob/master/gunicorn/arbiter.py#L285. The START_CTX
is created at http://github.com/benoitc/gunicorn/blob/master/gunicorn/arbiter.py#L82-86.
The code is relying on sys.argv[0]
as the "caller". However, this fails in cases where it is invoked with:
python script.py ...
This case does work:
python ./script.py ...
because the code uses os.chdir
before running os.execlp
.
I did notice os.environ["_"]
, but I am not sure how reliable that would be. Another possible case is to check if sys.argv[0]
is not on PATH
and is not executable and use sys.executable
when calling os.execlp
开发者_JS百科.
Any thoughts on a better approach solving this issue?
I think the real issue here is that the gunicorn/arbiter.py code wants to execute the Python script with the exact same environment every time. This is important because the Python script being invoked is an unknown and it is important for it be called exactly the same way every time.
My feeling is that the problem you are experiencing has to do with the environment having changed between invokations of the Python script by the arbiter.
In http://github.com/benoitc/gunicorn/blob/master/gunicorn/arbiter.py#L85-89, we see that the python executable and the args are being stored by the arbiter into self.START_CTX.
Then in http://github.com/benoitc/gunicorn/blob/master/gunicorn/arbiter.py#L303-305, we see that the execvpe is called with the sys.executable, the modified args and then os.environ.
If os.environ had changed somewhere else (i.e. the PWD variable), then your executable will fail to be called properly (because you're no longer in the correct folder). The arbiter seems to take care of that possibility by storing the cwd in START_CTX. So the question remains, why is the invokation failing for you?
I tried some test code out which I wrote as follows:
#!/usr/bin/env python
import sys
import os
def main():
"""Execute twice"""
cwd = os.getcwd()
print cwd
print sys.argv
if os.path.exists("/tmp/started.txt"):
os.unlink("/tmp/started.txt")
print "Deleted /tmp/started.txt"
print
return
args = [sys.executable] + sys.argv[:]
os.system("touch /tmp/started.txt")
print "Created /tmp/started.txt"
print
os.execvpe(sys.executable, args, os.environ)
if __name__ == '__main__':
main()
When I execute this code from the command line, it works just fine:
guest@desktop:~/Python/Test$ python selfreferential.py
/Users/guest/Python/Test
['selfreferential.py']
Created /tmp/started.txt
/Users/guest/Python/Test
['selfreferential.py']
Deleted /tmp/started.txt
guest@desktop:~/Python/Test$ python ./selfreferential.py
/Users/guest/Python/Test
['./selfreferential.py']
Created /tmp/started.txt
/Users/guest/Python/Test
['./selfreferential.py']
Deleted /tmp/started.txt
guest@desktop:~/Python/Test$ cd
guest@desktop:~$ python Python/Test/selfreferential.py
/Users/guest
['Python/Test/selfreferential.py']
Created /tmp/started.txt
/Users/guest
['Python/Test/selfreferential.py']
Deleted /tmp/started.txt
guest@desktop:~$ python /Users/guest/Python/Test/selfreferential.py
/Users/guest
['/Users/guest/Python/Test/selfreferential.py']
Created /tmp/started.txt
/Users/guest
['/Users/guest/Python/Test/selfreferential.py']
Deleted /tmp/started.txt
guest@desktop:~$
As you can see, there was no problem doing what gunicorn was doing. So, maybe your problem has something to do with the environment variable. Or maybe is has something to do with the way your operating system executes things.
I would suggest a different approach. Wrapp all of the script functionality into a single function, which gets called when the script is executed, which can recursively call itself, instead of executing a new process.
精彩评论