cython 嵌入后导入错误

2025-04-15 09:21:00
admin
原创
29
摘要:问题描述:我无法让已编译的 Python 脚本识别其他可用的模块。我需要如何更改以下流程才能接受基于 venv 或全局的模块?步骤:$ python3 -m venv sometest $ cd sometest $ . bin/activate (sometest) $ pip3 install PyCry...

问题描述:

我无法让已编译的 Python 脚本识别其他可用的模块。我需要如何更改以下流程才能接受基于 venv 或全局的模块?

步骤:

$ python3 -m venv sometest
$ cd sometest
$ . bin/activate
(sometest) $ pip3 install PyCrypto Cython

基本脚本,使用非标准模块Crypto

# hello.py
from Crypto.Cipher import AES
import base64
obj = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
msg = "The answer is no"
ciphertext = obj.encrypt(msg)
print(msg)
print(base64.b64encode(ciphertext))
(sometest) $ python3 hello.py
The answer is no
b'1oONZCFWVJKqYEEF4JuL8Q=='

编译它:

(sometest) $ cython -3 --embed hello.py
(sometest) $ gcc -Os -I /usr/include/python3.5m -o hello hello.c -lpython3.5m -lpthread -lm -lutil -ldl
(sometest) $ $ ./hello
Traceback (most recent call last):
  File "hello.py", line 1, in init hello
    from Crypto.Cipher import AES
ImportError: No module named 'Crypto'

我认为使用 cython 嵌入编译脚本中的 venv 没有问题:该脚本可以在系统中没有 venv 的其他地方运行(也就是说,python3 -c 'from Crypto.Cipher import AES'不会失败)。

否则,该过程运行正常:

(sometest) $ echo 'print("hello world")' > hello2.py
(sometest) $ cython -3 --embed hello2.py
(sometest) $ gcc -Os -I /usr/include/python3.5m -o hello2 hello2.c -lpython3.5m -lpthread -lm -lutil -ldl
(sometest) $ ./hello2
hello world

系统:

(sometest) $ python3 --version
Python 3.5.2
(sometest) $ pip3 freeze
Cython==0.29.11
pkg-resources==0.0.0
pycrypto==2.6.1

(sometest) $ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.6 LTS"

解决方案 1:

通常,Python 解释器不是“独立的”,为了工作,它需要其标准库(例如ctypes(编译)或(解释)),并且还必须设置site.py到其他站点包的路径(例如)。numpy

虽然可以通过冻结 py 模块并将所有 c 扩展(例如,参见此 SO-post)合并到生成的可执行文件中来使 Python 解释器完全独立,但为嵌入式解释器提供所需的安装更为容易。可以从 python-homepage 下载“标准”安装所需的文件(至少对于Windows 系统而言),另请参阅此SO- question。

有时,找到标准模块/站点包并不能立即使用:必须通过设置 Python 路径来帮助解释器,即通过以编程方式在 pyx 文件中添加<..>/sometest/lib/python3.5/site-packagessometest作为虚拟环境根文件夹)或在启动前设置环境变量。sys.path`PYTHONPATH`

请继续阅读以了解更多详细信息和替代解决方案。


这个答案针对的是Linux和Python3(Python 3.7),对于Windows / MacOS,基本思想是相同的,但一些细节可能有所不同。

因为venv使用了,所以我们有以下替代方法来解决这个问题:

  • 以编程方式在 pyx 文件中添加<..>/sometest/lib/python3.5/site-packagessometest作为虚拟环境根文件夹)或在启动之前设置环境变量。sys.path`PYTHONPATH`

  • 将嵌入 Python 的可执行文件放在子目录中sometest(例如bin或创建自己的子目录)。

  • 使用virtualenv而不是venv

注意:对于嵌入python的可执行文件,虚拟环境(或哪个)是否激活都不起作用。


为什么上述方法可以解决您场景中的问题?

问题是,(嵌入式)Python 解释器需要弄清楚以下内容在哪里:

  • 独立于平台的目录/文件,例如os.pyargparse.py几乎所有 .py/ .pyc)。给定sys.prefix,解释器可以确定在哪里找到它们(即在 中prefix/lib/pythonX.Y)。

  • 平台相关的目录/文件,例如共享库。假设sys.exec_prefix解释器能够找到它们(例如,可以在 中找到共享库exec_prefix/lib/pythonX.Y/lib-dynload)。

执行 时,可以在此处找到算法并执行搜索Py_Initialize。找到这些目录后,sys.path即可构建 。

但是,使用时, exe 旁边或父目录中venv有一个pyvenv.cfg-file ,可确保找到正确的 Python-Home - 一个好的起点是此文件中的 -key。home

如果Py_NoSiteFlag未设置 ,Py_Initialize则会利用(因为已知site.py,所以解释器可以找到它),或者更准确地说,将虚拟环境的 site-packages 添加到。在执行此操作时,会查找并解析它。但是,仅在以下情况下,本地文件才会添加到 python-path 中:sys.prefix`site.main()sys.pathsite.pypyvenv.cfgsite-packages`

如果名为“pyvenv.cfg”的文件存在于 sys.executable 上方的一个目录中,则 sys.prefix 和 sys.exec_prefix 将设置为该目录,并且还会检查站点包(sys.base_prefix 和 sys.base_exec_prefix 将始终是 Python 安装的“真实”前缀)。

在您的情况下pyvenv.cfg, 不在上述目录中,而是与 exe 文件位于同一目录中 - 因此,通过 pip 安装库的本地站点包未包含在内。全局站点包由于pyvenv.cfghas 键而不包含在内include-system-site-packages = false。因此,不允许使用站点包,并且找不到已安装的库。

但是,将 exe 向下移动一个目录会导致本地站点包被包含到路径中。


还可能存在其他情况,重要的是可执行文件的位置而不是激活了哪个环境。

答:可执行文件位于某个地方,但不在虚拟环境中

这种搜索启发式方法对于已安装的 python 解释器或多或少是可靠的,但对于嵌入式解释器或虚拟环境可能会失效(有关更多信息,请参阅此问题)。

如果使用通常或类似的方式安装了 python apt install,那么它将被找到(由于搜索算法中的第 4 步)并且嵌入式解释器将使用系统安装。

但是,如果文件被移动或者 python 是从源代码构建的但未安装,则嵌入式解释器无法启动:

Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Fatal Python error: initfsencoding: unable to load the file system codec
ModuleNotFoundError: No module named 'encodings'

在这种情况下,Py_SetPythonHome或者设置环境变量$PYTHONHOME是可能的解决方案。

B:可在使用 virtualenv 创建的虚拟环境中执行

假设虚拟环境和嵌入式 Python 的 Python 版本相同(否则会出现上述情况),嵌入式 exe 将使用本地侧包。主目录搜索算法总是会找到本地主目录,原因如下:

步骤 3. 尝试查找相对于 argv0_path 的 prefix 和 exec_prefix,并沿路径回溯直至遍历完毕。这是最常见的成功步骤。请注意,如果 prefix 和 exec_prefix 不同,则更有可能找到 exec_prefix;但是,如果 exec_prefix 是 prefix 的子目录,则两者都会找到。

在这种情况下 argv0_path是 exe 的路径(没有pyvenv.cfg文件!),并且会找到“地标”(lib/python$VERSION/os.py 和 lib/python$VERSION/lib-dynload),因为它们在 exe 上方的 local-home 中显示为符号链接。

C:可执行文件位于venv环境深处的两个文件夹中

在 -environment中向下移动两个文件夹而不是一个文件夹(它可以工作)venv会导致情况 A:pyvenv.cfg在搜索 home(太靠上)时未读取文件,'venv'-environments 缺少指向“landmarkers”的符号链接(本地仅存在 side-packages),因此步骤 3 将失败,步骤 4是唯一的希望。


推论:如果没有正确安装 Python,嵌入式 Python 将无法工作,除非有其他可能性:

  • 所需的文件被打包到libpythonX.Y*嵌入可执行文件的旁边或上面的某个地方(并且不会pyvenv.cfg弄乱搜索)。

  • pyvenv.cfg用于将解释器指向正确的位置。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用