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"