mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:48 +00:00
Respect multi-segment submodule imports when resolving qualified names (#9382)
Ensures that if the user has `import collections.abc`, then `get_or_import_symbol` returns `collections.abc.Iterator` (or similar) when requested.
This commit is contained in:
parent
1ffc738c84
commit
7b6baff734
3 changed files with 68 additions and 111 deletions
|
@ -51,19 +51,14 @@ PYI058.py:21:13: PYI058 [*] Use `Iterator` as the return value for simple `__ite
|
||||||
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import Iterator
|
18 18 | import collections.abc
|
||||||
1 2 | def scope():
|
19 19 |
|
||||||
2 3 | from collections.abc import Generator
|
20 20 | class IteratorReturningSimpleGenerator3:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
18 19 | import collections.abc
|
|
||||||
19 20 |
|
|
||||||
20 21 | class IteratorReturningSimpleGenerator3:
|
|
||||||
21 |- def __iter__(self) -> collections.abc.Generator:
|
21 |- def __iter__(self) -> collections.abc.Generator:
|
||||||
22 |+ def __iter__(self) -> Iterator:
|
21 |+ def __iter__(self) -> collections.abc.Iterator:
|
||||||
22 23 | ... # PYI058 (use `Iterator`)
|
22 22 | ... # PYI058 (use `Iterator`)
|
||||||
23 24 |
|
23 23 |
|
||||||
24 25 |
|
24 24 |
|
||||||
|
|
||||||
PYI058.py:30:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
PYI058.py:30:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
||||||
|
|
|
|
||||||
|
@ -75,19 +70,14 @@ PYI058.py:30:13: PYI058 [*] Use `Iterator` as the return value for simple `__ite
|
||||||
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import Iterator
|
27 27 | from typing import Any
|
||||||
1 2 | def scope():
|
28 28 |
|
||||||
2 3 | from collections.abc import Generator
|
29 29 | class IteratorReturningSimpleGenerator4:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
27 28 | from typing import Any
|
|
||||||
28 29 |
|
|
||||||
29 30 | class IteratorReturningSimpleGenerator4:
|
|
||||||
30 |- def __iter__(self, /) -> collections.abc.Generator[str, Any, None]:
|
30 |- def __iter__(self, /) -> collections.abc.Generator[str, Any, None]:
|
||||||
31 |+ def __iter__(self, /) -> Iterator[str]:
|
30 |+ def __iter__(self, /) -> collections.abc.Iterator[str]:
|
||||||
31 32 | ... # PYI058 (use `Iterator`)
|
31 31 | ... # PYI058 (use `Iterator`)
|
||||||
32 33 |
|
32 32 |
|
||||||
33 34 |
|
33 33 |
|
||||||
|
|
||||||
PYI058.py:39:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
PYI058.py:39:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
||||||
|
|
|
|
||||||
|
@ -99,19 +89,14 @@ PYI058.py:39:13: PYI058 [*] Use `Iterator` as the return value for simple `__ite
|
||||||
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import Iterator
|
36 36 | import typing
|
||||||
1 2 | def scope():
|
37 37 |
|
||||||
2 3 | from collections.abc import Generator
|
38 38 | class IteratorReturningSimpleGenerator5:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
36 37 | import typing
|
|
||||||
37 38 |
|
|
||||||
38 39 | class IteratorReturningSimpleGenerator5:
|
|
||||||
39 |- def __iter__(self, /) -> collections.abc.Generator[str, None, typing.Any]:
|
39 |- def __iter__(self, /) -> collections.abc.Generator[str, None, typing.Any]:
|
||||||
40 |+ def __iter__(self, /) -> Iterator[str]:
|
39 |+ def __iter__(self, /) -> collections.abc.Iterator[str]:
|
||||||
40 41 | ... # PYI058 (use `Iterator`)
|
40 40 | ... # PYI058 (use `Iterator`)
|
||||||
41 42 |
|
41 41 |
|
||||||
42 43 |
|
42 42 |
|
||||||
|
|
||||||
PYI058.py:47:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
PYI058.py:47:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
||||||
|
|
|
|
||||||
|
@ -167,18 +152,13 @@ PYI058.py:73:13: PYI058 [*] Use `AsyncIterator` as the return value for simple `
|
||||||
= help: Convert the return annotation of your `__aiter__` method to `AsyncIterator`
|
= help: Convert the return annotation of your `__aiter__` method to `AsyncIterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import AsyncIterator
|
70 70 | import collections.abc
|
||||||
1 2 | def scope():
|
71 71 |
|
||||||
2 3 | from collections.abc import Generator
|
72 72 | class AsyncIteratorReturningSimpleAsyncGenerator3:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
70 71 | import collections.abc
|
|
||||||
71 72 |
|
|
||||||
72 73 | class AsyncIteratorReturningSimpleAsyncGenerator3:
|
|
||||||
73 |- def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]:
|
73 |- def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]:
|
||||||
74 |+ def __aiter__(self, /) -> AsyncIterator[str]:
|
73 |+ def __aiter__(self, /) -> collections.abc.AsyncIterator[str]:
|
||||||
74 75 | ... # PYI058 (Use `AsyncIterator`)
|
74 74 | ... # PYI058 (Use `AsyncIterator`)
|
||||||
75 76 |
|
75 75 |
|
||||||
76 77 |
|
76 76 |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,19 +54,14 @@ PYI058.pyi:17:13: PYI058 [*] Use `Iterator` as the return value for simple `__it
|
||||||
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import Iterator
|
14 14 | import collections.abc
|
||||||
1 2 | def scope():
|
15 15 |
|
||||||
2 3 | from collections.abc import Generator
|
16 16 | class IteratorReturningSimpleGenerator3:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
14 15 | import collections.abc
|
|
||||||
15 16 |
|
|
||||||
16 17 | class IteratorReturningSimpleGenerator3:
|
|
||||||
17 |- def __iter__(self) -> collections.abc.Generator: ... # PYI058 (use `Iterator`)
|
17 |- def __iter__(self) -> collections.abc.Generator: ... # PYI058 (use `Iterator`)
|
||||||
18 |+ def __iter__(self) -> Iterator: ... # PYI058 (use `Iterator`)
|
17 |+ def __iter__(self) -> collections.abc.Iterator: ... # PYI058 (use `Iterator`)
|
||||||
18 19 |
|
18 18 |
|
||||||
19 20 | def scope():
|
19 19 | def scope():
|
||||||
20 21 | import collections.abc
|
20 20 | import collections.abc
|
||||||
|
|
||||||
PYI058.pyi:24:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
PYI058.pyi:24:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
||||||
|
|
|
|
||||||
|
@ -79,19 +74,14 @@ PYI058.pyi:24:13: PYI058 [*] Use `Iterator` as the return value for simple `__it
|
||||||
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import Iterator
|
21 21 | from typing import Any
|
||||||
1 2 | def scope():
|
22 22 |
|
||||||
2 3 | from collections.abc import Generator
|
23 23 | class IteratorReturningSimpleGenerator4:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
21 22 | from typing import Any
|
|
||||||
22 23 |
|
|
||||||
23 24 | class IteratorReturningSimpleGenerator4:
|
|
||||||
24 |- def __iter__(self, /) -> collections.abc.Generator[str, Any, None]: ... # PYI058 (use `Iterator`)
|
24 |- def __iter__(self, /) -> collections.abc.Generator[str, Any, None]: ... # PYI058 (use `Iterator`)
|
||||||
25 |+ def __iter__(self, /) -> Iterator[str]: ... # PYI058 (use `Iterator`)
|
24 |+ def __iter__(self, /) -> collections.abc.Iterator[str]: ... # PYI058 (use `Iterator`)
|
||||||
25 26 |
|
25 25 |
|
||||||
26 27 | def scope():
|
26 26 | def scope():
|
||||||
27 28 | import collections.abc
|
27 27 | import collections.abc
|
||||||
|
|
||||||
PYI058.pyi:31:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
PYI058.pyi:31:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
||||||
|
|
|
|
||||||
|
@ -104,19 +94,14 @@ PYI058.pyi:31:13: PYI058 [*] Use `Iterator` as the return value for simple `__it
|
||||||
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
= help: Convert the return annotation of your `__iter__` method to `Iterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import Iterator
|
28 28 | import typing
|
||||||
1 2 | def scope():
|
29 29 |
|
||||||
2 3 | from collections.abc import Generator
|
30 30 | class IteratorReturningSimpleGenerator5:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
28 29 | import typing
|
|
||||||
29 30 |
|
|
||||||
30 31 | class IteratorReturningSimpleGenerator5:
|
|
||||||
31 |- def __iter__(self, /) -> collections.abc.Generator[str, None, typing.Any]: ... # PYI058 (use `Iterator`)
|
31 |- def __iter__(self, /) -> collections.abc.Generator[str, None, typing.Any]: ... # PYI058 (use `Iterator`)
|
||||||
32 |+ def __iter__(self, /) -> Iterator[str]: ... # PYI058 (use `Iterator`)
|
31 |+ def __iter__(self, /) -> collections.abc.Iterator[str]: ... # PYI058 (use `Iterator`)
|
||||||
32 33 |
|
32 32 |
|
||||||
33 34 | def scope():
|
33 33 | def scope():
|
||||||
34 35 | from collections.abc import Generator
|
34 34 | from collections.abc import Generator
|
||||||
|
|
||||||
PYI058.pyi:37:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
PYI058.pyi:37:13: PYI058 [*] Use `Iterator` as the return value for simple `__iter__` methods
|
||||||
|
|
|
|
||||||
|
@ -173,19 +158,14 @@ PYI058.pyi:49:13: PYI058 [*] Use `AsyncIterator` as the return value for simple
|
||||||
= help: Convert the return annotation of your `__aiter__` method to `AsyncIterator`
|
= help: Convert the return annotation of your `__aiter__` method to `AsyncIterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import AsyncIterator
|
46 46 | import collections.abc
|
||||||
1 2 | def scope():
|
47 47 |
|
||||||
2 3 | from collections.abc import Generator
|
48 48 | class AsyncIteratorReturningSimpleAsyncGenerator3:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
46 47 | import collections.abc
|
|
||||||
47 48 |
|
|
||||||
48 49 | class AsyncIteratorReturningSimpleAsyncGenerator3:
|
|
||||||
49 |- def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]:
|
49 |- def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]:
|
||||||
50 |+ def __aiter__(self, /) -> AsyncIterator[str]:
|
49 |+ def __aiter__(self, /) -> collections.abc.AsyncIterator[str]:
|
||||||
50 51 | ... # PYI058 (Use `AsyncIterator`)
|
50 50 | ... # PYI058 (Use `AsyncIterator`)
|
||||||
51 52 |
|
51 51 |
|
||||||
52 53 | def scope():
|
52 52 | def scope():
|
||||||
|
|
||||||
PYI058.pyi:56:13: PYI058 [*] Use `AsyncIterator` as the return value for simple `__aiter__` methods
|
PYI058.pyi:56:13: PYI058 [*] Use `AsyncIterator` as the return value for simple `__aiter__` methods
|
||||||
|
|
|
|
||||||
|
@ -198,18 +178,13 @@ PYI058.pyi:56:13: PYI058 [*] Use `AsyncIterator` as the return value for simple
|
||||||
= help: Convert the return annotation of your `__aiter__` method to `AsyncIterator`
|
= help: Convert the return annotation of your `__aiter__` method to `AsyncIterator`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
1 |+from collections.abc import AsyncIterator
|
53 53 | import collections.abc
|
||||||
1 2 | def scope():
|
54 54 |
|
||||||
2 3 | from collections.abc import Generator
|
55 55 | class AsyncIteratorReturningSimpleAsyncGenerator3:
|
||||||
3 4 |
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
53 54 | import collections.abc
|
|
||||||
54 55 |
|
|
||||||
55 56 | class AsyncIteratorReturningSimpleAsyncGenerator3:
|
|
||||||
56 |- def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]: ... # PYI058 (Use `AsyncIterator`)
|
56 |- def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]: ... # PYI058 (Use `AsyncIterator`)
|
||||||
57 |+ def __aiter__(self, /) -> AsyncIterator[str]: ... # PYI058 (Use `AsyncIterator`)
|
56 |+ def __aiter__(self, /) -> collections.abc.AsyncIterator[str]: ... # PYI058 (Use `AsyncIterator`)
|
||||||
57 58 |
|
57 57 |
|
||||||
58 59 | def scope():
|
58 58 | def scope():
|
||||||
59 60 | from typing import Iterator
|
59 59 | from typing import Iterator
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -802,8 +802,10 @@ impl<'a> SemanticModel<'a> {
|
||||||
}
|
}
|
||||||
// Ex) Given `module="os"` and `object="name"`:
|
// Ex) Given `module="os"` and `object="name"`:
|
||||||
// `import os.path ` -> `os.name`
|
// `import os.path ` -> `os.name`
|
||||||
BindingKind::SubmoduleImport(SubmoduleImport { .. }) => {
|
// Ex) Given `module="os.path"` and `object="join"`:
|
||||||
if name == module {
|
// `import os.path ` -> `os.path.join`
|
||||||
|
BindingKind::SubmoduleImport(SubmoduleImport { call_path }) => {
|
||||||
|
if call_path.starts_with(&module_path) {
|
||||||
if let Some(source) = binding.source {
|
if let Some(source) = binding.source {
|
||||||
// Verify that `os` isn't bound in an inner scope.
|
// Verify that `os` isn't bound in an inner scope.
|
||||||
if self
|
if self
|
||||||
|
@ -812,7 +814,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
.all(|scope| !scope.has(name))
|
.all(|scope| !scope.has(name))
|
||||||
{
|
{
|
||||||
return Some(ImportedName {
|
return Some(ImportedName {
|
||||||
name: format!("{name}.{member}"),
|
name: format!("{module}.{member}"),
|
||||||
source,
|
source,
|
||||||
range: self.nodes[source].range(),
|
range: self.nodes[source].range(),
|
||||||
context: binding.context,
|
context: binding.context,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue