相对导入问题和 Python 3
Problems with relative import and Python 3
首先,我需要描述一下我写作的环境。我正在编写 Python 代码,这些代码将由 CAD 应用程序中的 Python 运行时 运行 加载和执行。 CAD 应用程序使用 Python 作为其脚本引擎。因此,我无法访问 Python 运行时,作为所有其他脚本的好公民,我不应该修改任何系统设置。我的脚本只是加载的众多脚本之一 运行.
这一切都很好,除非我想使用非标准库。在那种情况下,我需要安装库的本地副本以便我的脚本访问。我遇到的问题是大多数库都希望安装并添加到 sys 路径,这是我不应该做的事情,因为它可能会与其他脚本正在做的事情产生冲突。我试图做的是设置库的本地副本,然后编辑它们的源代码,以便它们的导入是相对的,并且它们不依赖于 sys 路径。这样我的程序将拥有自己的库本地副本,而不依赖于任何其他内容,也不会干扰任何其他脚本。
我正在使用 PIP 的 -t 选项将 Requests 和 PyOpenSSL 安装到脚本文件夹中的 "Packages" 子文件夹中。这是我所拥有的一个简短列表。
RequestsTest/
RequestsTest.py
Packages/
OpenSSL/
cryptography/
x509/
__init__.py
base.py
hazmat/
__init__.py
backends/
__init__.py
interfaces.py
openssl/
__init__.py
backend.py
x509.py
OpenSSL/
__init__.py
SSL.py
Requests/
chardet/
__init__.py
requests/
__init__.py
urllib3/
__init__.py
request.py
contrib/
__init__.py
pyopenssl.py
util/
__init__.py
request.py
ssl_.py
虽然跟踪各种导入语句并使其成为相对的是乏味的,但它似乎确实有效。但是,我在处理一组特定的导入时遇到了问题。
在 Packages/Requests/urllib3/contrib/pyopenssl.py 中,它包含以下我已修改的导入:
from ....OpenSSL.OpenSSL import SSL
from ....OpenSSL.cryptography import x509
他们原来是:
from OpenSSL import OpenSSL.SSL
from cryptography import x509
第一行错误 "ImportError: No module named 'OpenSSL'",第二行错误 "ImportError: No module named 'cryptography'"。我相当确定路径是正确的,因为如果我更改点数,我会得到 no module named 错误,但它列出了它试图加载的完整路径,而不仅仅是模块的名称。
对于这个特定问题,我希望得到一些帮助,但也可以使用一些关于如何设置和使用库的私有副本的总体建议。请记住,我的程序只是系统正在加载的众多程序之一,更改系统或设置虚拟环境不是一种选择。
查看 localimport 模块,它似乎是针对您的特定用例的解决方案。来自自述文件:
Given your Python script, application or plugin comes with a directory that contains modules for import, you can use localimport to keep the global importer state clean.
app.py
res/modules/
some_package/
__init__.py
# app.py
with localimport('res/modules') as _importer:
import some_package
assert 'some_package' not in sys.modules
标语是 "Isolated import of Python Modules for embedded applications." 所以它看起来很相关。
使用该模块时,以下内容可能有助于保持整洁:
- 将您的实际脚本逻辑放入其自己的文件中。
- 有一个包装器脚本(这将由 CAD 软件加载),它按照 README 中所述执行
localimport
,然后对您的模块进行相对导入。如果您的模块足够大,可以将其放入自己的包中并以与其他所有内容相同的方式使用它(只需在 with localimport(): ...
. 的正文中执行 from RequestsTest import *
- 尝试在您编写的源代码与在 CAD Python 运行时上下文中使用该源代码所需的最终组织文件集之间划清界限。可以有一个 build/packaging 步骤来创建
localimport
脚本,下载所需的包等。甚至更好,因为它是自动化的,而不是将来有人可能手动完成的事情必须重新创建。
首先,我需要描述一下我写作的环境。我正在编写 Python 代码,这些代码将由 CAD 应用程序中的 Python 运行时 运行 加载和执行。 CAD 应用程序使用 Python 作为其脚本引擎。因此,我无法访问 Python 运行时,作为所有其他脚本的好公民,我不应该修改任何系统设置。我的脚本只是加载的众多脚本之一 运行.
这一切都很好,除非我想使用非标准库。在那种情况下,我需要安装库的本地副本以便我的脚本访问。我遇到的问题是大多数库都希望安装并添加到 sys 路径,这是我不应该做的事情,因为它可能会与其他脚本正在做的事情产生冲突。我试图做的是设置库的本地副本,然后编辑它们的源代码,以便它们的导入是相对的,并且它们不依赖于 sys 路径。这样我的程序将拥有自己的库本地副本,而不依赖于任何其他内容,也不会干扰任何其他脚本。
我正在使用 PIP 的 -t 选项将 Requests 和 PyOpenSSL 安装到脚本文件夹中的 "Packages" 子文件夹中。这是我所拥有的一个简短列表。
RequestsTest/
RequestsTest.py
Packages/
OpenSSL/
cryptography/
x509/
__init__.py
base.py
hazmat/
__init__.py
backends/
__init__.py
interfaces.py
openssl/
__init__.py
backend.py
x509.py
OpenSSL/
__init__.py
SSL.py
Requests/
chardet/
__init__.py
requests/
__init__.py
urllib3/
__init__.py
request.py
contrib/
__init__.py
pyopenssl.py
util/
__init__.py
request.py
ssl_.py
虽然跟踪各种导入语句并使其成为相对的是乏味的,但它似乎确实有效。但是,我在处理一组特定的导入时遇到了问题。
在 Packages/Requests/urllib3/contrib/pyopenssl.py 中,它包含以下我已修改的导入:
from ....OpenSSL.OpenSSL import SSL
from ....OpenSSL.cryptography import x509
他们原来是:
from OpenSSL import OpenSSL.SSL
from cryptography import x509
第一行错误 "ImportError: No module named 'OpenSSL'",第二行错误 "ImportError: No module named 'cryptography'"。我相当确定路径是正确的,因为如果我更改点数,我会得到 no module named 错误,但它列出了它试图加载的完整路径,而不仅仅是模块的名称。
对于这个特定问题,我希望得到一些帮助,但也可以使用一些关于如何设置和使用库的私有副本的总体建议。请记住,我的程序只是系统正在加载的众多程序之一,更改系统或设置虚拟环境不是一种选择。
查看 localimport 模块,它似乎是针对您的特定用例的解决方案。来自自述文件:
Given your Python script, application or plugin comes with a directory that contains modules for import, you can use localimport to keep the global importer state clean.
app.py res/modules/ some_package/ __init__.py # app.py with localimport('res/modules') as _importer: import some_package assert 'some_package' not in sys.modules
标语是 "Isolated import of Python Modules for embedded applications." 所以它看起来很相关。
使用该模块时,以下内容可能有助于保持整洁:
- 将您的实际脚本逻辑放入其自己的文件中。
- 有一个包装器脚本(这将由 CAD 软件加载),它按照 README 中所述执行
localimport
,然后对您的模块进行相对导入。如果您的模块足够大,可以将其放入自己的包中并以与其他所有内容相同的方式使用它(只需在with localimport(): ...
. 的正文中执行 - 尝试在您编写的源代码与在 CAD Python 运行时上下文中使用该源代码所需的最终组织文件集之间划清界限。可以有一个 build/packaging 步骤来创建
localimport
脚本,下载所需的包等。甚至更好,因为它是自动化的,而不是将来有人可能手动完成的事情必须重新创建。
from RequestsTest import *