我为一个使用模块(https://luarocks.org/)来管理包的系统编写小python包。对于那些不了解它的人,你可以运行module load x
并运行一个小脚本来修改各种环境变量以制作软件' x'然后,您可以使用module unload x
撤消此操作。
这种软件管理方法在科学计算中几乎无处不在,并且在该领域具有很多价值:您可以运行古老的非维护软件以及该软件会干扰的软件包,您可以运行多个版本的软件,这样您就可以准确地重现你的数据(你可以回到旧版本),你可以用过时的依赖性来运行写得不好的非更新软件。
这些功能很棒,但是它们会导致python 2/3拆分出现问题:
如果你想编写一个适用于两者 python 2和3的软件包,并将其与需要 python 2或3的软件一起使用,该怎么办?
你让旧的python2依赖软件在这些大型系统上工作的方式是你创建一个python / 2.7.x模块和一个python / 3.5模块。如果要运行使用python 2的脚本,请加载该模块等。
但是,我想编写一个可以在 环境中工作的python包,因为无论使用哪个python解释器,我都希望该软件处于活动状态。
这从根本上说非常简单:只需使用#!/usr/bin/env python
shebang行即可完成。这样可行。我写的所有软件都可以使用,所以没问题。
问题是:我想使用setuptools将我的包分发给同样情况下的其他科学家,并且设置工具会破坏shebang系列。
我不想进入关于是否管理shebang线是否是一个好主意的辩论,我相信它已经存在多年了,现在已经存在于同一个州。老实说,我不在乎,它对我不起作用。默认的setuptools安装导致软件无法运行,因为当没有加载python解释器模块时,python解释器不起作用,PYTHONPATH
完全错误。
如果我的所有用户都具有超级用户权限,我可以使用data_files
选项将脚本复制到/usr/bin
,但这对兼容性来说不是一个好主意,而且我的用户不会这样做。无论如何都有root访问权限,所以这是一个没有实际意义的点。
到目前为止我尝试过的事情:
我尝试在sys.executable
文件中将/usr/bin/env python
设置为setup.py
,但这不起作用,因为shebang是#!"/usr/bin/env python"
,这显然很明显不起作用。
在这个问题中,我试着不要触摸我的shebang课程想法:Don't touch my shebang!(这是0票的底部答案)。这也没有用,可能是因为它是为distutils而不是setuptools编写的。再加上这个问题已经有6年了。
我也看了这些问题:
Setuptools entry_points/console_scripts have specific Python version in shebang
Changing console_script entry point interpreter for packaging
那里描述的方法不起作用,shebang线仍在改变。
使用内容::
创建setup.cfg
文件
[build]
executable = /usr/bin/env python
也不会改变shebang line mangling行为。
setuptools github页面上有一个开放的问题,讨论类似的事情:
https://github.com/pypa/setuptools/issues/494
所以我认为这不可能本地化,但我想知道是否有解决方法?
最后,我不喜欢任何涉及要求用户修改其安装标志的解决方案,例如:与-e
。
无论如何都要修改此行为,还是有其他我可以使用的分发系统?或者这是一个太多的边缘情况,我只需要编写某种自定义安装脚本?
谢谢大家。
我认为我原来的问题不够清楚,我希望用户能够做的是:
如果有办法在不阻止shebang重复的情况下实现这一点,那就太棒了。
我的所有代码已经与python 2.7和python 3.3+兼容,开箱即用,主要是让脚本运行而不管活动的python环境。
答案 0 :(得分:1)
我在尝试编写自定义安装脚本时偶然发现了一种解决方法。
import os
from setuptools import setup
from setuptools.command.install import install
here = os.path.abspath(os.path.dirname(__file__))
# Generate a list of python scripts
scpts = []
scpt_dir = os.listdir(os.path.join(here, 'bin'))
for scpt in scpt_dir:
scpts.append(os.path.join(here, 'bin', scpt))
class ScriptInstaller(install):
"""Install scripts directly."""
def run(self):
"""Wrapper for parent run."""
super(ScriptInstaller, self).run()
setup(
cmdclass={'install': ScriptInstaller},
scripts=scpts,
...
)
这段代码并没有完全符合我的要求(只改变了shebang系列),它实际上只是将整个脚本复制到~/.local/bin
,而不是将其包装在::
__import__('pkg_resources').run_script()
此外,更为关注的是,这个方法使setuptools创建了一个根模块目录以及一个像这样的egg-info目录::
.local/lib/python3.5/site-packages/cluster
.local/lib/python3.5/site-packages/python_cluster-0.6.1-py3.5.egg-info
而不是单个鸡蛋,这是通常的行为::
.local/lib/python3.5/site-packages/python_cluster-0.6.1-py3.5.egg
据我所知,这是旧的distutils的行为,这使我担心这个安装会在某些系统上失败或有其他意外的行为(虽然如果我错了请纠正我,我真的不是专家在此)。
但是,鉴于我的代码几乎完全用于Linux和OS X,这不是世界末日。我更担心的是,这种行为很快就会消失。
我在setuptools github页面上发布了对开放功能请求的评论:
https://github.com/pypa/setuptools/issues/494
理想的解决方案是,如果我可以向setup.cfg添加executable=/usr/bin/env python
语句,希望很快就会重新实现。
这种解决方法现在适用于我。谢谢大家。