使用 Python setuptools 的安装后脚本

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

python setup.py install

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

pip install <name>

并且脚本将在标准 setuptools 安装完成时运行?我希望执行可以在单个 Python 脚本文件中编码的安装后任务(例如,向用户发送自定义的安装后消息,从不同的远程源存储库中提取额外的数据文件)。

我偶然发现 这是几年前的回答解决了这个问题,当时的共识似乎是您需要创建一个 install 子命令。如果仍然是这种情况,是否可能有人提供一个示例,说明如何做到这一点,以便用户不必输入第二个命令来运行脚本?

53312 次浏览

注意: 下面的解决方案只有在安装源代码分发压缩文件或 tarball,或从源代码树以可编辑模式安装时才有效。它将 没有工作时,安装从一个二进制轮(.whl)


解决方案可以是在 setup.py的目录中包含一个 post_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__':语句允许您从命令行手动启动安装后。

注意: 下面的解决方案只有在安装源代码分发压缩文件或 tarball,或从源代码树以可编辑模式安装时才有效。它将 没有工作时,安装从一个二进制轮(.whl)


这种解决方案更加透明:

您将向 setup.py添加一些内容,并且不需要额外的文件。

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

将这两个包含 你的安装后脚本的类添加到 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):
develop.run(self)
# PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION


class PostInstallCommand(install):
"""Post-installation for installation mode."""
def run(self):
install.run(self)
# PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION

cmdclass参数插入到 setup.py中的 setup()函数:

setup(
...


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


...
)

You can even call shell commands during installation, like in this example which does pre-installation preparation:

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
from subprocess import check_call




class PreDevelopCommand(develop):
"""Pre-installation for development mode."""
def run(self):
check_call("apt-get install this-package".split())
develop.run(self)


class PreInstallCommand(install):
"""Pre-installation for installation mode."""
def run(self):
check_call("apt-get install this-package".split())
install.run(self)




setup(
...

另外,setuptools 上没有任何可用的预安装入口点。如果你想知道为什么没有 这个讨论,请阅读 这个讨论

注意: 下面的解决方案只有在安装源代码分发压缩文件或 tarball,或从源代码树以可编辑模式安装时才有效。它将 没有工作时,安装从一个二进制轮(.whl)


This is the only strategy that has worked for me when the post-install script requires that the package dependencies have already been installed:

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},

Combining the answers from @Apalala, @Zulu and @mertyildiran; this worked for me in a Python 3.5 environment:

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 工作。

我认为最简单的方法来执行后安装,并保持要求,是装饰对 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()

如果使用 atexit,则不需要创建新的 cmdclass。您可以简单地在 setup ()调用之前创建 atexit 寄存器。它也有同样的功能。

另外,如果您需要首先安装依赖项,那么使用 pip 安装就可以实现 没有,因为您的 atexit 处理程序将在 pip 将包移动到位之前被调用。

我不能用任何提出的建议来解决问题,所以下面是帮助我的建议。

你可以调用函数,在 setup.py中的 setup()之后,你想要在安装之后运行的函数,像这样:

from setuptools import setup


def _post_install():
<your code>


setup(...)


_post_install()