解决动态加载模块的Python代码审查错误。

huangapple go评论67阅读模式
英文:

Resolve Python linting errors for dynamically loaded modules

问题

考虑以下使用嵌套模块的项目结构:

$ tree
.
├── a
│   ├── b
│   │   ├── c
│   │   │   └── __init__.py
│   │   └── __init__.py
│   └── __init__.py
└── test.py

3 directories, 4 files

test.py 文件的内容如下:

from a.b.c import foo

print(foo())

a/b/c/__init__.py 文件的内容如下:

def foo():
    return "Hello world"

我想在导入时省略 b,在 test.py 中使用 from a.c import foo。这是因为我想在内部将代码组织在单独的子目录中,同时允许根目录中的文件使用相同的基本导入路径导入所有内容。我可以通过将以下代码添加到 a/__init__.py 来实现这一目标:

import importlib
import sys

importlib.import_module("a.b.c")
sys.modules["a.c"] = sys.modules["a.b.c"]

这样做确实有效,当我在其中的 test.py 中使用 from a.c import foo 调用 python test.py 时,我可以看到预期的 Hello world 输出。然而,各种 Python 工具和代码检查工具都不喜欢这种做法。如果我尝试在 test.py 上运行 pylint,它会报告导入错误:

$ pylint test.py
************* Module test
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
test.py:1:0: E0401: Unable to import 'a.c' (import-error)
test.py:1:0: E0611: No name 'c' in module 'a' (no-name-in-module)

------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)

类似地,如果我在 PyCharm 中打开这个文件,它会报告导入行中的错误:

Cannot find reference 'c' in '__init__.py'
Unresolved reference 'foo'

我应该如何使这些工具理解我的意图,将 c 模块视为位于 a 目录中?我知道我可以在 test.py 中加入注释来禁用各种检查,比如 # pylint: disable=E0401,但这不是可移植的(如果有人在不同的 IDE 中使用不同的代码检查工具会怎么样?),而且这只是隐藏问题而不是解决问题。我也不想将这些代码复制到根目录中的每个 .py 文件中。

或者也许这是不可能实现的,我必须始终指定正确的完整路径…?

英文:

Consider following project structure that uses nested modules:

$ tree
.
├── a
│   ├── b
│   │   ├── c
│   │   │   └── __init__.py
│   │   └── __init__.py
│   └── __init__.py
└── test.py

3 directories, 4 files

Content of test.py file:

<!-- language: lang-python -->

from a.b.c import foo

print(foo())

Content of a/b/c/__init__.py:

<!-- language: lang-python -->

def foo():
    return &quot;Hello world&quot;

I'd like to omit b when importing things and use from a.c import foo in test.py. This is because I want to organize the code internally in separate subdirectories while allowing files in the root directory to import everything using same base import path. I can achieve that by adding following code to the a/__init__.py:

<!-- language: lang-python -->

import importlib
import sys

importlib.import_module(&quot;a.b.c&quot;)
sys.modules[&quot;a.c&quot;] = sys.modules[&quot;a.b.c&quot;]

It works and when I call python test.py having from a.c import foo in it I can see expected Hello world output. However various Python tools and linters hate this. If I try to run pylint on test.py I can see it reporting import errors:

$ pylint test.py
************* Module test
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
test.py:1:0: E0401: Unable to import &#39;a.c&#39; (import-error)
test.py:1:0: E0611: No name &#39;c&#39; in module &#39;a&#39; (no-name-in-module)

------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)

Similarly, if I try to open this in PyCharm it reports errors in the import line:

Cannot find reference &#39;c&#39; in &#39;__init__.py&#39; 
Unresolved reference &#39;foo&#39; 

How can I make these tools understand my intent of treating c module as it were inside a directory? I know I can disable various lints placing comments such as # pylint: disable=E0401 in test.py but that's not portable (what if someone uses a different linter in some different IDE...?) and hides the problem instead of resolving it. I'd also hate to copy these into every .py file in the root directory.

Or perhaps it's impossible to achieve and I have just always specify a proper full path...?

答案1

得分: 1

为什么不将 a 中的 __init__.py 修改为导入所有必要的子模块并使其可访问。你可以基于以下放置在 a 中的 __init__.py 来构思你的想法。

import b.c as c

然后你可以在 test.py 中这样访问模块:

import a
a.c.foo()

或者,你可以像 ivvija 建议的那样在 a 中创建一个 c.py

c.py:

from b.c import *

为此,你只需确保你没有在 a/b/c/__init__.py 中重新定义 __all__,如果你这样做了,请确保添加所有所需的函数,如 __all__ = ["foo"]

英文:

Why don't you change __init__.py in a to import all the necessary submodules and make it accessible. You could base your ideas on the following __init__.py placed in a.

import b.c as c

Then you can access the module in test.py as follows:

import a
a.c.foo()

Alternatively, you could create a c.py in a as ivvija suggests.

c.py:

from b.c import *

For this you just need to make sure you aren't redefining __all__ in a/b/c/__init__.py and if you are make sure to add all the needed function like __all__ = [&quot;foo&quot;]

huangapple
  • 本文由 发表于 2023年3月3日 19:55:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75626762.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定