简体   繁体   English

三路 Python 导入链导致 ModuleNotFoundError 或 ImportError

[英]Three-way Python import chain results in ModuleNotFoundError or ImportError

Consider a project structure --考虑一个项目结构——

\root
    __init__.py
    bar.py
    \package1
        __init__.py
        abstractFoo.py
        implementedFoo.py
   

And a few file definitions for context --还有一些上下文的文件定义——

  • bar.py: project's primary functionality bar.py:项目的主要功能
  • abstractFoo.py: defines Foo abstractFoo.py:定义 Foo
  • implementedFoo.py: implements Foo (numerous of these files exist under package1 corresponding to distinct implementations of Foo) implementsFoo.py:实现 Foo (在 package1 下存在许多这些文件,对应于 Foo 的不同实现)

Lastly, the imports --最后,进口——

  • bar.py imports helper functions from abstractFoo.py (ie from package1.abstractFoo import validateFoo, loadFoo ...); bar.py 从 abstractFoo.py 导入辅助函数(即从 package1.abstractFoo import validateFoo, loadFoo ...); bar.py leverages said helper functions to import various implementedFoo.py on-demand bar.py 利用上述辅助函数按需导入各种implementedFoo.py
  • implementedFoo.py imports abstract classes from abstractFoo.py (see below for attempts) implementedFoo.py 从 abstractFoo.py 导入抽象类(见下文尝试)
  • abstractFoo.py imports nothing abstractFoo.py 什么都不进口

The clash occurs in bar.py, when trying to import implementedFoo.py on-demand, specifically when implementedFoo.py itself tries importing from abstractFoo.py.冲突发生在 bar.py 中,当尝试按需导入implementedFoo.py 时,特别是当implementedFoo.py 本身尝试从abstractFoo.py 导入时。

It seems both relative (eg implementedFoo.py: from . import abstractFoo) and absolute (eg implementedFoo.py: from root.package1 import abstractFoo) imports fail as they are no longer "correct" from the vantage point of bar.py at runtime.似乎相对(例如implementedFoo.py:from .import abstractFoo)和绝对(例如implementedFoo.py:from root.package1 import abstractFoo)导入都失败了,因为从bar.py的有利位置在运行时它们不再“正确” .

Note I am running Python 3.10.x.注意我正在运行 Python 3.10.x。 Please let me know if I can provide any additional information.如果我可以提供任何其他信息,请告诉我。 I am appending below a sample error...我在下面附加一个示例错误...

In [2]: Source('bloomberg')
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-2-c290b4e239b8> in <cell line: 1>()
----> 1 Foo('Foo')

<ipython-input-1-a0ec8d9f6e48> in __init__(self, Foo_name)
     85     def __init__(self, name: str):
     86         self.Foo_name = Foo_name
---> 87         self.Foo = package1.abstractFoo.load_Foo(self._Foo_path(self.Foo_name))
     88
     89     def read(self, s: str):

path\to\root\package1\abstractFoo.py in load_Foo(Foo_path)
     33     foo = importlib.util.module_from_spec(spec)
     34     sys.modules['foo'] = foo
---> 35     spec.loader.exec_module(foo)
     36     return foo

C:\Python310\lib\importlib\_bootstrap_external.py in exec_module(self, module)

C:\Python310\lib\importlib\_bootstrap.py in _call_with_frames_removed(f, *args, **kwds)

path\to\root\package1\implementedFoo.py in <module>
----> 3 import abstractFoo
      4 from typing import Optional, Union
      5 from datetime import date, datetime

ModuleNotFoundError: No module named 'abstractFoo'

Thank you in advance.先感谢您。

Creating a subpackage directory subpackage1 under package1,and placing abstractFoo in subpackage1 allows me to accomplish what I'm looking for via absolute imports.在 package1 下创建一个子包目录 subpackage1,并将 abstractFoo 放在 subpackage1 中允许我通过绝对导入来完成我正在寻找的东西。 I would probably have been content with this solution if I'd come across it before posting this question, but still open for any enhancements/alternatives.如果在发布此问题之前遇到此解决方案,我可能会对此解决方案感到满意,但仍对任何增强/替代方案持开放态度。

For some additional context on why the structure is so convoluted: root is a database folder, bar is the database driver, abstractFoo abstracts as much as possible from pulling data via third party sources, and implementedFoo files are created on a 1:1 basis against third parties, each implementing common functions and returning data in a common format for database consumption.关于为什么结构如此复杂的一些额外上下文:root 是数据库文件夹,bar 是数据库驱动程序,abstractFoo 尽可能从通过第三方来源提取数据进行抽象,并且以 1:1 的方式创建implementedFoo 文件第三方,每个都实现通用功能并以通用格式返回数据以供数据库使用。 The database driver (bar) and API implementations (implementedFoo) must both import abstract classes and/or helper functions from abstractFoo.数据库驱动程序 (bar) 和 API 实现 (implementedFoo) 都必须从 abstractFoo 导入抽象类和/或辅助函数。 Upstream (ie beyond the root folder), only bar.py (or the root folder itself, TBD) will be imported to handle database i/o back-end.上游(即超出根文件夹),只会导入 bar.py(或根文件夹本身,待定)来处理数据库 i/o 后端。

You could use my new, experimental import library ultraimport and rather use relative imports你可以使用我的新的、实验性的导入库ultraimport ,而不是使用相对导入

In implementedFoo.py you would then write:在implementedFoo.py中,你会写:

import ultraimport
abstractFoo = ultraimport('__dir__/abstractFoo.py')

This import will always work, no matter how you run your script or what is your current working directory.无论您如何运行脚本或当前工作目录是什么,此导入都将始终有效。 You also don't need to create a new directory.您也不需要创建新目录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM