跳转到主要内容

自动将文件中的 'import *' 导入替换为显式导入的工具

项目描述

removestar

Actions Status PyPI version Anaconda-Server Badge PyPI platforms Downloads Conda Downloads Ruff

工具,用于自动将Python文件中的 import * 导入替换为显式导入

安装

全局安装 removestar 以通过CLI使用 pypi -

pip install removestar
pip install "removestar[nb]"  # notebook support

或者 conda -

conda install -c conda-forge removestar

或者在 .pre-commit-config.yaml 中添加 removestar -

- repo: https://github.com/asmeurer/removestar
  rev: "1.5"
  hooks:
    - id: removestar
      args: [-i] # See docs for all args (-i edits file in-place)
      additional_dependencies: # The libraries or packages your code imports
        - ... # Add . if running inside a library (to install the library itself in the environment)
        - ... # Add nbformat and nbconvert for notebook support

用法

pre-commit 插件

一旦在 .pre-commit-config.yaml 中添加了 removestar,执行以下操作将始终在每次提交前运行它(以及其他 pre-commits)-

pre-commit install

可选地,可以使用 - 手动触发所有文件的 pre-commits(包括 removestar

pre-commit run --all-files

命令行界面(CLI)

# scripts

$ removestar file.py # Shows diff but does not edit file.py

$ removestar -i file.py # Edits file.py in-place

$ removestar -i module/ # Modifies every Python file in module/ recursively

# notebooks (make sure nbformat and nbconvert are installed)

$ removestar file.ipynb # Shows diff but does not edit file.ipynb

$ removestar -i file.ipynb # Edits file.ipynb in-place

为什么 import * 那么糟糕?

from module import * 在 Python 中通常是不受欢迎的。在交互式使用 python 提示符或在 __init__.py 文件中工作时被认为是可接受的(removestar 默认跳过 __init__.py 文件)。

import * 糟糕的几个原因

  • 它隐藏了实际导入的名称。
  • 当使用 import * 时,对于人类阅读者以及像 pyflakes 这样的静态分析器来说,很难确定给定名称的来源。例如,pyflakes 无法检测到 import * 存在时未使用的名称(例如,来自拼写错误)。
  • 如果有多个 import * 语句,可能不清楚哪些名称来自哪个模块。在某些情况下,两个模块可能都有相同的名称,但只有第二个导入最终会被使用。这可能会打破人们对 Python 文件中导入顺序通常不重要的直觉。
  • import * 经常导入比预期的更多名称。除非你导入的模块定义了 __all__ 或在模块级别仔细 del 未使用的名称,否则 import * 将导入模块文件中定义的每个公共(不以下划线开头)名称。这通常包括标准库导入或文件顶级定义的循环变量。从模块(从 __init__.py)的导入中,from module import * 将包括在该模块中定义的每个子模块。在模块和 __init__.py 文件中使用 __all__ 也是良好的实践,因为这些内容对于交互式使用 import * 时也常常令人困惑。
  • 在 Python 3 中,import * 在函数内部是不允许的。

以下是一些官方 Python 引用,说明不要在文件中使用 import *

  • 官方 Python FAQ:

    一般来说,不要使用 from modulename import *。这样做会使导入者的命名空间变得混乱,并使代码检查器检测未定义的名称变得更加困难。

  • PEP 8(官方 Python 风格指南)

    避免使用通配符导入(from <module> import *),因为它们使命名空间中存在的名称变得不清楚,既使读者困惑,也使许多自动化工具困惑。

不幸的是,如果你遇到使用 import * 的文件,修复它可能很困难,因为你需要找到文件中从 * 导入的每个名称。Removestar 通过自动替换文件中的导入行来简化这个过程。

一个例外是,在代码开发的早期阶段,可能难以确定一个明确的必需函数集。在这种情况下,通配符导入可以通过避免不断维护必需函数集而有益。例如,在开发阶段使用 from os.path import * 可以节省维护必需函数的时间。在开发完成后,可以使用 removestar 确定通配符导入。话虽如此,由于多个上述原因,应该避免使用通配符导入。

示例

假设你有一个名为 mymod 的模块

mymod/
  | __init__.py
  | a.py
  | b.py

# mymod/a.py
from .b import *


def func(x):
    return x + y
# mymod/b.py
x = 1
y = 2

那么 removestar 将像这样工作

$ removestar mymod/

--- original/mymod/a.py
+++ fixed/mymod/a.py
@@ -1,5 +1,5 @@
 # mymod/a.py
-from .b import *
+from .b import y

 def func(x):
     return x + y

默认情况下,此工具不会编辑 a.py。使用 -i 标志会在原地编辑 a.py

$ removestar -i mymod/
$ cat mymod/a.py
# mymod/a.py
from .b import y

def func(x):
    return x + y

命令行选项

$ removestar --help
usage: removestar [-h] [-i] [--version] [--no-skip-init]
                  [--no-dynamic-importing] [-v] [-q]
                  [--max-line-length MAX_LINE_LENGTH]
                  PATH [PATH ...]

Tool to automatically replace "import *" imports with explicit imports

Requires pyflakes.

Usage:

$ removestar file.py # Shows diff but does not edit file.py

$ removestar -i file.py # Edits file.py in-place

$ removestar -i module/ # Modifies every Python file in module/ recursively

positional arguments:
  PATH                  Files or directories to fix

optional arguments:
  -h, --help            show this help message and exit
  -i, --in-place        Edit the files in-place. (default: False)
  --version             Show removestar version number and exit.
  --no-skip-init        Don't skip __init__.py files (they are skipped by
                        default) (default: True)
  --no-dynamic-importing
                        Don't dynamically import modules to determine the list
                        of names. This is required for star imports from
                        external modules and modules in the standard library.
                        (default: True)
  -v, --verbose         Print information about every imported name that is
                        replaced. (default: False)
  -q, --quiet           Don't print any warning messages. (default: False)
  --max-line-length MAX_LINE_LENGTH
                        The maximum line length for replaced imports before
                        they are wrapped. Set to 0 to disable line wrapping.
                        (default: 100)

白名单星号导入

removestar 不会替换标记有允许星号导入的 Flake8 noqa 注释 的星号导入行(例如,F401F403)。

例如,此模块中的星号导入将被保留

from os import *  # noqa: F401
from .b import *  # noqa


def func(x):
    return x + y

当前限制

  • 假设星号导入只使用当前文件中的名称(例如,在 __init__.py 中替换星号导入将不起作用)。

  • 对于同一模块内的文件,removestar 会静态地确定缺失的导入名称。对于外部库导入,包括标准库模块的导入,它会动态导入模块以确定名称。可以使用 --no-dynamic-importing 标志禁用此功能。

贡献

请参阅 问题跟踪器。欢迎提交拉取请求。

变更日志

请参阅 CHANGELOG 文件。

许可

MIT

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源分布

removestar-1.5.1.tar.gz (14.0 kB 查看哈希值)

上传时间

构建分布

removestar-1.5.1-py3-none-any.whl (16.1 kB 查看哈希值)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面