使 flake8 区分未定义函数和星形导入

Make flake8 differentiate between undefined functions and star imports

我有一个相当大的项目,我试图在发布之前清理它,但是当我 运行 flake8 我得到大量

'F405 <function> may be undefined, or defined from star imports: generic_functions`

我可以通过替换以下行来避免这种情况:

from generic_functions import *

在我文件的开头,但是:

  1. 我确实使用了其中的所有函数,所以我不明白输入每个函数超过 80 个字符的限制有多 pythonic:

     from generic_functions import (function1, function2, function3, function4, function5, function6, function7...)
    
  2. 做上面的事情会很乏味,特别是如果我需要在 generic_functions.py

  3. 的几十个函数中添加或删除

另一个选项是禁用 F405 警告,但如果函数确实未定义怎么办?允许 star 导入同时仍然捕获任何未定义的东西会很好。有没有办法做到这一点?我尝试将 # noqa 添加到导入行,但似乎没有帮助。

您可以执行以下操作:

  1. 将您的导入保留为 from generic_functions import *
  2. 运行 flake8 为 flake8 --ignore=F405 file.py。我真的不知道为什么 # noqa 不起作用,但是 --ignore 可以。
  3. 使用 pylint 测试其余可能的错误。 Pylint 能够确定 <function> 是从 generic_functions.
  4. 定义和导入的

您可以使用 pylint 来确定哪些功能是必需的,哪些不是。我写了一个函数来自动化这个过程。它的工作原理如下:

  1. 运行 脚本上的 pylint 并匹配所有 W0614: Unused import 错误。
  2. 用vars()获取目标模块中的变量列表
  3. 取那些集合的差值,只有return个可以导入的东西。

import subprocess, types

def scrape_wildcard(filename, modvars):
    "Get variables imported from module in wild * import"
    error = "W0614: Unused import "
    unused = []
    for line in quickrun(['pylint', filename]):
        if error in line:
            unused.append(line.split(error)[1].split()[0])

    out = dict()
    for name in set(modvars.keys()) - set(unused):
        if not name.startswith('__'):
            func = modvars[name]
            if not isinstance(func, types.ModuleType):
                out[name] = modvars[name]
    return out


def quickrun(cmd, check=False, encoding='utf-8', errors='replace'):
    ret = subprocess.run(cmd, stdout=subprocess.PIPE, check=check)
    return ret.stdout.decode(encoding=encoding, errors=errors).splitlines()


import ????? as mymod
filename = "?????"
print('from', mymod.__name__, 'import', ', '.join(scrape_wildcard(filename, vars(mymod)).keys()))
'''

替换 ??????分别使用您的模块名称和模块的文件名。