LINUX.ORG.RU

Выполнить одну команду в контексте python'овского virtual environment

 ,


0

1

Есть задача запустить одну(!) команду в контексте python’овского virtual environment, и вернуться обратно в нормальный контекст

(Дислаймеры: Одну команду. Одной башевской командой, запустить одну башевскую команду в том контексте и вернуться обратно. Как sudo ls. Нет, заходить в venv мне не надо, не предлагайте. Писать обертки которая зайдет и выйдет тоже не подходит.)

Пока рабочие варианты у меня

bash -c 'source ~/.venv/bin/activate; export'

или

(cat  ~/.venv/bin/activate ; echo "export" ) | bash

которые по сути те же обертки только в одну строку. Команда export приведена для примера. По ее выводу можно определить что она отработала внутри venv’а.

Есть ли какие-то более прямые способы, или в питоне все так и должно быть через одно место, и с эти надо смириться?

Update: правильный ответ от @firkax

( . ~/.venv/bin/activate ; export )
★★★

Последнее исправление: shaplov (всего исправлений: 2)

Ответ на: комментарий от pekmop1024

а при чем тут питон, если ты шелл-команды выполняешь?

Потому что в продакшене там будет запуск некоего питоновского быдлокода, про который лучше всего не знать никому и никогда. И ему нужен свой venv.

shaplov ★★★
() автор топика

Не знаю что такое venv, но судя по тому что ты пишешь, venv это и есть шелл-обёртка над чем-то по своей сути, и если даже ты придумаешь команду где её обёрточная суть будет не видна - она будет просто спрятана внутри.

Что касается твоих команд, то кажется можно ещё короче

( . ~/.venv/bin/activate ; export )

Круглые скобки это то же самое что bash/sh -c "..." (но без перечитывания бинарника шелла с диска), а точка - то же что и source.

Второй вариант их твоих двух плохой: ты запускаешь два шелла, один чтоб сделать echo команд и второй чтоб их исполнять, это какая-то ерунда.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 4)
Ответ на: комментарий от firkax

( . ~/.venv/bin/activate ; export )

Да, пожалуй так лучше…

А можешь пояснить, что именно делают скобки… Они клонируют текущей контекст shella (переменные окружения и вот это всё) и по завершении его уничтожают, возвращась к предыдущему? Или может там сам shell форкается и естественным образом по завершении форка все забывает? Что там под капотом?

Не знаю что такое venv

Вот похоже что это ключевой момент… Те кто знают, ответить не могут. Морок какой-то на них наведен…

shaplov ★★★
() автор топика
Ответ на: комментарий от shaplov

сам shell форкается и естественным образом по завершении форка все забывает?

Вот это, можно легко проверить выполнив такую команду

( A=B ; ( A=B ; ( A=B ; ( A=B ; sleep 12345 ) ) ) )
или
( ( ( ( sleep 12345 ; A=B ) ; A=B ) ; A=B ) ; A=B )
и посмотрев дерево процессов. Если A=B; не дописывать то он видимо учитывает что в скобках всего одна команда и оптимизирует - не форкается.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)

You don’t specifically need to activate a virtual environment, as you can just specify the full path to that environment’s Python interpreter when invoking Python. Furthermore, all scripts installed in the environment should be runnable without activating it.

thesis ★★★★★
()

Есть задача запустить одну(!) команду в контексте python’овского virtual environment

Какую команду, если не секрет? Я не вижу смысла запускать в venv что-то, кроме питоновских скриптов. А их можно запускать без source bin/activate, как написал @thesis.

anonymous
()
Ответ на: комментарий от anonymous

Какую команду, если не секрет? Я не вижу смысла запускать в venv что-то, кроме питоновских скриптов. А их можно запускать без source bin/activate, как написал @thesis.

Сначала pip install того что этот быдлокод хочет видеть, а потом сам быдлокод, да.

Звучит логично. Но не один питонист до @thesis мне такого не предложил. А меня история venv ввела в такой ступор, что я не догадался спросить.

Тогда вопрос, а как это делается, чтобы я знал на будущее?

shaplov ★★★
() автор топика
Ответ на: комментарий от shaplov
<venv>/bin/pip install -r requirements.txt

<venv>/bin/python program.py

Либо, для запуска, добавь строчку с шебангом до <venv>/bin/python в свой скрипт, сделай его исполняемым и просто запускай как ./program.py.

«pip install» можно также запускать из скрипта, если, например, при импорте модуля возникло исключение ModuleNotFoundError:

try:
    import module
except ModuleNotFoundError:
    import pip
    exit_status = pip.main(['install', 'module'])
    if exit_status == 0:
        import module

Можно это дело обернуть в функцию, тогда для импорта используй встроенную функцию __import__(), принимающую строкой имя модуля.

Но лучше явное pip install, чем неявное pip.main(['install', ...]).

anonymous
()
Ответ на: комментарий от t184256

.venv/bin/python -c ‘import sys; print(sys.path)’

Почему это работает? У питона и pip разное поведение в зависимости от того из какого места на него указывает символическая ссылка? Я не понимаю. В документации приведенной ниже я про это не нашел. Может плохо искал.

shaplov ★★★
() автор топика
Ответ на: комментарий от shaplov

У питона и pip разное поведение в зависимости от того из какого места на него указывает символическая ссылка?

pip - это всего лишь костыль для чего-то типа python -m pip:

❯ cat `which pip`
#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == "__main__":
    sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0])
    sys.exit(main())

Ну или:

❯ cat `which yt-dlp`
#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from yt_dlp import main
if __name__ == "__main__":
    sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0])
    sys.exit(main())

Шибанг - наше все!

rtxtxtrx
()
Последнее исправление: rtxtxtrx (всего исправлений: 1)
Ответ на: комментарий от shaplov

Короче, питон ищет установленные модули в папочке lib на уровень выше той, из которой запускается (bin - в которой находится бинарник). venv просто копирует экзешник со всеми потрохами и после его активации ты устанавливаешь модули в отдельную папочку, ага.

rtxtxtrx
()
Последнее исправление: rtxtxtrx (всего исправлений: 2)
Ответ на: комментарий от rtxtxtrx

Короче, питон ищет установленные модули в папочке lib на уровень выше той, из которой запускается (bin - в которой находится бинарник). venv просто копирует экзешник со всеми потрохами и после его активации ты устанавливаешь модули в отдельную папочку, ага.

Ага. Этого куска в мозайке мне не хватало. Теперь все стало понятно. Мне это поведение не кажется логичным, но как минимум оно объясняет что ранее пытались сказать эти странные люди… Спасибо!

shaplov ★★★
() автор топика
Последнее исправление: shaplov (всего исправлений: 1)