问题:使用Python setuptools的安装后脚本
是否可以在setuptools setup.py文件中指定安装后的Python脚本文件,以便用户可以运行以下命令:
python setup.py install
在本地项目文件存档上,或
pip install <name>
对于PyPI项目,该脚本将在标准setuptools安装完成时运行吗?我希望执行可以在单个Python脚本文件中编码的安装后任务(例如,向用户传递自定义安装后消息,从其他远程源存储库中提取其他数据文件)。
几年前,我遇到了这个SO答案,它回答了该主题,听起来好像当时的共识是您需要创建一个install子命令。如果仍然是这种情况,是否可以有人提供如何执行此操作的示例,以便用户不必输入第二条命令来运行脚本?
回答 0
注意:以下解决方案仅在安装源分发zip或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()
函数中插入参数setup.py
:
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 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(
...
PS:setuptools上没有任何预安装入口点。如果您想知道为什么没有,请阅读此讨论。
回答 1
注意:以下解决方案仅在安装源分发zip或tarball或从源树以可编辑模式安装时有效。从二元轮()安装时将无法使用.whl
当安装后脚本要求已安装软件包依赖项时,这是对我有用的唯一策略:
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
注意:以下解决方案仅在安装源分发zip或tarball或从源树以可编辑模式安装时有效。从二元轮()安装时将无法使用.whl
一个解决方案可能是post_setup.py
在in setup.py
目录中包含一个。post_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
结合@ 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工作。
回答 4
我认为执行后安装并保持要求的最简单方法是装饰对的调用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()
。
回答 5
如果使用atexit,则无需创建新的cmdclass。您可以直接在setup()调用之前创建atexit寄存器。它做同样的事情。
另外,如果你需要依赖先安装,但这不是用PIP工作进行安装,因为你的atexit处理程序之前PIP移动套餐到位调用。
回答 6
我无法通过提出的任何建议来解决问题,因此这对我有所帮助。
你可以调用功能,你想刚过安装之后运行setup()
的setup.py
,这样的:
from setuptools import setup
def _post_install():
<your code>
setup(...)
_post_install()