【问题标题】:pyinstaller onefile but still import external library if availablepyinstaller onefile,但如果可用,仍会导入外部库
【发布时间】:2019-06-13 03:17:41
【问题描述】:

我正在使用“pyinstaller --onefile myapp.py”打包一个 python 应用程序,它会创建一个可执行文件,并且该应用程序运行良好。现在我希望能够从系统中导入一个模块(如果存在),否则使用单个可执行文件中的捆绑模块。如果安装了 PySide2,我特别想从系统导入 PySide2,理想情况下,它带有一个可配置的标志,指示应用程序是从系统加载还是从单个可执行文件加载。我已经在使用由单个可执行文件读取的配置文件,因此我可以在其中放置一个标志来指示如何加载模块。有没有办法做到这一点?

伪代码是这样的:

read import_external from configuration file
if import_external is true:
    try:
        import PySide2 from system
    except:
        import PySide2 from executable

编辑我正在接近解决方案。我可以从 pyinstaller onefile 可执行文件中动态导入单个 Python 文件,如下面的代码所示,我使用简单的打印语句创建了一个虚拟“PySide2.py”文件来验证它是否已导入。

import os
print("Import test")
if os.path.isfile('./PySide2.py'):
    print('Importing local PySide2')
    import importlib
    import importlib.util
    spec = importlib.util.spec_from_file_location('PySide2', './PySide2.py')
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
else:
    print('Importing system PySide2')
    import PySide2
    print(PySide2.__version__)
print("Import complete")

但是 PySide2 不是单个文件,所以现在我需要了解如何从目录导入。任何建议表示赞赏!

EDIT 2我在这里找到了解决方案:Python use importlib to import a module from a package directory

【问题讨论】:

  • PyInstaller 安装自己的 Python 解释器,如果有的话,它与已经安装的解释器是分开的。我认为你不能(或者你不应该)尝试从另一个 Python 安装中导入包。
  • 感谢您指出单独的解释器。我没有想到这一点。不如先搜索本地目录看看是否可以从那里导入?用户必须注意版本是否兼容。
  • 如果你必须这样做,你应该看看importlib
  • 我不确定你为什么要这样做,因为 pyinstaller 的目的是将 py 文件转换为 exe。但是,如果您想在运行时导入外部模块(指出 Python 已安装在目标机器上),为什么要首先使用 pyinstaller?只需使用您的脚本。
  • 我之所以这样做是为了遵守 PySide2 的 LGPL 许可。据我了解,使用 LGPL 库的作品必须分发源代码或使最终用户能够用不同的库替换 LGPL 库(他们有责任确保与API/函数调用/等)。如果我用 pyinstaller 创建了一个封闭的包,那么最终用户没有办法换掉 PySide2,这似乎违反了许可。

标签: python import module pyinstaller


【解决方案1】:

经过更多研究和发布,我得到了以下解决方案(来自this post)。

import os, sys
if os.path.isdir('./PySide2/'):
    print('Importing local PySide2')
    import importlib.util

    MODULE_PATH = "./PySide2/__init__.py"
    MODULE_NAME = "PySide2"

    spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
    PySide2 = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = PySide2
    spec.loader.exec_module(PySide2)

    print(PySide2.__version__)
else:
    print('Importing system PySide2')
    import PySide2
    print(PySide2.__version__)

【讨论】:

  • 解决方案的后续问题 - 如何在 myapp.py 中使用子模块(QtWidgets 等)?
猜你喜欢
  • 2016-12-14
  • 2013-10-04
  • 2014-12-22
  • 1970-01-01
  • 2014-06-16
  • 2020-12-17
  • 1970-01-01
  • 1970-01-01
  • 2017-11-04
相关资源
最近更新 更多