Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to flag forbidden imports on the line at which they occur #411

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* In multiline import statements, import-related error codes such as Y022 and
Y027 are now emitted on the line of the specific import that is disallowed,
rather than the first line of the import statement.
* Introduce Y090, which warns if you have an annotation such as `tuple[int]` or
`Tuple[int]`. These mean "a tuple of length 1, in which the sole element is
of type `int`". This is sometimes what you want, but more usually you'll want
Expand Down
12 changes: 6 additions & 6 deletions pyi.py
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ def __repr__(self) -> str:
return f"{self.__class__.__name__}(filename={self.filename!r})"

def _check_import_or_attribute(
self, node: ast.Attribute | ast.ImportFrom, module_name: str, object_name: str
self, node: ast.Attribute | ast.alias, module_name: str, object_name: str
) -> None:
fullname = f"{module_name}.{object_name}"

Expand Down Expand Up @@ -975,21 +975,21 @@ def visit_ImportFrom(self, node: ast.ImportFrom) -> None:

if module_name == "__future__":
if "annotations" in imported_names:
self.error(node, Y044)
self.error(imported_names["annotations"], Y044)
return

if (
module_name == "collections.abc"
and "Set" in imported_names
and imported_names["Set"].asname != "AbstractSet"
):
self.error(node, Y025)
self.error(imported_names["Set"], Y025)

for object_name in imported_names:
self._check_import_or_attribute(node, module_name, object_name)
for object_name, subnode in imported_names.items():
self._check_import_or_attribute(subnode, module_name, object_name)

if module_name == "typing" and "AbstractSet" in imported_names:
self.error(node, Y038)
self.error(imported_names["AbstractSet"], Y038)

def _check_for_typevarlike_assignments(
self, node: ast.Assign, function: ast.expr, object_name: str
Expand Down
4 changes: 2 additions & 2 deletions tests/disabled_by_default.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This test file checks that disabled-by-default error codes aren't triggered,
# unless they're explicitly enabled
from typing import ( # Y022 Use "tuple[Foo, Bar]" instead of "typing.Tuple[Foo, Bar]" (PEP 585 syntax)
Tuple,
from typing import (
Tuple, # Y022 Use "tuple[Foo, Bar]" instead of "typing.Tuple[Foo, Bar]" (PEP 585 syntax)
)

# These would trigger Y090, but it's disabled by default
Expand Down
8 changes: 5 additions & 3 deletions tests/pep604_union_types.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import typing
from typing import ( # Y037 Use PEP 604 union types instead of typing.Optional (e.g. "int | None" instead of "Optional[int]"). # Y037 Use PEP 604 union types instead of typing.Union (e.g. "int | str" instead of "Union[int, str]").
Optional,
Union,
from typing import (
Optional, # Y037 Use PEP 604 union types instead of typing.Optional (e.g. "int | None" instead of "Optional[int]").
)
from typing import (
Union, # Y037 Use PEP 604 union types instead of typing.Union (e.g. "int | str" instead of "Union[int, str]").
)

x1: Optional[str]
Expand Down
14 changes: 9 additions & 5 deletions tests/union_duplicates.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@
import builtins
import typing
from collections.abc import Mapping
from typing import ( # Y022 Use "type[MyClass]" instead of "typing.Type[MyClass]" (PEP 585 syntax)
Type,
Union,
from typing import (
Type, # Y022 Use "type[MyClass]" instead of "typing.Type[MyClass]" (PEP 585 syntax)
)
from typing import Union

import typing_extensions
from typing_extensions import ( # Y022 Use "type[MyClass]" instead of "typing_extensions.Type[MyClass]" (PEP 585 syntax)

# Switch isort off or it auto-adds some fun SyntaxErrors here!!
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
# isort: off
from typing_extensions import (
Literal,
Type as Type_,
Type as Type_, # Y022 Use "type[MyClass]" instead of "typing_extensions.Type[MyClass]" (PEP 585 syntax)
TypeAlias,
)
# isort: on

def f1_pipe(x: int | str) -> None: ...
def f2_pipe(x: int | int) -> None: ... # Y016 Duplicate union member "int"
Expand Down