Skip to main content

强制某些模块不能从其他模块导入。

项目描述

进口卫士

强制某些模块不能从其他模块导入。在运行时!

如果您需要静态分析工具,请查看flake8-import-graph

特征:

  • 在运行时工作
  • 检查动态导入
  • 可定制的规则

这个库有一些性能开销。在某些情况下,它可能会导致导入时间(和启动时间分别)降低 1.5-2 倍。建议仅在开发过程中启用 import_guard。

安装

pip install import-guard

用法

from import_guard import guard, mod


guard.set_deny_rules({
    # deny `csv` import from `test_proj` and submodules
    "test_proj": "csv",  # the same as mod("csv")
    # deny `selenium` and top_level `test_proj.tasks` imports from test_proj.api
    # but allow `test_proj.tasks` import inside the function (lazy import)
    # the same as mod("selenium") | (mod("test_proj.tasks") & Flags.TopLevel)
    "test_proj.api": ["selenium", mod.top_level("test_proj.tasks")],
    # deny `test_proj.api` and `test_proj.business_logic` imports from `test_proj.core`
    "test_proj.core": mod.matches(r"test_proj\.(api|business_logic)"),
    # deny all imports except `logging` and `yaml`
    "test_proj.logging": ~mod.explicit(["logging", "yaml"]),
})

# raise ForbiddenImportError
guard.enable(strict=True)

规则

下面的代码可以复制粘贴到 Python 解释器中,并假定以下导入:

from importlib import reload
from import_guard import guard, mod
# enable guard in advance
guard.enable()

完全符合

guard.set_deny_rules({"<stdin>": "decimal"})
# shortcut for mod("decimal")

from decimal import Decimal  # shows warning

from enum import Enum  # ok

显式匹配

考虑以下代码:

guard.set_deny_rules({"<stdin>": "re"})

import csv  # shows warning!

发生了什么?

csv在后台导入一些模块,例如reio. 我们通过模块隐式地启动了re模块的加载csv(深度 = 1 的规则匹配)。这是默认行为。您只能使用mod.explicit("re")函数检查显式导入。

guard.set_deny_rules({"<stdin>": mod.explicit("re")})
reload(csv)  # allowed
import re  # shows warning

匹配多个模块

guard.set_deny_rules({"<stdin>": ["logging", "json"]})
# the same as mod.any(["logging", "json'])
# the same as mod("logging") | mod("json")


import json  # shows warning
from logging import getLogger  # shows warning

通过正则表达式匹配

guard.set_deny_rules({"<stdin>": mod.matches("log.*")})

# shows multiple warnings
from logging.config import dictConfig

倒置

guard.set_deny_rules({"<stdin>": ~mod.matches("log.*")})

import io # shows warning

仅匹配模块级导入

通常的做法是进行本地导入而不是全局导入,以中断循环导入或推迟导入,直到您运行实际需要您正在导入的模块的代码。

# deny module-level imports
guard.set_deny_rules({"<stdin>": mod.top_level("array")})

def some_function():
    import array  # allowed (lazy import)

some_function()
import array  # shows warning

匹配明星导入

guard.set_deny_rules({"<stdin>": mod.star("csv")})

from csv import *  # shows warning

复杂的规则

规则非常灵活。您可以以不同的方式将它们组合在一起并构建非常复杂的条件。

mod.explicit(
    ~mod.top_level(["math", "json"])
    | mod.matches("log.*")
)

很好的例子:

  • 拒绝某些模块中的非延迟导入:
guard.set_deny_rules({
    "test_proj.business_logic": mod.top_level(mod.matches(".*")),
})
  • 拒绝在项目中开始导入:
guard.set_deny_rules({
    "test_proj": mod.star(mod.explicit(mod.matches(".*"))),
})

非严格模式

# not enabled for `prod`
if env == "staging":
    # warn on forbidden import
    guard.enable(strict=False)
elif env == "local":
    # raise ForbiddenImportError
    guard.enable(strict=True)

规则层次结构

模块的拒绝规则集也会影响其子模块。

guard.set_deny_rules({
    "test_proj": "json",
    "test_proj.api": ["selenum", "pandas"],
    "test_proj.core": "celery"
})

test_proj.core禁止jsoncelery进口。 test_proj.api.views禁止json, selenium,pandas进口。

懒惰模块

考虑以下项目结构:

# main.py
import api

# api.py
def view():
    import tasks

# tasks.py
import pandas

这里的main.pyimportsapitasks惰性导入,是pandas在模块级别导入。 import_guard将这种情况作为惰性模块导入处理,并且会认为熊猫被惰性导入。因此,在这种情况下,以下规则不会发出警告:

guard.set_deny_rules({"tasks": mod.top_level("pandas")})

自定义模块匹配器

def is_relative_import(import_info, caller_info):
    return import_info.level > 1

# deny relative import
guard.set_deny_rules({"proj": mod.hook(is_relative_import)})

from .api import view  # shows warning
from proj.api import view  # ok

测试

规则

直接测试规则:

rule = mod.top_level(mod.matches(".*"))
# True; mod1 imported at the module level in mod2
rule.test("mod1", caller="mod2")
# False; mod1 doesn't match the top_level constraint
rule.test("mod1", caller="<stdin>", top_level=False)

通过守卫测试拒绝规则:

guard.is_import_allowed("csv", caller="test_proj.api")  # False
guard.is_import_allowed("logging", caller="test_proj.api")  # True
guard.is_import_allowed("selenium", caller="test_proj.api")  # False
guard.is_import_allowed(
    "test_proj.tasks", caller="test_proj.api"
)  # False
guard.is_import_allowed(
    "test_proj.tasks", caller="test_proj.api", top_level=False
)  # True

单元测试

使用当前的 Python 解释器进行测试:

$ python -m unittest discover tests -v

使用不同的 Python 版本和解释器进行测试:

$ tox

项目详情


下载文件

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

源分布

import-guard-0.1.2.tar.gz (11.8 kB 查看哈希

已上传 source

内置分布

import_guard-0.1.2-py2.py3-none-any.whl (9.8 kB 查看哈希

已上传 py2 py3