使用Python setuptools安装后脚本

时间:2013-11-29 15:11:59

标签: python setuptools software-distribution setup.py pypi

是否可以将安装后的Python脚本文件指定为setuptools setup.py文件的一部分,以便用户可以运行该命令:

python setup.py install

在本地项目文件存档上,或

pip install <name>

对于PyPI项目,脚本将在标准setuptools安装完成后运行?我希望执行可以在单个Python脚本文件中编码的安装后任务(例如,向用户提供自定义安装后消息,从其他远程源存储库中提取其他数据文件)。

我遇到了解决该主题的this SO answer from several years ago,听起来好像当时的共识是你需要创建一个install子命令。如果仍然如此,是否有人可以提供如何执行此操作的示例,以便用户无需输入第二个命令来运行脚本?

7 个答案:

答案 0 :(得分:61)

此解决方案更透明:

您将对 setup.py 添加一些内容,而无需额外的文件。

另外,您需要考虑两种不同的后期安装;一个用于开发/可编辑模式,另一个用于安装模式。

将包含您的安装后脚本的这两个类添加到 setup.py

if (dot) *dot = '.';

并在{strong> setup.py 中向from setuptools import setup from setuptools.command.develop import develop from setuptools.command.install import install class PostDevelopCommand(develop): """Post-installation for development mode.""" def run(self): # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION develop.run(self) class PostInstallCommand(install): """Post-installation for installation mode.""" def run(self): # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION install.run(self) 函数插入cmdclass参数:

setup()

您甚至可以在安装后调用shell命令,如下所示:

setup(
    ...

    cmdclass={
        'develop': PostDevelopCommand,
        'install': PostInstallCommand,
    },

    ...
)

P.S。 setuptools上没有任何预安装入口点。如果您想知道为什么没有,请阅读this discussion

答案 1 :(得分:11)

当安装后脚本要求已经安装了软件包依赖项时,这是唯一对我有用的策略:

import atexit
from setuptools.command.install import install


def _post_install():
    print('POST INSTALL')


class new_install(install):
    def __init__(self, *args, **kwargs):
        super(new_install, self).__init__(*args, **kwargs)
        atexit.register(_post_install)


setuptools.setup(
    cmdclass={'install': new_install},

答案 2 :(得分:6)

解决方案可能是在post_setup.py目录中加入setup.pypost_setup.py将包含一个执行安装后的功能,而setup.py只会在适当的时间导入并启动它。

setup.py

from distutils.core import setup
from distutils.command.install_data import install_data

try:
    from post_setup import main as post_install
except ImportError:
    post_install = lambda: None

class my_install(install_data):
    def run(self):
        install_data.run(self)
        post_install()

if __name__ == '__main__':
    setup(
        ...
        cmdclass={'install_data': my_install},
        ...
    )

post_setup.py

def main():
    """Do here your post-install"""
    pass

if __name__ == '__main__':
    main()

有了从其目录启动setup.py的常见想法,您将能够导入post_setup.py否则它将启动一个空函数。

post_setup.py中,if __name__ == '__main__':语句允许您从命令行手动启动安装后。

答案 3 :(得分: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()

答案 4 :(得分:1)

如果使用atexit,则无需创建新的cmdclass。您可以直接在setup()调用之前创建atexit寄存器。它做同样的事情。

此外,如果您需要先安装依赖项,则不适用于pip安装,因为将在pip将软件包移到位之前调用atexit处理程序。

答案 5 :(得分:1)

我无法通过提出的任何建议解决问题,所以这对我有所帮助。

您可以调用要在安装后在setup()setup.py之后运行的函数,如下所示:

from setuptools import setup

def _post_install():
    <your code>

setup(...)

_post_install()

答案 6 :(得分:0)

结合@Apalala,@ Zulu和@mertyildiran的答案;这在Python 3.5环境中适用于我:

import atexit
import os
import sys
from setuptools import setup
from setuptools.command.install import install

class CustomInstall(install):
    def run(self):
        def _post_install():
            def find_module_path():
                for p in sys.path:
                    if os.path.isdir(p) and my_name in os.listdir(p):
                        return os.path.join(p, my_name)
            install_path = find_module_path()

            # Add your post install code here

        atexit.register(_post_install)
        install.run(self)

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

这也允许您访问install_path中包的安装路径,以便进行一些shell工作。