问题
As we know from documentation:
-c If this option is given, the first element of sys.argv will be "-c" and the current directory will be added to the start of sys.path (allowing modules in that directory to be imported as top level modules).
How can I get full interpreter command line options? I need it to solve this:
https://github.com/mitsuhiko/werkzeug/blob/f50bdc04cf1c8d71d12d13a0c8ef2878477f4d24/werkzeug/_reloader.py#L141
If I start werkzeug development server, then it will lost -c cmd
option on fork. I want to patch werkzeug, but cant find how to get real options.
If you want to know why I need this - I want to preexecute some code before manage.py that want to parse sys.argv
. And also I think that werkzeug method is incorrect due it is not working in corner case.
回答1:
If I start werkzeug development server, then it will lost -c cmd option on fork.
First of all, the process is not simply forked. A fresh Python interpreter is invoked.
What do you mean with it will lost -c cmd
? The fact that the cmd
string is gone in argv? That is:
$ python -c "import sys; print(sys.argv)"
['-c']
Indeed, the cmd
string is not accessible from within sys.argv
. This is related documentation:
If the command was executed using the -c command line option to the interpreter, argv[0] is set to the string '-c'
The docs do not comment on the actual command string. While that command string was clearly "sent" as an argument to the Python interpreter exectuable, the CPython implementation does not seem to expose this information within sys.argv
. I guess there is no way to reconstruct this information without changing the source code of sysmodule.c
. So, if you think you depend on extracting cmd
-- you shouldn't! You need to find another way to inject this information.
Edit:
The actual command string is consumed in Modules/main.c in function Py_Main()
:
wcscpy(command, _PyOS_optarg);
This command
is what is being executed later on in main.c
.
The command line arguments are processed via PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
, which in turn calls makeargvobject()
in sysmodule.c
. The latter function translates the binary argument data into Python unicode objects (at least in Python 3 it does) in a for (i = 0; i < argc; i++) {}
-like loop. So, argc
must (purposely) be off by -1 in order to ignore the command in said loop.
That is, the magic of dropping the command argument is in setting _PyOS_optind
, so that the subsequent call to PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
suggests an argument count smaller (by 1) than it actually is.
I did not really follow through, but I guess the decrement in these lines is responsible:
if (command != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */
_PyOS_optind--;
argv[_PyOS_optind] = L"-c";
}
Edit2:
Verified the crucial role of _PyOS_optind
here with the following patch to the current Python 3 tip:
diff --git a/Modules/main.c b/Modules/main.c
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -679,9 +679,11 @@
}
if (command != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */
_PyOS_optind--;
- argv[_PyOS_optind] = L"-c";
+ _PyOS_optind = 0;
+ //argv[_PyOS_optind] = L"-c";
}
if (module != NULL) {
Test:
$ ./python -c "import sys; print(sys.argv)"
['./python', '-c', 'import sys; print(sys.argv)']
来源:https://stackoverflow.com/questions/28412903/how-to-get-python-interpreter-full-argv-command-line-options