Python运行时的可选动态依赖

4
我正在构建一个复杂的Python应用程序,以最大化支持不同的库为目标,其中一些是使用几个千兆字节的机器学习库。我现在准备发布这个项目,但我意识到构建大小非常庞大,其中99%不是我的代码,而且其中一些可能永远不会被用户调用。
我希望能够让用户下载一个具有最小依赖关系的发布版本,如果他们选择在GUI中使用其他依赖关系,可以在运行时提示并安装它们,甚至可以使用pyinstaller重新构建应用程序。
我并不期望所有的用户都是开发人员,所以只有一个可配置的构建脚本并不是最好的选择,而且我也不想发布多个版本。
我描述的这种情况在Python中是否可行,是否是一种常见的模式?我应该如何实现这样的功能?
如果这个问题更适合在软件工程堆栈交流,我可以将它转移到那里。
编辑: 我的一些软件包只适用于Linux或Windows。我想将我的项目发布为一个可移植的可执行文件,类似于PyInstaller。我不希望我的用户需要理解如何管理venv或系统Python版本。我可以理解制作另一个软件,通过安装和构建程序来管理自己的Python版本、venv和可执行文件,就像安装的系统软件包一样。这样一个复杂而繁琐的解决方案是否有必要来处理这个问题?

2
你正在寻找使用extras_require来添加可选依赖项。请参考https://stackoverflow.com/search?q=%5Bsetuptools%5D+optional+dependencies。 - undefined
1
那么在这里使用pip是错误的标签。pip/setuptools无法做到这一点,您需要编写自己的安装程序。 - undefined
@phd 哎呀,好吧,听起来有点吓人,我在想是否已经有任何既定的软件包/做法来处理这种行为了。 - undefined
1
很抱歉,这并不适用于Python的世界。 - undefined
如果您不打算分发Python源代码,那么PyInstaller只是一种贫穷人的保护措施。但是,如果您不介意分发源代码,您可以将Python环境压缩为您的软件包,并制作自己的安装程序,将一个启动主程序的脚本添加到路径中。然后,pip也会被包含在内,您可以以编程方式调用它来安装(甚至卸载)其他包。 您无法避免为每个操作系统制作一个软件包。 - undefined
显示剩余5条评论
4个回答

1

用Python可以实现你所描述的功能,这实际上是软件开发中常见的模式,被称为“懒加载”或“动态依赖”。它允许你推迟安装和加载某些依赖,直到用户实际需要它们。

  • 你可以使用Python内置的importlib模块,该模块提供了在运行时以编程方式导入模块的函数。
  • 确定你想要包含在应用程序中但默认情况下不提供的可选依赖项。这些库对于应用程序的核心功能并非必需。
  • 修改你的代码,使用动态导入来处理这些可选依赖项,例如:
import importlib

def use_optional_library():
    try:
        optional_lib = importlib.import_module('optional_lib')
        # Use the optional library here
    except ImportError:
        # Handle the case when the library is not available
        pass

在你的GUI中,提供一种让用户“启用”或“禁用”这些可选库的方式。当用户选择启用特定库时,你可以调用相应的函数,使用`importlib.import_module()`来动态加载库。
为了处理可选依赖的安装,你可以使用像`pip`或`conda`这样的软件包管理器,或者像`pipenv`或`poetry`这样的库。
你可以使用`subprocess`模块以编程方式执行软件包管理器命令。
如果你想将应用程序作为可便携的可执行文件分发,你可以使用`PyInstaller`,将可选库作为数据文件而不是直接依赖项包含在其中。这样,它们不会默认地与可执行文件捆绑在一起,但如果用户选择启用它们,你可以在运行时动态加载它们。
这种方法给你的代码库增加了一些复杂性,但它可以为用户提供更灵活和可定制的体验,而不会使初始下载大小变得庞大。

0
大多数机器学习模型可以在不安装完整的机器学习框架的情况下进行推理。没有一种通用的方法来最小化或缩小分发范围,以仅包括有用的模块(无法在运行时了解所有可能的流程和文件,以及模型将使用和包含的那些模块)。您可以尝试创建一个简约的运行时,仅使用您的模型和其他应用逻辑进行推理。例如,尝试使用mlflow-skinny或onyx运行时,看看是否可以减小分发大小。如果没有效果,您可能需要深入挖掘并实现一些模块来自行进行推理,以避免庞大的分发。

-1
在客户端上运行应用程序时,动态安装依赖项是一个多步骤的任务,它严重依赖于您计划如何运行应用程序。虽然我不知道有任何已知的库可以解决这个一般性的任务,但您可以实现自己的解决方案。
  1. 如果您的分发依赖于使用pip进行安装,最简单的解决方案是使用subprocess从应用程序内部调用pip并下载依赖项。

  2. 如果您的分发使用类似PyInstaller的工具,那么它已经捆绑了一个Python解释器,但通常没有pip包。一个解决方案是使用urllib下载依赖项,并使其对该解释器可用,例如通过将下载的文件夹位置追加到sys.path或按照捆绑工具的说明将文件夹放置在特定位置。


3
因为Python的setuptools已经内置了extras_require,可以让用户通过pip install package[extra]来安装额外的依赖项,所以我不同意这种方式。通过上述建议的方式来下载外部依赖库听起来像是一个巨大的安全隐患,通常难以维护,最糟糕的是,这会破坏与最终用户的信任关系。 - undefined
@felipe OP说,她并不指望所有的用户都对终端感兴趣。此外,捆绑器不会在捆绑包中包含pip,因此如果客户端没有安装python,就必须先下载pip,这也会带来同样的问题。 - undefined
@felipe 这会有什么安全风险吗?我的应用程序是完全开源的,我只是希望能够为了可访问性的原因分发一些小型二进制文件,并且我想通过图形界面以编程方式控制 venv 包。我立即注意到的唯一缺点是,PyInstaller 构建的项目比 venv(约 8GB)要小得多(但仍然有几个 GB),如果用户可以下载并重新构建二进制文件,那可能是最理想的情况。 - undefined

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接