- Python subprocess.Popen() не работает в контейнере Docker — отлично работает локально
- почему мое выполнение не работает? subprocess.run [duplicate]
- 23 ответа
- Вызов внешней команды в Python
- Почему?
- Захват output
- Передача списка команд
- Полная подпись
- Расширенная подпись
- Popen
- Обновление:
- Оригинальный ответ:
- С помощью стандартной библиотеки
- С внешним Зависимости
- macOS subprocess.Popen not work #4859
- Comments
- tuda2009 commented May 6, 2020 •
- tuda2009 commented May 6, 2020
- chen-zehua commented Jul 6, 2020
- EgeHe commented Jul 29, 2020
- BoboTiG commented Oct 18, 2020
- BoboTiG commented Oct 18, 2020
- BoboTiG commented Oct 18, 2020
- BoboTiG commented Dec 2, 2020
- glebarez commented Mar 30, 2021 •
- BoboTiG commented Mar 31, 2021
- glebarez commented Mar 31, 2021 •
- bwoodsend commented Mar 31, 2021
- glebarez commented Mar 31, 2021 •
- rokm commented Mar 31, 2021 •
- rokm commented Mar 31, 2021
- BoboTiG commented Apr 6, 2021
- glebarez commented Apr 6, 2021
Python subprocess.Popen() не работает в контейнере Docker — отлично работает локально
Я создал проект инфраструктуры Django REST, который я хочу развернуть на сервере. У меня нет доступа администратора к серверу, и поэтому я нашел единственный способ убедиться, что все зависимости проекта (такие как распределение Anaconda) будут доступны на сервере, это создать образ докера для моего проекта, а затем создать соответствующий контейнер на сервере, затем запустите его оттуда.
В моем проекте у меня есть скрипт на python (mymain.py), который вызывается с помощью subprocess.Popen(). Это прекрасно работает локально, и subprocess.Popen() делает все, что должен.
Однако, когда я пытаюсь сделать это из контейнера Docker, создается впечатление, что строка subprocess.Popen() была полностью пропущена [mymain.py не вызывается].
Для docker я создал файл docker-compose.yml, и в командной строке я набираю:
Я не вижу никакой ошибки, и все, кажется, работает нормально, однако subprocess.Popen(), кажется, не работает.
mymain.py первая строка:
В другом файле я вызываю subprocess.Popen(). Я попытался распечатать ошибку, но, к сожалению, stdout и stderr ничего не возвращают:
И вот что я получаю:
Как видите, первая строка моего main.py никогда не печаталась.
Тем не менее, когда я делаю это локально, набрав в командной строке:
все работает без проблем (выводится строка «Тестирование, если подпроцесс называется mymain.py . «.
Я даже пытался открыть оболочку контейнера Docker и набрать там ту же команду «python manage.py runserver 9000», но, к сожалению, это не сработало.
Теперь вопрос в том, как заставить подпроцесс работать удаленно (в контейнере Docker)?
Источник
почему мое выполнение не работает? subprocess.run [duplicate]
В отличие от других языков, имеющих переменную и значение, у Python есть имя и объект.
означает присвоение списку (объекту) имени a , и это:
просто дает тому же объекту a новое имя b , поэтому всякий раз, когда вы что-то делаете с a , объект изменяется, и поэтому b изменяется .
Единственный способ сделать действительно копию a для создания нового объекта, как и другие ответы, уже сказал.
Вы можете увидеть больше об этом здесь .
23 ответа
Вы можете использовать Popen, а затем вы можете проверить статус процедуры:
Здесь есть другая разница, которая не упоминается ранее.
subprocess.Popen выполняет команду & lt; command> как подпроцесс. В моем случае мне нужно выполнить файл & lt; a>, который должен связываться с другой программой, & lt; b>.
Я попробовал подпроцесс, и выполнение было успешным. Однако & lt; b> не удалось установить связь с & lt; a>. Все нормально, когда я запускаю оба из терминала.
Еще одно: (ПРИМЕЧАНИЕ: kwrite ведет себя отличным от других приложений. Если вы попробуете ниже с Firefox, результаты будут не такими.)
Если вы попытаетесь os.system(«kwrite») , поток программы зависает, пока пользователь не закроет kwrite. Чтобы преодолеть это, я попытался вместо этого os.system(konsole -e kwrite) . Эта программа продолжилась, но kwrite стал подпроцессом консоли.
Кто-нибудь запускает kwrite, не являющийся подпроцессом (то есть в системном мониторе он должен появляться на крайнем левом краю дерева).
Вызов внешней команды в Python
Простой, используйте subprocess.run , который возвращает объект CompletedProcess :
Почему?
Начиная с Python 3.5, в документации рекомендуется subprocess.run :
. Рекомендуемым подходом к вызову подпроцессов является использование функции run () для всех случаев использования, которые он может обрабатывать.
Ниже приведен пример простейшего возможного использования — и он выполняет точно так же, как и задано:
run ждет завершения команды, а затем возвращает объект CompletedProcess . Он может вместо этого поднимать TimeoutExpired (если вы дадите ему аргумент timeout= ) или CalledProcessError (если он терпит неудачу и вы пройдете check=True ).
Как вы могли бы сделать вывод из приведенного выше примера, stdout и stderr оба по умолчанию передаются по вашему собственному stdout и stderr.
Мы можем проверить возвращаемый объект и увидеть команду, которая была указана, и код возврата:
Захват output
Если вы хотите захватить вывод, вы можете передать subprocess.PIPE в соответствующие stderr или stdout :
(я нахожу это интересным и слегка что информация о версии попадает в stderr вместо stdout.)
Передача списка команд
Можно легко перейти от ручного предоставления командной строки (например, вопрос) к предоставлению строка построена программно. Не стройте строки программно. Это потенциальная проблема безопасности. Лучше предположить, что вы не доверяете входным данным.
Обратите внимание, что только args следует передавать по позициям.
Полная подпись
Вот фактическая сигнатура в источнике и как показано на рисунке help(run) :
popenargs и kwargs присваиваются конструктору Popen . input может быть строкой байтов (или unicode, если указать кодировку или universal_newlines=True ), которые будут переданы по каналу в stdin подпроцесса.
Документация описывает timeout= и check=True лучше, чем I can:
Аргумент timeout передается Popen.communicate (). Если истечет время ожидания, дочерний процесс будет убит и будет ждать. Исключение TimeoutExpired будет повторно поднято после завершения дочернего процесса.
Если проверка верна, и процесс завершается с ненулевым кодом выхода, будет вызвано исключение CalledProcessError. Атрибуты этого исключения содержат аргументы, код выхода и stdout и stderr, если они были захвачены.
, и этот пример для check=True лучше, чем один, который я мог бы придумать:
Расширенная подпись
Вот расширенная подпись, указанная в документации:
Обратите внимание, что это означает, что только список аргументов должен быть передан позиционно. Итак, передайте оставшиеся аргументы в качестве аргументов ключевого слова.
Popen
При использовании Popen вместо этого? Я бы изо всех сил пытался найти прецедент, основанный только на аргументах. Однако прямое использование Popen даст вам доступ к его методам, включая poll , «send_signal», «terminate» и «wait».
Вот подпись Popen , как указано в источнике . Я думаю, что это наиболее точное инкапсулирование информации (в отличие от help(Popen) ):
Но более информативным является документация Popen :
Выполнить дочернюю программу в новом процессе. В POSIX класс использует os.execvp () — подобное поведение для выполнения дочерней программы. В Windows класс использует функцию Windows CreateProcess (). Аргументы для Popen следующие.
Понимание оставшейся документации в Popen будет оставлено как упражнение для читателя.
subprocess.check_call удобно, если вы не хотите проверять возвращаемые значения. Он генерирует исключение при любой ошибке.
Я бы рекомендовал использовать модуль подпроцесса вместо os.system, потому что для него выполняется экранирование оболочки и, следовательно, гораздо безопаснее: http://docs.python.org/library/subprocess.html
Обновление:
subprocess.run является рекомендуемым подходом к Python 3.5 , если вашему коду не требуется поддерживать совместимость с более ранними версиями Python. Это более последовательно и предлагает аналогичную простоту использования в качестве посланника. (Трубопровод не так прост. См. этот вопрос, как .)
Вот несколько примеров из документов .
Поднять при неудачном прогоне:
Оригинальный ответ:
Я рекомендую попробовать Envoy . Это оболочка для подпроцесса, которая, в свою очередь, стремится заменить более старые модули и функции. Посланник является подпроцессом для людей.
Пример использования из readme :
Материал трубы тоже:
Я склонен использовать подпроцесс вместе с shlex (для обработки экранирования цитируемых строк):
Я всегда использую fabric для таких вещей, как:
Но это кажется хорошим инструментом: sh (интерфейс подпроцесса Python) .
С помощью стандартной библиотеки
Используйте модуль подпроцесса :
Это рекомендуемый стандартный способ. Однако более сложные задачи (трубы, выходные данные, вход и т. Д.) Могут быть утомительными для построения и записи.
Примечание: shlex.split может помочь вам разобрать команда для call и других функций subprocess в случае, если вы не хотите (или не можете!) предоставить их в виде списков:
С внешним Зависимости
Если вы не против внешних зависимостей, используйте plumbum :
Это лучшая обертка subprocess . Это кросс-платформенный, т. Е. Он работает как в Windows, так и в Unix-подобных системах. Установите pip install plumbum .
Еще одна популярная библиотека — sh :
Однако sh отказалась от поддержки Windows, поэтому она не такая потрясающая как это было раньше. Установите pip install sh .
Бесстыдный плагин, я написал для этого библиотеку: P https://github.com/houqp/shell.py
Это в основном оболочка для popen и shlex для Теперь. Он также поддерживает команды конвейеров, чтобы упростить цепочку команд в Python. Таким образом, вы можете делать такие вещи, как:
Чтобы получить идентификатор сети из нейтрона openstack:
Выход nova net-list
Вывод печати (networkId)
os.system в порядке, но как-то датировано. Это также не очень безопасно. Вместо этого попробуйте subprocess . subprocess не вызывает sh напрямую и поэтому более безопасен, чем os.system .
Получить дополнительную информацию здесь .
. или для очень простой команды:
os.system не позволяет сохранять результаты, поэтому, если вы хотите сохранить результаты в каком-то списке или что-то работает subprocess.call .
Мне очень нравится shell_command за его простоту. Он построен поверх модуля подпроцесса.
Вот пример из документов:
Если вы хотите вернуть результаты команды, вы можете использовать os.popen . Однако это не рекомендуется с версии 2.6 в пользу модуля подпроцесса , который хорошо освещает другие ответы.
Некоторые подсказки по отсоединению дочернего процесса от вызывающего (начало дочернего процесса в фоновом режиме).
Предположим, вы хотите запустить длинную задачу из CGI-скрипта, то есть дочерний процесс должен живут дольше, чем процесс выполнения CGI-скрипта.
Классический пример из документов модуля подпроцесса:
Идея здесь заключается в том, что вы не хотите ждать в line ‘call subprocess’, пока не будет закончен longtask.py. Но неясно, что происходит после строки «еще один код здесь» из примера.
Моя целевая платформа была бесплатной, но разработка была на окнах, поэтому я столкнулся с проблемой сначала в Windows
В окнах (win xp) родительский процесс не завершится, пока longtask.py не завершит свою работу. Это не то, что вы хотите в CGI-скрипте. Проблема не специфична для Python, в сообществе PHP проблемы одинаковы.
Решение состоит в передаче DETACHED_PROCESS Флаг создания процесса в базовую функцию CreateProcess в win API. Если вы установили pywin32, вы можете импортировать флаг из модуля win32process, иначе вы должны определить его самостоятельно:
/ * UPD 2015.10.27 @eryksun in комментарий ниже отмечает, что семантически правильный флаг CREATE_NEW_CONSOLE (0x00000010) * /
В freebsd у нас есть другая проблема: когда родительский процесс завершен, он также завершает дочерние процессы. И это не то, что вы хотите в CGI-скрипте. Некоторые эксперименты показали, что проблема, по-видимому, заключается в совместном использовании sys.stdout. И рабочим решением было следующее:
Я не проверял код на других платформах и не знаю причин поведения на freebsd. Если кто-нибудь знает, пожалуйста, поделитесь своими идеями. Googling при запуске фоновых процессов в Python еще не проливает свет.
Это может быть так просто:
Вот краткое описание способов вызова внешних программ и преимуществ и недостатков каждого из них:
- os.system(«some_command with args») передает команду и аргументы в оболочку вашей системы. Это хорошо, потому что вы можете запускать сразу несколько команд таким образом и настраивать каналы и перенаправление ввода / вывода. Например: Однако, хотя это удобно, вы должны вручную обрабатывать экранирование символов оболочки, таких как пробелы и т. Д. С другой стороны, это также позволяет запускать команды, которые являются просто командами оболочки, а не фактически внешними программами , См. документацию .
- stream = os.popen(«some_command with args») будет делать то же самое, что и os.system , за исключением того, что он дает файл-подобный объект, который вы можете использовать для доступа к стандартному вводу / выводу для этого процесса. Есть еще 3 варианта popen, которые все обрабатывают i / o немного по-другому. Если вы передаете все как строку, ваша команда передается в оболочку; если вы передадите их в список, то вам не нужно беспокоиться о том, чтобы избежать чего-либо. См. документацию .
- Класс Popen модуля subprocess . Это предназначено для замены os.popen , но имеет недостаток в том, что он немного усложняется благодаря тому, что он настолько всеобъемлющий. Например, вы могли бы сказать: вместо: , но хорошо иметь все варианты там в одном унифицированном классе вместо 4 различных функций popen. См. документацию .
- Функция call из модуля subprocess . Это в основном так же, как класс Popen , и принимает все те же аргументы, но он просто ждет, пока команда не завершится, и вы получите код возврата. Например: См. документацию .
- Если вы используете Python 3.5 или новее, вы можете использовать новую функцию subprocess.run , что очень похоже на выше, но еще более гибкое и возвращает объект CompletedProcess , когда команда завершает выполнение.
- В модуле os также есть все fork / exec / spawn, которые у вас были бы в программе на C, но я не рекомендую использовать их напрямую.
Возможно, модуль subprocess — это то, что вы используете.
Наконец, имейте в виду, что для всех методов, в которых вы передаете окончательную команду для выполнения оболочкой в виде строки, и вы несете ответственность за ее выход из нее. Имеются серьезные последствия для безопасности, если какая-либо часть передаваемой строки не может быть полностью доверена. Например, если пользователь вводит какую-либо / любую часть строки. Если вы не уверены, используйте эти методы только с константами. Чтобы дать вам намек на последствия, рассмотрите этот код:
и представьте, что пользователь вводит «моя мама не любила меня & amp; & amp; rm -rf /».
Источник
macOS subprocess.Popen not work #4859
Comments
tuda2009 commented May 6, 2020 •
PyInstaller 3.6
python 3.7.4
run dist/scClient the worker start successfully
run dist/scClient.app, but the worker not start. how to fix it? thanks!
The text was updated successfully, but these errors were encountered:
tuda2009 commented May 6, 2020
os.system(‘cp requirements.txt requirements.txt2’)
os.system same result as subprocess.Popen
chen-zehua commented Jul 6, 2020
i got the same issue, could anyone gives some tips?
EgeHe commented Jul 29, 2020
It seems that the working directory is root / when running .app.
I tested this by adding
to worker function. Working directory can then be read from path.txt in user home folder.
As I did not have requirements.txt in my root folder, the subprocess command did nothing. However, if copying fails in subprocess, it doesn’t raise python exception.
Copying worked after adding full paths to files in cp command. You can try if using full file paths work for you.
I ran the test with python 3.7.4 installed with pyenv and PyInstaller 3.6.
BoboTiG commented Oct 18, 2020
I reproduced the subprocess issue and fixed like that:
BoboTiG commented Oct 18, 2020
But I will need to test with PyQt involded, to see if there is something else wrong.
BoboTiG commented Oct 18, 2020
@tuda2009 could you try with PyInstaller 3.5?
BoboTiG commented Dec 2, 2020
I can’t reproduce. Here is a naive test case that do not trigger your issue (to put in tests/functional/test_libraries.py ):
This is ugly but we just need to know if it works on your machine. Could you try it?
glebarez commented Mar 30, 2021 •
@BoboTiG I,m experiencing same problem in different python versions (3.7 -3.9)
and did a test as you suggested above.
I used the current PyInstaller from develop branch (6df79e6)
Here’s the output (without full 3k lines log)
Should I try migrating my app to PySide2 ?
OS:
MacOS Catalina 10.15.7
BoboTiG commented Mar 31, 2021
Thanks for the test.
You can try to do the migration, but a fix will be needed for PyQt5 in any cases 🤔
glebarez commented Mar 31, 2021 •
Thanks for the test.
You can try to do the migration, but a fix will be needed for PyQt5 in any cases 🤔
Indeed migration to PySide works.
I think i need to add some details here about the bug itself.
In my case I was using subprocess.run() function, and passed a full path to the executable.
The call failed with error (printed to the console) «cannot open binary file».
In another shot I gave it the full path to a shell-script with shebang. That one failed because CWD was not set to a script’s location.
In summary: I know it sounds strange, but it seems that subprocess module (in a compiled PyQt5) treats executables as text/script files, and tries to source them via a shell.
Does that makes sense at all?
bwoodsend commented Mar 31, 2021
The call failed with error (printed to the console) «cannot open binary file».
Can we see the full error message in that case?
glebarez commented Mar 31, 2021 •
The call failed with error (printed to the console) «cannot open binary file».
Can we see the full error message in that case?
Sure, here I call two IDE’s via subprocess.call(» «) from PyQt5 signal handler.
First one is PyCharm, which is an executable at /usr/local/bin/charm
The console output is:
Next, I call VSCode, which is a shebang script at /usr/local/bin/code
The russian text in error output means «cannot run a binary file».
For reference, I give the /usr/local/bin/code contents below:
rokm commented Mar 31, 2021 •
/var/folders/24/lznsq7bs3jqd0t03v7n1wc0c0000gq/T/_MEIh4TmLO/python: /var/folders/24/lznsq7bs3jqd0t03v7n1wc0c0000gq/T/_MEIh4TmLO/python: cannot execute binary file
This one is because macOS filesystem is case-insensitive, and there’s Python shared library located in the _MEIPASS . And PyQt5 rthook explicitly prepends PATH with _MEIPASS (if PATH is set; which is probably true in this case) whereas PySide2 does not.
So trying to run python ends up in attempt to execute Python shared library, which fails.
rokm commented Mar 31, 2021
Adding equivalent of is_win condition to the referenced code block should probably do the trick, as PATH does not influence shared library search on linux and macOS.
BoboTiG commented Apr 6, 2021
@glebarez could you relaunch the test from the fix-4859-macos-subprocess-open branch and let us know if it effectively fixes your case?
glebarez commented Apr 6, 2021
@glebarez could you relaunch the test from the fix-4859-macos-subprocess-open branch and let us know if it effectively fixes your case?
@BoboTiG , hello.
Unfortunately same result.
Источник