setup.py 中的条件要求

Conditional requirements in setup.py

我正在编写一个 library that's dependent on file-magic, which works just fine for most platforms, but in Alpine Linux, file-magic won't work so I need to instead use the python-magic 库。

现在我知道如何编写自己的代码来处理不同的 Python 库 API,但我不知道如何编写我的 setup.cfgsetup.py 根据我们进行安装的系统有不同的要求。

我认为最好的选择是使用 PEP 508 规则,但我不知道如何说 "libmagic like Alpine" 或该语法中的其他内容,更不用说它是否适用于一个包的 setup.py。事实上,如果不安装 file-magic 并看着它死掉,我什至无法弄清楚如何分辨架构之间的区别:-(

当然,对于这种事情一定有最佳实践吗?

更新

在从下面的 Tim 那里获得了更广泛的理解之后,我拼凑了这个 hack 来让它工作:

def get_requirements():
    """
    Alpine is problematic in how it doesn't play nice with file-magic -- a
    module that appears to be the standard for most other Linux distros.  As a
    work-around for this, we swap out file-magic for python-magic in the Alpine
    case.
    """

    config = configparser.ConfigParser()
    config.read("setup.cfg")
    requirements = config["options"]["install_requires"].split()

    os_id = None
    try:
        with open("/etc/os-release") as f:
            os_id = [_ for _ in f.readlines() if _.startswith("ID=")][0] \
                .strip() \
                .replace("ID=", "")
    except (FileNotFoundError, OSError, IndexError):
        pass

    if os_id == "alpine":
        requirements[1] = "python-magic>=0.4.15"

    return requirements


setuptools.setup(install_requires=get_requirements())

这允许使用 setup.cfg 的声明性语法,但如果安装目标是 Alpine 系统,则会调整 install_requires 值。

您可能想使用 platform module 来尝试识别系统详细信息。

最好的办法是尝试使用 platform.architecture()platform.platform()platform.system() 的组合,并适当地处理错误并考虑所有可能的 return 信息。

示例:

我在 Win10 上 运行,这是这些函数的输出(还有一个):

>>> import platform
>>> print(platform.architecture())
('32bit', 'WindowsPE')
>>> print(platform.platform())
Windows-10-10.0.17134-SP0
>>> print(platform.processor())
Intel64 Family 6 Model 142 Stepping 10, GenuineIntel
>>> print(platform.system())
Windows

编辑

以上答案不一定return您想要的信息(我没有提及平台模块中任何已弃用的功能)。

深入挖掘,得到 this SO result,这说明用于收集发行版名称的内置平台功能已被弃用。

官方文档指向一个名为 distro 的 PyPi 包。 PyPi 上的发行版文档承认需要此类信息,并且在那里找到的示例用法如下所示:

>>> import distro
>>> distro.linux_distribution(full_distribution_name=False)
('centos', '7.1.1503', 'Core')