Issue
I want to restart a script from within itself. However on Linux os.execv
ignores sys.executable
and falls back to the default python version, 2.7.
Here is a minimal running example :
import os
import sys
print(sys.executable, sys.version)
os.execv(sys.executable, ["python"] + sys.argv)
Here is the output for python3 main.py
(python3 referring to the default python 3 exe):
> /usr/local/bin/python3.8 3.8.0 (default, Jun 1 2022, 16:03:28) [GCC 8.3.0]
> /usr/bin/python 3.8.0 (default, Jun 1 2022, 16:03:28) [GCC 8.3.0]
> ('/usr/bin/python', '2.7.16 (default, Oct 10 2019, 22:02:15) \n[GCC 8.3.0]')
> ('/usr/bin/python', '2.7.16 (default, Oct 10 2019, 22:02:15) \n[GCC 8.3.0]')
> ('/usr/bin/python', '2.7.16 (default, Oct 10 2019, 22:02:15) \n[GCC 8.3.0]')
...
I don't quite get what part needs to be changed or what goes wrong/am I doing wrong.
Solution
Explicit specification of the Python version in execv()
does not result in a fallback to the Python 2 version like the specification only of python
does. See the code ( which is not executing an endless loop):
import os, sys, time
strF = None
try:
f = open("counter.txt", "r")
strF = f.read()
f.close()
except:
print('except')
f = open("counter.txt", "w")
f.write("0")
f.close()
strF = "0"
if strF == '3':
print('> strF == 3')
sys.exit()
print('>> strF == 3')
else:
f = open("counter.txt", "w")
f.write(str(1+int(strF)))
f.close()
print(sys.executable, sys.version, strF)
time.sleep(3)
os.execv(sys.executable, ["python3.9"] + sys.argv)
Which gives following output:
$ python3.9 main.py
except
/usr/local/bin/python3.9 3.9.13 (main, May 20 2022, 21:21:14)
[GCC 5.4.1 20160904] 0
/usr/local/bin/python3.9 3.9.13 (main, May 20 2022, 21:21:14)
[GCC 5.4.1 20160904] 1
/usr/local/bin/python3.9 3.9.13 (main, May 20 2022, 21:21:14)
[GCC 5.4.1 20160904] 2
> strF == 3
where the output in case of not specifying the Python version is:
$ python3.9 main.py
except
/usr/local/bin/python3.9 3.9.13 (main, May 20 2022, 21:21:14)
[GCC 5.4.1 20160904] 0
/usr/bin/python 3.9.13 (main, May 20 2022, 21:21:14)
[GCC 5.4.1 20160904] 1
('/usr/bin/python', '2.7.12 (default, Nov 19 2016, 06:48:10) \n[GCC 5.4.0 20160609]', '2')
> strF == 3
UPDATE (1): The only right usage of execv()
for restarting a script from within itself should be:
os.execv(sys.executable, [sys.executable] + sys.argv)
With the above code there is no need for explicit specification of the Python version, so it should work with any Python version as the version must not be hard-coded.
The Python documentation ( https://docs.python.org/3/library/os.html?highlight=execv#os.execv ) appears to me not sufficiently explaining what os.execv()
actually does, as giving the same value twice appears a bit weird. Maybe someone else can comment on this here? What does path
in os.execv(path, args)
actually mean?
The Python documentation states only that:
The “v” variants [of exec()] are good when the number of parameters is variable, with the arguments being passed in a list or tuple as the args parameter. In either case, the arguments to the child process should start with the name of the command being run, but this is not enforced.
UPDATE (2): as pointed out in the comments the way how it comes that python2 is called by python3 not already at the first, but at the second restart seem to be as follows:
Though python3 is using the argv[0] 'python' value as the sys.executable in the restarted Python script run, it actually executes the in 'path' ( is it called ""path"" to increase confusion??? ) argument to execv() passed python3. Now in the restarted version of the main.py the sys.executable value is a wrong one not reflecting the Python version which runs the script what results in running python2 ( if python2 is the default python version on the system) as executable only in the second restart.
Answered By - Claudio
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.