【问题标题】:Install by default, "optional" dependencies in Python (setuptools)默认情况下,在 Python 中安装“可选”依赖项(setuptools)
【发布时间】:2019-04-21 21:38:16
【问题描述】:

有没有办法为 Python 包指定可选依赖项,该依赖项应该默认安装来自pip,但如果无法安装则不应将其视为失败?

我知道我可以指定 install_requires 以便为 90% 使用可以轻松安装某些可选依赖项的操作系统的用户安装软件包,我也知道我可以指定 extra_require 来指定用户可以声明他们想要完整安装来获得这些功能,但我还没有找到一种方法来设置默认的 pip 安装尝试安装这些包,但如果无法安装它们也不会抱怨。

(我想更新 setuptoolssetup.py 的特定软件包称为 music21,其中 95% 的工具可以在没有 matplotlib、IPython、scipy、pygame 和一些不起眼的音频工具的情况下运行等等,但是如果安装了这些包,包会获得额外的能力和速度,我更愿意让人们默认拥有这些能力,但如果无法安装则不报告错误)

【问题讨论】:

    标签: python pip setuptools music21


    【解决方案1】:

    无论如何都不是一个完美的解决方案,但您可以设置一个安装后脚本来尝试安装软件包,如下所示:

    from distutils.core import setup
    from distutils import debug
    
    
    from setuptools.command.install import install
    class PostInstallExtrasInstaller(install):
        extras_install_by_default = ['matplotlib', 'nothing']
    
        @classmethod
        def pip_main(cls, *args, **kwargs):
            def pip_main(*args, **kwargs):
                raise Exception('No pip module found')
            try:
                from pip import main as pip_main
            except ImportError:
                from pip._internal import main as pip_main
    
            ret = pip_main(*args, **kwargs)
            if ret:
                raise Exception(f'Exitcode {ret}')
            return ret
    
        def run(self):
            for extra in self.extras_install_by_default:
                try:
                    self.pip_main(['install', extra])
                except Exception as E:
                    print(f'Optional package {extra} not installed: {E}')
                else:
                    print(f"Optional package {extra} installed")
            return install.run(self)
    
    
    setup(
        name='python-package-ignore-extra-dep-failures',
        version='0.1dev',
        packages=['somewhat',],
        license='Creative Commons Attribution-Noncommercial-Share Alike license',
        install_requires=['requests',],
        extras_require={
            'extras': PostInstallExtrasInstaller.extras_install_by_default,
        },
        cmdclass={
            'install': PostInstallExtrasInstaller,
        },
    )
    

    【讨论】:

    • 这似乎是一个我没有想到的好主意。如果没有更简单的事情出现,就值得赏金。
    • 请注意,安装后的命令对于pip 是无用的,除非您明确指示您的用户通过pip install pkgname --no-binary=pkgname 进行安装。这仅在直接调用 python setup.py install 时有效。
    • 请不要推荐用户导入pip:它是一个命令行工具,不支持任何可导入的API。这样做会导致用户崩溃和困惑,并且当pip 开发人员需要在内部移动内容时会头疼(因此您的try/except - pip._internal 模块表明这是pip 内部的并且不应被导入。)
    【解决方案2】:

    执行此操作的最简单方法是添加自定义安装命令,该命令简单地向 pip 安装“可选”包。在你的setup.py:

    import sys
    import subprocess
    from setuptools import setup
    from setuptools.command.install import install
    
    class MyInstall(install):
        def run(self):
            subprocess.call([sys.executable, "-m", "pip", "install", "whatever"])
            install.run(self)
    
    setup(
        ...
    
        cmdclass={
            'install': MyInstall,
        },
    )
    

    就像上面提到的hoefling 一样,这只有在您发布源分发版(.tar.gz.zip)时才有效。如果您将包发布为内置发行版 (.whl),它将无法正常工作。

    【讨论】:

      【解决方案3】:

      这可能是您正在寻找的。它似乎是设置工具的内置功能,允许您声明“可选依赖项”。

      https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#optional-dependencies

      setup(
          name="Project-A",
          ...
          extras_require={
              'PDF':  ["ReportLab>=1.2", "RXP"],
              'reST': ["docutils>=0.3"],
          }
      )
      

      【讨论】:

      • 这些不幸的是默认情况下不安装。它们是高级用户决定安装什么的好方法,但对大多数用户没有帮助。
      猜你喜欢
      • 2021-02-24
      • 1970-01-01
      • 2014-10-02
      • 2019-02-11
      • 2013-08-30
      • 2015-06-28
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多