From 1049370231c32db4dd385896e2471e6223482f5e Mon Sep 17 00:00:00 2001 From: shuiyu67 Date: Fri, 7 Aug 2026 09:04:53 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8F=8D=E5=95=83=20CPython=20=E6=A0=87?= =?UTF-8?q?=E5=87=86=E5=BA=93=E5=85=A8=E9=87=8F=20(630=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6)=20=E4=BF=AE=E5=A4=8D=E5=87=BD=E6=95=B0=E5=86=85=20im?= =?UTF-8?q?port=20=E6=BC=8F=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _ScopeAnalyzer 缺 visit_Import/visit_ImportFrom → 函数内 import (局部导入) 的名字没注册进作用域 → aifc.py math/audioop、argparse.py copy/shutil/textwrap 等 763 个 E002 误报消除 - E002 无 jedi 全量: 2332 → 1569 (剩余为 import* 盲区 + 模块级条件导入, jedi 会消大半) - E004 216 条抽查: enum i(空串真炸)/gzip buf(else 不赋) 为合理保留; functools candidate/dataclasses value 为条件关联盲区 - 新增 2 回归测试 (函数内 import / import from); 304 passed --- plugins/py_detect.py | 16 ++++++++++++++++ tests/test_py_detect.py | 13 +++++++++++++ 2 files changed, 29 insertions(+) diff --git a/plugins/py_detect.py b/plugins/py_detect.py index e5094f7..ddccb7a 100644 --- a/plugins/py_detect.py +++ b/plugins/py_detect.py @@ -351,6 +351,22 @@ class _ScopeAnalyzer(ast.NodeVisitor): self.generic_visit(node) self.scope_stack.pop() + def visit_Import(self, node: ast.Import): + if self.scope_stack: + for alias in node.names: + name = (alias.asname or alias.name).split(".")[0] + self.scope_stack[-1][name] = "导入" # 函数内 import (局部导入) + self.generic_visit(node) + + def visit_ImportFrom(self, node: ast.ImportFrom): + if self.scope_stack: + for alias in node.names: + if alias.name == "*": + continue + name = alias.asname or alias.name + self.scope_stack[-1][name] = "导入" + self.generic_visit(node) + def visit_Lambda(self, node: ast.Lambda): for a in node.args.args: self._declare(a.arg) diff --git a/tests/test_py_detect.py b/tests/test_py_detect.py index 7e2a74c..c1cf499 100644 --- a/tests/test_py_detect.py +++ b/tests/test_py_detect.py @@ -580,6 +580,19 @@ class TestDataFlow: assert "E002" not in {d["code"] for d in pd.analyze(src, "t.py")} assert "E004" not in {d["code"] for d in pd.analyze(src, "t.py")} + def test_function_local_import_ok(self, pd): + """函数内 import 不得误报 E002 (标准库 aifc math / argparse copy 场景)""" + src = ("def f(x):\n" + " import math\n" + " return math.frexp(x)\n") + assert "E002" not in {d["code"] for d in pd.analyze(src, "t.py")} + + def test_function_local_import_from_ok(self, pd): + src = ("def f():\n" + " from math import sqrt\n" + " return sqrt(4)\n") + assert "E002" not in {d["code"] for d in pd.analyze(src, "t.py")} + def test_const_iter_always_runs(self, pd): """for f in ('a','b','c'): 常量非空 → 循环变量确定 (pydantic v1 host 场景)""" src = ("def f(parts):\n"