使用 distutils / setuptools 执行 Python 脚本安装后

Posted

技术标签:

【中文标题】使用 distutils / setuptools 执行 Python 脚本安装后【英文标题】:Execute a Python script post install using distutils / setuptools 【发布时间】:2013-07-22 07:18:01 【问题描述】:

我正在尝试向 Python distutils 添加一个安装后任务,如How to extend distutils with a simple post install script? 中所述。该任务应该在已安装的 lib 目录中执行 Python 脚本。此脚本会生成已安装包所需的其他 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 获取的解释器,则安装后脚本将使用 不同的解释器执行,这可能会导致问题。 它对空运行等是不安全的,我可以通过将其包装在一个函数中并使用 distutils.cmd.Command.execute 调用它来进行补救。

如何改进我的解决方案?有推荐的方法/最佳实践吗?如果可能的话,我想避免引入另一个依赖项。

【问题讨论】:

对于那些想要同时使用python setup.py install,以及pip install的人,请参阅:***.com/questions/21915469/… 【参考方案1】:

解决这些不足的方法是:

    sys.executable获取执行setup.py的Python解释器的完整路径。

    distutils.cmd.Command 继承的类(例如我们在此处使用的distutils.command.install.install)实现execute 方法,该方法以“安全方式”执行给定函数,即尊重试运行标志。

    但请注意,the --dry-run option is currently broken 并不能按预期工作。

我最终得到了以下解决方案:

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 将使用的。

【讨论】:

谢谢,这真的很有帮助,我还需要关注 (***.com/questions/15853058/…) 以避免我的 pip 安装出错。我将所有内容放在一篇博文 (diffbrent.ghost.io/…) 中。如果我错过了什么,请告诉我。 @brent.payne 很高兴听到它有帮助!请注意我对为什么使用 install 作为类名的评论。 它可以工作,但我无法使用pip install -e name 执行自定义安装。 ps,刚刚找到this link,见BONUS部分。 看起来非常好,使用setuptools 而不是distutils 后安装部分仍然可以正常运行,但setuptools 处理依赖关系的能力似乎丢失了(它们只是被忽略了)。 @Paolo 的链接已移至:blog.niteo.co/setuptools-run-custom-code-in-setup-py【参考方案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()

【讨论】:

此代码似乎无法按预期工作...它将直接运行_post_action ...

以上是关于使用 distutils / setuptools 执行 Python 脚本安装后的主要内容,如果未能解决你的问题,请参考以下文章

Python setuptools/distutils 使用 Makefile 自定义构建 `extra` 包

如何将安装后脚本添加到 easy_install / setuptools / distutils?

python3 安装 pip3 出现问题??distutils.core 不存在

python怎么打包整个项目

python模块的打包setuptools

YOLOV7:AttributeError: module ‘distutils‘ has no attribute ‘version‘ 的解决方案