覆盖python setuptools

时间:2016-06-17 06:18:35

标签: python linux setuptools

背景

我为一个使用模块(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

无论如何都要修改此行为,还是有其他我可以使用的分发系统?或者这是一个太多的边缘情况,我只需要编写某种自定义安装脚本?

谢谢大家。

更新

我认为我原来的问题不够清楚,我希望用户能够做的是:

  • 在python2和python3中安装软件包(模块将进入lib / pythonx / site-lib。
  • 无论哪个python环境处于活动状态,都能够运行脚本

如果有办法在不阻止shebang重复的情况下实现这一点,那就太棒了。

我的所有代码已经与python 2.7和python 3.3+兼容,开箱即用,主要是让脚本运行而不管活动的python环境。

1 个答案:

答案 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语句,希望很快就会重新实现。

这种解决方法现在适用于我。谢谢大家。