当前位置: 首页 > 面试题库 >

cython嵌入后的ImportError

澹台华翰
2023-03-14
问题内容

我无法通过编译后的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"

问题答案:

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

尽管可以通过冻结py-modules并将所有c扩展名合并)到生成的可执行文件中来使Python插入器完全独立,但更容易为嵌入的插入器提供所需的安装。可以从python-
homepage(至少对于Windows)下载“标准”安装所需的文件。

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

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

这个答案适用于Linux和Python3(Python 3.7),基本思想与Windows / MacOS相同,但某些细节可能有所不同。

因为venv使用,所以有以下替代方法可以解决此问题:

  • 在pyx文件中以编程方式添加<..>/sometest/lib/python3.5/site-packagessometest是虚拟环境根文件夹)sys.path或通过PYTHONPATH在启动之前设置-environment变量来添加。
  • 将带有嵌入式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可以构建。

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

如果Py_NoSiteFlag未设置,Py_Initialize则将利用site.py(可以通过解释器找到它,因为sys.prefix是已知的)或更精确site.main()地将虚拟环境的站点包添加到中sys.path。这样做时,site.py查找pyvenv.cfg并解析它。但是,site- packages仅在以下情况下将local添加到python-path:

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

您的情况pyvenv.cfg不在上面的目录中,而是与exe相同-
因此,不包括通过pip安装库的本地站点软件包。不包含全局站点程序包,因为pyvenv.cfg具有key include-system-site- packages = false。因此,不允许使用站点包,也无法找到已安装的库。

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

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

答:可执行文件在某处,但不在虚拟环境中

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

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

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

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的前缀和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上方的本地住宅中以符号链接的形式显示。

C:在venv-environment内的两个可执行文件夹

venv如果pyvenv.cfg在搜索home(太远)时未读取文件A ,则在-
environment中向下移动两个文件夹(而不是在其中工作的文件夹)会导致’venv`-environments缺少指向“地标”的符号链接(仅本地)存在侧面包装),则第3步将失败,而第4步是唯一的希望。

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

  • 所需的文件被打包到lib\pythonX.Y\*嵌入可执行文件的旁边或上方(并且pyvenv.cfg周围没有混乱的搜索内容)。

  • pyvenv.cfg用于将口译员指向正确的位置。



 类似资料:
  • 准确说Cython是单独的一门语言,专门用来写在Python里面import用的扩展库。实际上Cython的语法基本上跟Python一致,而Cython有专门的&ldquo;编译器&rdquo;先将 Cython代码转变成C(自动加入了一大堆的C-Python API),然后使用C编译器编译出最终的Python可调用的模块。

  • 我们有一个spring boot(spring MVC)应用程序,在Apache SSL代理背后的专用appserver上嵌入了Tomcat。 代理服务器上的SSL端口为4433,转发到AppServer上的端口8080。 因此转发到代理服务器的URL如下所示: 在没有代理的情况下运行时,发生的第一件事是 spring安全重定向请求,如: 若要显示登录表单,请使用扩展 它在没有代理的情况下工作很好

  • 问题内容: 在Cython文档的教程中,有numpy模块的cimport和import语句: 我发现此约定在numpy / cython用户中非常流行。 这看起来很奇怪的我,因为他们 都 命名为 NP 。在代码的哪一部分中使用了导入/导入的np?为什么cython编译器不会混淆它们? 问题答案: 可以访问 C 函数或属性,甚至可以访问下面的子模块 可以访问下方的 Python 函数或属性或子模块。

  • 本文向大家介绍cython 包装DLL:从C ++到Cython到Python,包括了cython 包装DLL:从C ++到Cython到Python的使用技巧和注意事项,需要的朋友参考一下 示例 这展示了一个用Cython包装C ++ dll的简单例子。它将涵盖以下主要步骤: 使用Visual Studio使用C ++创建示例DLL。 用Cython包裹DLL,以便可以在Python中调用它。

  • 我正在寻找一个能够在Apache SSL代理后面运行Spring应用程序的解决方案。我尝试了很多配置都没有成功。所有的Spring响应都转到http,导致一个Not Found错误。 以下是apache配置: 以下是Spring选项: 我正在使用Spring启动2.5.6在阿帕奇雄猫/ 9.0.54。操作系统 Apache 是一个 2.4.25 版本,运行在 Debian 9.13 上。 问题似乎

  • 这是个无用的主意吗?