Запустите сценарий оболочки во время установки pip

Я опубликовал пакет PyPI, для которого требуются некоторые дополнительные пакеты Apt, поэтому в моем репозитории Github есть setup.sh, который я хочу выполнить вместе с процессом установки pip install mypackage (т. е. всякий раз, когда пользователь запускает pip install mypackage, он должен запускать сценарий оболочки во время процесс установки.)

Я сделал setup.py, чтобы использовать параметр cmdclass вот так

from setuptools import setup, find_packages
from setuptools.command.install import install
import subprocess
import codecs 
import os

class CustomInstall(install):
    def run(self):
        subprocess.check_call("bash setup.sh", shell=True)
        install.run(self)

with open('requirements.txt') as f:
    requirements = f.read().splitlines()


setup(
    ...
    cmdclass = {'install': CustomInstall},   install_requires=requirements,
    ...
)

Когда я обычно собираю его с помощью python setup.py sdist bdist_wheel, класс Custominstall работает нормально, но во время установки pip он игнорирует класс Custominstall.

Наконец я нашел эту ветку stackoverflow, из которой я узнал, что мне нужно только запустить python setup.py sdist, что я и сделал, и получил файл tar.gz в папке dist, но когда я перехожу к установке этого файла tar.gz с помощью pip install, я получаю

with open('requirements.txt') as f:

           ^^^^^^^^^^^^^^^^^^^^^^^^

  FileNotFoundError: [Errno 2] No such file or directory: 'requirements.txt'

Что я делаю не так? Путь неверный? Файл требований находится в родительской папке моего репозитория (а не внутри какой-либо другой папки).

«Файл требований находится в родительской папке моего репозитория (а не внутри какой-либо другой папки)» — но что вы видите в архиве?

Karl Knechtel 26.03.2024 08:17
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
513
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Непосредственная проблема заключается в том, что процесс pip запускается в любом каталоге, в котором находится вызывающий пользователь. Возможно, см. Также Что такое текущий рабочий каталог?

Решение этой проблемы: Как мне получить путь и имя файла Python, который выполняется в данный момент? -- по сути, проверьте __file__ и извлеките из него каталог, к которому вы хотите получить доступ.

Однако предпосылка вашего вопроса кажется глубоко ошибочной. Вам следует объявить зависимости от тех пакетов Python, от которых вы зависите, и позволить pip взять их оттуда; или же создайте пакет Debian, а затем объявите все свои зависимости в терминах других пакетов Debian. (Конечно, вы можете сделать и то, и другое. Конечно, в последнем случае вам, вероятно, следует сделать и первое, чтобы ваш пакет можно было установить на платформах, отличных от Debian.)

Вы не сообщили нам, от каких пакетов будет зависеть ваш, поэтому мы можем сформулировать это только в самых общих чертах. Допустим, ваша посылка зависит от requests и beautifulsoup4. Тогда ваш setup.py должен объявить эти зависимости:

setup(
   ...
   install_requires=["requests", "beautifulsoup4"],
   ...
)

Для удобства вы также можете объявить их в requirements.txt, но этот файл не играет формальной роли в упаковке Python. Ваши зависимости должны быть объявлены в setup.py (или для современных пакетов определенно предпочтительнее pyproject.toml или setup.cfg).

Если некоторые из этих зависимостей можно выполнить через менеджер пакетов ОС, предоставление другого механизма установки для удобства не является обязательным, но является приятным дополнением. Ваш пакетный скрипт не должен от этого зависеть (а возможно и наоборот).

#!/bin/sh
apt-get install -y python3-requests python3-bs4

(Возможно, обратите внимание также на то, что пакеты Debian обычно имеют другие имена, чем соответствующие пакеты Python. Это неприятно, но в принципе неизбежно.)

Я использовал небольшой обходной путь, чтобы распечатать файлы из каталогов с помощью script_dir = os.path.dirname(os.path.realpath(__file__)) dir_contents = os.listdir(script_dir) print("Contents of the directory:") for item in dir_contents: print(item), и увидел, что требований.py и setup.py там нет. Содержимое каталога было: LICENSE PKG-INFO README.md setup.cfg setup.py mypackage mypackage.egg-info build

Ayus Chatterjee 26.03.2024 06:36

Хорошо, я нашел частичное решение, основанное на том, что вы сказали, я помещу требования pip в install_requires = [] и что я сделал, это переместил сценарий setup.sh в mypackage/setup.sh и использовал параметр package_data в setup() package_data = {'mypackage': ['setup.sh']}, include_package_data=True, и изменил мой класс CustomIntall как class CustomInstall(install): def run(self): script_dir = os.path.dirname(os.path.realpath(__file__)) setup_sh= script_dir+"/mypackage/setup.sh" os.system(f"bash {setup_sh}") install.run(self)

Ayus Chatterjee 26.03.2024 07:30

Странно, что он использует apt вместо pkg, тогда как мой скрипт везде использовал pkg./data/data/com.termux/files/usr/tmp/pip-req-build‌​-ky2zym9d/setup.py No mirror or mirror group selected. You might want to select one by running 'termux-change-repo' Checking availability of current mirror: [*] https://termux.astra.in.ua/apt/termux-main: ok WARNING: apt does not have a stable CLI interface. Use with caution in scripts. Hit:1 https://termux.astra.in.ua/apt/termux-main stable InRelease Reading package lists... ...... ...... ......

Ayus Chatterjee 26.03.2024 07:54
Ответ принят как подходящий

Причина, по которой это происходит, заключается в том, что ваш setup.py зависит от requirements.txt, но вы не упаковываете requirements.txt в свой дистрибутив. Если вы откроете .tar.gz, вы не найдете свой requirements.txt файл. Чтобы это исправить, создайте файл MANIFEST.in с содержимым:

include requirements.txt

И добавьте include_package_data=True к своему setup звонку.

Вам нужно будет добавить любые другие файлы, не относящиеся к Python, которые вы хотите включить в свой дистрибутив .tar.gz, например, ваш скрипт setup.sh.

Когда вы создадите свой исходный дистрибутив с этими изменениями, вы увидите, что requirements.txt теперь включен в содержимое вашего дистрибутива сборки.

Альтернативно, вы также можете использовать для этого ключевое слово package_data в setup (или [options.package_data] в setup.cfg). См.: эту ссылку для более подробного объяснения.


Однако, вообще говоря, запускать сценарии оболочки или устанавливать системные пакеты как часть вашего setup.py. Это усложнит использование вашего пакета, а не упростит его.

Если ваш пакет зависит от зависимостей Python, используйте вместо него install_requires.

Я боролся несколько дней, хотя решение было таким простым 😦. Большое спасибо. Теперь pip install работает нормально и может найти все необходимые файлы. Я понимаю ваше предложение, но у меня нет возможности полагаться на эти системные пакеты, поскольку мой скрипт Python полностью полагается на эти пакеты, такие как диалог для gui, ffmpeg, termux-api и т. д. Вы можете посмотреть мой репозиторий

Ayus Chatterjee 26.03.2024 08:18

Обычно вы оставляете пользователю право убедиться, что у него установлены правильные системные пакеты. Вы можете выдать полезную ошибку, если ваши внешние зависимости не найдены, например if not shutil.which('ffmpeg'): raise EnvironmentError("ffmpeg is not installed, please install it e.g., with 'apt install ffmpeg'") или что-то в этом роде. Множество популярных библиотек Python зависят от системных пакетов — я гарантирую, что ни одна из них не установит эти зависимости за вас! В качестве альтернативы вы можете рассмотреть возможность создания пакета conda или собственного пакета Debian для установки всего @AyusChatterjee

sytech 26.03.2024 08:23

Другие вопросы по теме