如何获取mypy插件回调当前处理的模块/文件信息?
如何在mypy插件中跟踪当前模块以区分内部/外部API访问?
要解决这个问题,核心是从AttributeContext中获取当前代码所在的模块信息,以此判断访问是否来自库内部还是外部客户代码,具体实现如下:
核心思路
- 通过
AttributeContext.context.location获取当前访问代码所在的文件路径 - 利用mypy插件的
API对象(ctx.api)将文件路径映射为对应的模块名称 - 对比模块名称是否属于目标库包(示例中为
simu),仅记录外部模块的访问
修改后的插件代码
from mypy.plugin import AttributeContext, Plugin from mypy.types import Type from mypy.nodes import MemberExpr, SuperExpr, node_kinds class ObserverPlugin(Plugin): basename = "simu" def get_attribute_hook(self, value: str): # 仅处理来自目标包的属性 if value.startswith(self.basename): def log_external_access(ctx: AttributeContext) -> Type: # 获取当前访问所在的文件路径 if not ctx.context.location: return ctx.default_attr_type file_path = ctx.context.location.filename # 通过mypy API将文件路径转换为模块名 module_name = ctx.api.modules.get(file_path) if not module_name: # 无法识别模块时跳过(比如临时文件或未纳入检查的代码) return ctx.default_attr_type # 过滤内部模块的访问 if module_name.startswith(self.basename): return ctx.default_attr_type # 记录访问类型(保留原有逻辑) new = "" if isinstance(ctx.context, SuperExpr): kind = "via super()" elif isinstance(ctx.context, MemberExpr): kind = node_kinds.get(ctx.context.kind) or "read access" if ctx.context.is_new_def: new = "new " else: kind = str(type(ctx.context)) print(f"外部访问: {value} ({new}{kind}) - 来源模块: {module_name}") return ctx.default_attr_type return log_external_access def plugin(version: str): return ObserverPlugin
关键细节说明
- 模块名映射:
ctx.api.modules是mypy维护的文件路径与模块名的映射表,可直接通过当前文件路径获取对应的模块名称 - 内部访问过滤:若当前模块名以目标库包名(
simu)开头,判定为内部访问,直接返回默认类型不记录;否则视为外部访问并输出日志 - 边界兼容:增加了对
location不存在、无法识别模块等异常情况的处理,避免插件运行崩溃
内容的提问来源于stack exchange,提问作者Anaphory
相关产品推荐
相关产品推荐

