Как использовать python subprocess.run для вызова других файлов Python и файлов Bash ⇐ Python
-
Гость
Как использовать python subprocess.run для вызова других файлов Python и файлов Bash
Я использую python subprocess.run для вызова файлов .sh и .py, которые расположены в другом каталоге, удаленном от источника. Это единственная связь между двумя каталогами, поэтому импорт нецелесообразен. Код ниже упрощен до минимума.
родительский-каталог/ ├── реж.A │ ├── main.py │ └── main_test.py └── реж.B ├── app.sh └── утилита.py main.py
из пути импорта pathlib от ввода import Tuple, необязательно подпроцесс импорта импортировать систему dir_a_path = Путь(__file__).resolve().parent # получаем родительскую папку родительский_каталог = каталог_а_путь.родитель dir_b_path = str(parent_dir.joinpath("dirB")) defexecute_bash_command(команда: str, cwd: Необязательный[str]=None) -> Tuple[int, str, str]: """Запускает команду bash в новой оболочке. exit_code, stdout, stderr = Execute_bash_command (команда) Аргументы: команда (str): команда для запуска cwd (Необязательно[str]): откуда запускать командную строку. Используйте это вместо команды «cd some_dir/ &&» Поднимает: Исключение: Исключение Возврат: Tuple[int, str, str]: [код выхода, stdout, stderr] """ пытаться: print(f"Выполнение {команды} из cwd: {cwd}") вывод = subprocess.run(команда, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, проверка=True, оболочка=True) stdout = output.stdout.decode("utf-8").strip() печать (стандартный вывод) return (output.returncode, stdout, "") кроме subprocess.CalledProcessError как cpe: print(f"ошибка: {cpe}") stdout = cpe.stdout.decode("utf-8").strip() stderr = cpe.stderr.decode("utf-8").strip() возврат (cpe.returncode, stdout, stderr) def call_app() -> Tuple[int, str, str]: команда = [ "./app.sh", "установить" ] команда = " ".join(команда) вернуть выполнение_bash_command (команда = команда, cwd = dir_b_path) def call_utility() -> Tuple[int, str, str]: команда = [ sys.исполняемый файл, "приветствовать" ] команда = " ".join(команда) вернуть выполнение_bash_command (команда = команда, cwd = dir_b_path) main_test.py
из основного импорта call_app, call_utility защита test_call_app(): код, стандартный вывод, стандартный вывод = call_app() код подтверждения == 0 Assert stdout == "Установка приложения..." защита test_call_utility(): код, стандартный вывод, стандартный вывод = call_utility() код подтверждения == 0 Assert stdout == "выполнение команды приветствия" защита test_execute_bash_command(): """ Создает фиктивный файл """ exit_code, stdout, _ = Execute_bash_command("touch tmp/test.txt") утверждать код выхода == 0 app.sh
#!/bin/bash if [ "$1" = "приветствую"]; затем echo "Привет, мир!" элиф ["$1" = "установить"]; затем echo "Установка приложения..." еще echo "Использование: $0 {greet|install}" выход 1 фи utility.py
импортировать систему если __name__ == "__main__": print(f"выполнение команды {sys.argv[1]}") Когда я запускаю из терминала python Utility.py Greeting или ./app.sh install, все работает нормально. Проблема в том, что я выполняю main_test.py, используя python -m pytest. Я получаю ошибки о том, что подпроцесс завершился с разными кодами.
Ошибки:
Выполнение установки ./app.sh из cwd: /mnt/c/Users/XXX/source/python-testing/parent-dir/dirB ошибка: команда «./app.sh install» вернула ненулевой статус выхода 1. или
Выполнение приветствия /usr/bin/python3 из cwd: /mnt/c/Users/XXX/source/python-testing/parent-dir/dirB ошибка: команда «/usr/bin/python3 Greeting» вернула ненулевой статус выхода 2. Эти ошибки возникают при запуске pytest как из PowerShell, так и из WSL2.
Эти ошибки имитируют реальные ошибки, возникающие в базе кода.
Почему это не работает так, как задумано? Является ли использование cwd в subprocess.run неправильным решением? Я застрял, потому что пытаюсь провести рефакторинг какого-то отвратительного кода, который волшебным образом работает, но не ясен, поэтому буду признателен за советы.
Я использую python subprocess.run для вызова файлов .sh и .py, которые расположены в другом каталоге, удаленном от источника. Это единственная связь между двумя каталогами, поэтому импорт нецелесообразен. Код ниже упрощен до минимума.
родительский-каталог/ ├── реж.A │ ├── main.py │ └── main_test.py └── реж.B ├── app.sh └── утилита.py main.py
из пути импорта pathlib от ввода import Tuple, необязательно подпроцесс импорта импортировать систему dir_a_path = Путь(__file__).resolve().parent # получаем родительскую папку родительский_каталог = каталог_а_путь.родитель dir_b_path = str(parent_dir.joinpath("dirB")) defexecute_bash_command(команда: str, cwd: Необязательный[str]=None) -> Tuple[int, str, str]: """Запускает команду bash в новой оболочке. exit_code, stdout, stderr = Execute_bash_command (команда) Аргументы: команда (str): команда для запуска cwd (Необязательно[str]): откуда запускать командную строку. Используйте это вместо команды «cd some_dir/ &&» Поднимает: Исключение: Исключение Возврат: Tuple[int, str, str]: [код выхода, stdout, stderr] """ пытаться: print(f"Выполнение {команды} из cwd: {cwd}") вывод = subprocess.run(команда, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, проверка=True, оболочка=True) stdout = output.stdout.decode("utf-8").strip() печать (стандартный вывод) return (output.returncode, stdout, "") кроме subprocess.CalledProcessError как cpe: print(f"ошибка: {cpe}") stdout = cpe.stdout.decode("utf-8").strip() stderr = cpe.stderr.decode("utf-8").strip() возврат (cpe.returncode, stdout, stderr) def call_app() -> Tuple[int, str, str]: команда = [ "./app.sh", "установить" ] команда = " ".join(команда) вернуть выполнение_bash_command (команда = команда, cwd = dir_b_path) def call_utility() -> Tuple[int, str, str]: команда = [ sys.исполняемый файл, "приветствовать" ] команда = " ".join(команда) вернуть выполнение_bash_command (команда = команда, cwd = dir_b_path) main_test.py
из основного импорта call_app, call_utility защита test_call_app(): код, стандартный вывод, стандартный вывод = call_app() код подтверждения == 0 Assert stdout == "Установка приложения..." защита test_call_utility(): код, стандартный вывод, стандартный вывод = call_utility() код подтверждения == 0 Assert stdout == "выполнение команды приветствия" защита test_execute_bash_command(): """ Создает фиктивный файл """ exit_code, stdout, _ = Execute_bash_command("touch tmp/test.txt") утверждать код выхода == 0 app.sh
#!/bin/bash if [ "$1" = "приветствую"]; затем echo "Привет, мир!" элиф ["$1" = "установить"]; затем echo "Установка приложения..." еще echo "Использование: $0 {greet|install}" выход 1 фи utility.py
импортировать систему если __name__ == "__main__": print(f"выполнение команды {sys.argv[1]}") Когда я запускаю из терминала python Utility.py Greeting или ./app.sh install, все работает нормально. Проблема в том, что я выполняю main_test.py, используя python -m pytest. Я получаю ошибки о том, что подпроцесс завершился с разными кодами.
Ошибки:
Выполнение установки ./app.sh из cwd: /mnt/c/Users/XXX/source/python-testing/parent-dir/dirB ошибка: команда «./app.sh install» вернула ненулевой статус выхода 1. или
Выполнение приветствия /usr/bin/python3 из cwd: /mnt/c/Users/XXX/source/python-testing/parent-dir/dirB ошибка: команда «/usr/bin/python3 Greeting» вернула ненулевой статус выхода 2. Эти ошибки возникают при запуске pytest как из PowerShell, так и из WSL2.
Эти ошибки имитируют реальные ошибки, возникающие в базе кода.
Почему это не работает так, как задумано? Является ли использование cwd в subprocess.run неправильным решением? Я застрял, потому что пытаюсь провести рефакторинг какого-то отвратительного кода, который волшебным образом работает, но не ясен, поэтому буду признателен за советы.
Мобильная версия