Выполните установку post python script с помощью distutils/setuptools
Я пытаюсь добавить задачу после установки в Python distutils, как описано в Как расширить distutils с помощью простой пост-установки script?. Предполагается, что задача должна выполнить Python script в установленном каталоге lib. Этот script генерирует дополнительные модули Python, которые требует установленный пакет.
Моя первая попытка следующая:
from distutils.core import setup
from distutils.command.install import install
class post_install(install):
def run(self):
install.run(self)
from subprocess import call
call(['python', 'scriptname.py'],
cwd=self.install_lib + 'packagename')
setup(
...
cmdclass={'install': post_install},
)
Этот подход работает, но, насколько я могу судить, имеет два недостатка:
- Если пользователь использовал интерпретатор Python, отличный от того, который был выбран из
PATH
, post install script будет выполняться с другим интерпретатором, который может вызвать проблему.
- Он не защищен от сухого пробега и т.д., который я мог бы исправить, обернув его функцией и называя его
distutils.cmd.Command.execute
.
Как я могу улучшить свое решение? Есть ли рекомендуемый способ/наилучшая практика для этого? Я хотел бы избежать по возможности затягивания другой зависимости.
Ответы
Ответ 1
Способ устранения этих недостатков:
- Получить полный путь к интерпретатору Python, выполняющему
setup.py
из sys.executable
.
-
Классы, наследующие от distutils.cmd.Command
(например, distutils.command.install.install
, которые мы здесь используем) реализуем метод execute
, который выполняет заданную функцию "безопасным способом", то есть соблюдает флаг сухого пробега.
Обратите внимание, что параметр --dry-run
в настоящее время отключен и не работает должным образом.
У меня получилось следующее решение:
import os, sys
from distutils.core import setup
from distutils.command.install import install as _install
def _post_install(dir):
from subprocess import call
call([sys.executable, 'scriptname.py'],
cwd=os.path.join(dir, 'packagename'))
class install(_install):
def run(self):
_install.run(self)
self.execute(_post_install, (self.install_lib,),
msg="Running post install task")
setup(
...
cmdclass={'install': install},
)
Обратите внимание, что я использую имя класса install
для моего производного класса, потому что это то, что будет использовать python setup.py --help-commands
.
Ответ 2
Я думаю, что самый простой способ выполнить пост-установку и сохранить требования - украсить вызов setup(...)
:
from setup tools import setup
def _post_install(setup):
def _post_actions():
do_things()
_post_actions()
return setup
setup = _post_install(
setup(
name='NAME',
install_requires=['...
)
)
Это приведет к запуску setup()
при объявлении setup
. После выполнения установки требований будет запущена _post_install()
, которая будет запускать внутреннюю функцию _post_actions()
.