相对导入和Python 3的问题

时间:2019-01-03 19:07:51

标签: python python-import importerror

首先,我需要描述我正在编写的环境。我正在编写将由在CAD应用程序中运行的Python运行时加载并执行的Python代码。 CAD应用程序使用Python作为其脚本引擎。结果,我无权访问Python运行时,并且作为所有其他脚本的好公民,不应修改任何系统设置。我的脚本只是已加载并正在运行的众多脚本之一。

除了我要使用非标准库时,所有这些都工作正常。在这种情况下,我需要安装库的本地副本以供脚本访问。我遇到的问题是,大多数库都希望安装并添加到sys路径,这是我不应该做的事情,因为它可能与其他脚本在做的事情产生冲突。我要尝试执行的操作是设置库的本地副本,然后编辑它们的源,以便它们的导入是相对的,并且它们不依赖于sys路径。这样,我的程序将拥有自己的库的本地副本,而不依赖于其他任何东西,并且不会干扰任何其他脚本。

我正在使用PIP的-t选项将请求和PyOpenSSL安装到脚本文件夹中的“包”子文件夹中。这是我所拥有的简短清单。

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

尽管跟踪各种import语句并使其相对很繁琐,但这似乎确实有效。但是,我在一组特定的导入中遇到了问题。

在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:没有名为'OpenSSL'的模块”,第二行出现了“ ImportError:没有名为'cryptography'的模块”。我相当确定该路径是正确的,因为如果更改点数,则会得到名为error的no模块,但它会列出其尝试加载内容的完整路径,而不仅仅是模块名称。

我希望在此特定问题上有所帮助,但也可以使用一些有关如何设置和使用库的私有副本的总体建议。请记住,我的程序只是系统正在加载的许多程序之一,无法更改系统或设置虚拟环境。

1 个答案:

答案 0 :(得分:2)

签出localimport模块,这似乎是您特定用例的解决方案。从自述文件:

  

鉴于您的Python脚本,应用程序或插件带有一个包含要导入模块的目录,您可以使用localimport保持全局导入器状态的清洁。

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

标语是“为嵌入式应用程序单独导入Python模块”。所以看起来很相关。

使用该模块时,以下内容可能有助于保持整洁:

  1. 将实际的脚本逻辑放入自己的文件中。
  2. 具有一个包装器脚本(将由CAD软件加载),如自述文件所述执行localimport,然后对模块进行相对导入。如果您的模块足够大,则可以将其放入自己的包中,并以与其他所有组件相同的方式使用它(只需在from RequestsTest import *的正文中执行with localimport(): ...
  3. 尝试在您编写的源代码和在CAD Python运行时环境下使用该源代码所需的最终文件整理结构之间有清晰的界限。可以有一个构建/打包步骤来创建localimport脚本,下载所需的包,等等。这样做更好,因为这样做是自动化的,而不是将来某人可能需要手动完成的操作重新创建。