Запустить скрипт в потоке с другим интерпретатором
У меня есть скрипт, который выполняется одним интерпретатором (виртуальное окружение). Мне из него нужно создать поток, который запустит другой скрипт с другим интерпретатором (тоже виртуальное окружение). Как это сделать?
Пробовал передавать все в os.system() - возникает ошибка
ModuleNotFoundError: No module named 'module name'
Попробовал поставить зависимости из вызываемого интерпретатора окружения в это окружение - та же самая ошибка
Пробовал добавить перед вызовом скрипта в os.system() source /path/to/venv/bin/activate; - тоже не помогло.
Как можно это сделать?
Вызов происходит так:
th = threading.Thread(target=os.system, args=(params,))
th.start()
upd. Попробовал в вызываемом скрипте сделать
sys.path.append('/путь/к/вызывающей/программе')
Тоже не помогло
upd. Добавил пример:
# Вызывающий скрипт
import threading
import os
th = threading.Thread(target=os.system, args=('/path/to/flask/app.py',))
th.start()
# Вызываемый скрипт
#!/usr/bin/python3
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
Если выполнить вызывающий скрипт, то получим
Traceback (most recent call last):
File "/path/to/flask/app.py", line 3, in <module>
from flask import Flask
ModuleNotFoundError: No module named 'flask'
потому что у интерпретатор вызывающего скрипта нет flask (модуль взят только для примера)
Ответы (2 шт):
как пример - запуск этого-же файла, но рекурсивно с другим интерпретатором, импортируя при этом lib_new.settings, путем смены текущей домашней директории в cwd_to_lib_folder, которая может отличатся в новом процессе, от той, в которой запускали главный запускающий файл
import subprocess, os, sys
def cwd_to_lib_folder(lib_folder='lib_new', dsk=True) -> str:
""" нужно что-то такое, для импорта, при выполнении в отдельном python процессе.
т.е. найти каталог lib_folder, и сменить текущую директорию, для импорта польз. модулей, при неверной домашней директории
"""
path = os.path.abspath(os.path.dirname(__file__))
while lib_folder not in next(os.walk(path))[1]:
path = os.path.join(path, '..')
if dsk:
os.chdir(path[:2])
path = False
os.chdir(path)
sys.path.append(path)
return path
###
try: # импорт lib_new.settings при обычном запуске
Path = os.getcwd()
import lib_new.settings
except: # импорт lib_new.settings при запуске с другим интерпретатором
Path = cwd_to_lib_folder()
import lib_new.settings
###
if __name__ == '__main__':
if len(sys.argv) == 2:
a = int(sys.argv[1])
else:
a = 1
if a < 10:
sp = subprocess.Popen(['python', __file__, str(a+1)]) # запустить этот-же скрипт, но с другим интерпретатором
sp.communicate()
print(a)
out:
9
8
7
6
5
4
3
2
1
Нашел решение, которое, я уверен, не самое элегантное, но рабочее. В вызывающем скрипте управление нужно передать интерпретатору os.system (то есть bash в моем случае). Его содержимое:
#!/bin/bash
source $1
python3 $2
где $1 - путь до вашего venv/bin/activate, и $2 - путь до вызываемого скрипта. Таким образом в вызывающем скрипте мы пишем
import threading
import os
th = threading.Thread(target=os.system, args=('solve.sh /home/path/to/venv/bin/activate /home/path/to/app.py',))
th.start()
таким образом будет получен экземпляр системного интерпретатора, который затем зайдет в виртуальное окружение и выполнит скрипт в нем.