使用Python setuptools安装后的脚本

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

python setup.py install 

在本地项目文件存档或

 pip install <name> 

为一个PyPI项目和脚本将运行在标准setuptools安装完成? 我正在寻找执行安装后任务,可以编写在一个Python脚本文件(例如,提供一个自定义的安装后的消息给用户,从另一个远程源库拉额外的数据文件)。

几年前我遇到了这个解决这个问题的答案,听起来好像当时的共识是你需要创build一个install子命令。 如果情况仍然如此,那么是否有人可以提供一个如何执行此操作的示例,以便用户不必input第二个命令来运行脚本?

这个解决scheme更透明:

你将会对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): # 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) 

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

 setup( ... cmdclass={ 'develop': PostDevelopCommand, 'install': PostInstallCommand, }, ... ) 

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

 from setuptools import setup from setuptools.command.develop import develop from setuptools.command.install import install from subprocess import check_call class PostDevelopCommand(develop): """Post-installation for development mode.""" def run(self): check_call("apt-get install this-package".split()) develop.run(self) class PostInstallCommand(install): """Post-installation for installation mode.""" def run(self): check_call("apt-get install this-package".split()) install.run(self) setup( ... 

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

这是安装后脚本要求已经安装软件包依赖关系的唯一策略:

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

一个解决scheme可能是在setup.py的目录中包含post_setup.pypost_setup.py将包含一个安装后的function, 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.pyif __name__ == '__main__':语句允许您从命令行手动启动后安装。

结合@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访问软件包的安装path,做一些shell的工作。