How to get python interpreter full argv command line options?

早过忘川 提交于 2020-02-25 08:12:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!