From de898c52eb5ed8b7ed1d4f96508a773b42a7ee86 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 30 Jul 2023 18:16:25 -0400 Subject: [PATCH] Avoid falsely marking non-submodules as submodule aliases (#6182) ## Summary We have some code to ensure that if an aliased import is used, any submodules should be marked as used too. This comment says it best: ```rust // If the name of a submodule import is the same as an alias of another import, and the // alias is used, then the submodule import should be marked as used too. // // For example, mark `pyarrow.csv` as used in: // // ```python // import pyarrow as pa // import pyarrow.csv // print(pa.csv.read_csv("test.csv")) // ``` ``` However, it looks like when we go to look up `pyarrow` (of `import pyarrow as pa`), we aren't checking to ensure the resolved binding is _actually_ an import. This was causing us to attribute `print(rm.ANY)` to `def requests_mock` here: ```python import requests_mock as rm def requests_mock(requests_mock: rm.Mocker): print(rm.ANY) ``` Closes https://github.com/astral-sh/ruff/issues/6180. --- crates/ruff/resources/test/fixtures/pyflakes/F823.py | 7 +++++++ crates/ruff_python_semantic/src/model.rs | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/ruff/resources/test/fixtures/pyflakes/F823.py b/crates/ruff/resources/test/fixtures/pyflakes/F823.py index a17d91f0c735b..343150143e442 100644 --- a/crates/ruff/resources/test/fixtures/pyflakes/F823.py +++ b/crates/ruff/resources/test/fixtures/pyflakes/F823.py @@ -63,3 +63,10 @@ def main(): for sys in range(5): pass + + +import requests_mock as rm + + +def requests_mock(requests_mock: rm.Mocker): + print(rm.ANY) diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 75810ef142bc1..fc66f668de8cf 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -594,7 +594,12 @@ impl<'a> SemanticModel<'a> { return None; } - self.scopes[scope_id].get(qualified_name) + let binding_id = self.scopes[scope_id].get(qualified_name)?; + if !self.bindings[binding_id].kind.is_submodule_import() { + return None; + } + + Some(binding_id) } /// Resolves the [`Expr`] to a fully-qualified symbol-name, if `value` resolves to an imported