Как да получите пълни опции на командния ред на интерпретатора на python argv?

Както знаем от документацията:

-c Ако тази опция е дадена, първият елемент на sys.argv ще бъде "-c" и текущата директория ще бъде добавена към началото на sys.path (позволявайки модулите в тази директория да бъдат импортирани като модули от най-високо ниво).

Как мога да получа пълни опции на командния ред на интерпретатора? Трябва ми, за да реша това:

https://github.com/mitsuhiko/werkzeug/blob/f50bdc04cf1c8d71d12d13a0c8ef2878477f4d24/werkzeug/_reloader.py#L141

Ако стартирам сървър за разработка на werkzeug, той ще загуби опцията -c cmd при разклонението. Искам да закърпя werkzeug, но не мога да намеря как да получа реални опции.

Ако искате да знаете защо имам нужда от това - искам предварително да изпълня някакъв код преди manage.py, който иска да анализира sys.argv. И също така мисля, че методът werkzeug е неправилен, защото не работи в случай на ъгъл.


person Mihail Krivushin    schedule 09.02.2015    source източник


Отговори (1)


Ако стартирам сървър за разработка на werkzeug, той ще загуби опцията -c cmd при разклонението.

Първо, процесът не е просто раздвоен. Извиква се нов интерпретатор на Python.

Какво имаш предвид с it will lost -c cmd? Фактът, че низът cmd го няма в argv? Това е:

$ python -c "import sys; print(sys.argv)"
['-c']

Наистина низът cmd не е достъпен от sys.argv. Това е свързана документация:

Ако командата е била изпълнена с помощта на опцията на командния ред -c към интерпретатора, argv[0] е зададен на низа '-c'

Документите не коментират действителния команден низ. Въпреки че този команден низ е ясно "изпратен" като аргумент към изпълнимия файл на интерпретатора на Python, реализацията на CPython изглежда не излага тази информация в рамките на sys.argv. Предполагам, че няма начин да се реконструира тази информация, без да се промени изходният код на sysmodule.c. Така че, ако мислите, че зависи от извличането на cmd -- не трябва! Трябва да намерите друг начин да инжектирате тази информация.

Редактиране:

Действителният команден низ се консумира в Modules/main.c във функция Py_Main():

wcscpy(command, _PyOS_optarg);

Това command е това, което се изпълнява по-късно в main.c.

Аргументите на командния ред се обработват чрез PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);, което на свой ред извиква makeargvobject() в sysmodule.c. Последната функция преобразува данните от двоичния аргумент в Python unicode обекти (поне в Python 3 го прави) в for (i = 0; i < argc; i++) {}-подобен цикъл. И така, argc трябва (умишлено) да бъде изключено с -1, за да игнорира командата в споменатия цикъл.

Това означава, че магията на премахването на аргумента на командата е в настройката _PyOS_optind, така че последващото извикване на PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind); предполага брой аргументи, по-малък (с 1), отколкото е в действителност.

Не проследих наистина, но предполагам, че намаляването в тези редове е отговорно:

if (command != NULL) {
    /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
    _PyOS_optind--;
    argv[_PyOS_optind] = L"-c";
}

Редактиране 2:

Потвърдихте решаващата роля на _PyOS_optind тук със следната корекция към текущия съвет на Python 3:

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) {

Тест:

 $ ./python -c "import sys; print(sys.argv)"
['./python', '-c', 'import sys; print(sys.argv)']
person Dr. Jan-Philip Gehrcke    schedule 09.02.2015
comment
Благодаря ти! Не намерих къде cmd наистина е раиран. И в този файл намерих Py_GetArgcArgv! И тогава опитах някакъв странен персонал като този със странен резултат: >>> python -c 'import ctypes; argv = ctypes.POINTER(ctypes.c_char_p)(); argc = ctypes.c_int(); ctypes.pythonapi.Py_GetArgcArgv(ctypes.byref(argc), ctypes.byref(argv)); print([argv[i] for i in xrange(0, argc.value)])' ['python', '-c', '-c'] - person Mihail Krivushin; 10.02.2015