diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d5683a4c..5be12e41 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,7 +15,7 @@ unreleased statements). The previous checks were disabled by default. * detect usage of non-integer indices in sys.version_info checks * extend Y010 to check async functions in addition to normal functions -* introduce Y093 (require using TypeAlias for type aliases) +* introduce Y026 (require using TypeAlias for type aliases) * introduce Y017 (disallows assignments with multiple targets or non-name targets) * extend Y001 to cover ParamSpec and TypeVarTuple in addition to TypeVar * introduce Y018 (detect unused TypeVars) @@ -28,6 +28,7 @@ unreleased * introduce Y023 (prefer ``typing`` over ``typing_extensions``) * introduce Y024 (prefer ``typing.NamedTuple`` to ``collections.namedtuple``) * introduce Y025 (always alias ``collections.abc.Set``) +* all errors are now enabled by default 20.10.0 ~~~~~~~ diff --git a/README.rst b/README.rst index f24f395d..fbeeda2d 100644 --- a/README.rst +++ b/README.rst @@ -91,12 +91,16 @@ currently emitted: for more precise type inference. * Y025: Always alias ``collections.abc.Set`` when importing it, so as to avoid confusion with ``builtins.set``. +* Y026: Type aliases should be explicitly demarcated with ``typing.TypeAlias``. * Y028: Always use class-based syntax for ``typing.NamedTuple``, instead of assignment-based syntax. -The following warnings are disabled by default: +Many error codes enforce modern conventions, and some cannot yet be used in +all cases: -* Y093: Type aliases should be explicitly demarcated with ``typing.TypeAlias``. +* Y026 is incompatible with the pytype type checker and should be turned + off for stubs that need to be compatible with pytype. A fix is tracked + `here `_. License ------- diff --git a/pyi.py b/pyi.py index 63275f24..b1cebd5a 100644 --- a/pyi.py +++ b/pyi.py @@ -346,14 +346,15 @@ def visit_Assign(self, node: ast.Assign) -> None: self.typevarlike_defs[target_info] = node else: self.error(target, Y001.format(cls_name)) - # We avoid triggering Y093 in this case because there are various - # unusual cases where assignment to the result of a call is legitimate - # in stubs. - return if isinstance(node.value, (ast.Num, ast.Str, ast.Bytes)): self.error(node.value, Y015) - else: - self.error(node, Y093) + # We avoid triggering Y026 for calls and = ... because there are various + # unusual cases where assignment to the result of a call is legitimate + # in stubs. + elif target_name != "__all__" and not isinstance( + node.value, (ast.Ellipsis, ast.Call) + ): + self.error(node, Y026) def visit_Name(self, node: ast.Name) -> None: self.all_name_occurrences[node.id] += 1 @@ -803,8 +804,7 @@ def run(self): if path.suffix == ".pyi": visitor = PyiVisitor(filename=path) for error in visitor.run(self.tree): - if self.should_warn(error.message[:4]): - yield error + yield error @classmethod def add_options(cls, parser): @@ -830,7 +830,6 @@ def add_options(cls, parser): except optparse.OptionConflictError: # In tests, sometimes this option gets called twice for some reason. pass - parser.extend_default_ignore(DISABLED_BY_DEFAULT) @classmethod def parse_options(cls, optmanager, options, extra_args): @@ -838,28 +837,6 @@ def parse_options(cls, optmanager, options, extra_args): if not options.no_pyi_aware_file_checker: checker.FileChecker = PyiAwareFileChecker - # Functionality to ignore some warnings. Adapted from flake8-bugbear. - def should_warn(self, code): - """Returns `True` if flake8-pyi should emit a particular warning. - flake8 overrides default ignores when the user specifies - `ignore = ` in configuration. This is problematic because it means - specifying anything in `ignore = ` implicitly enables all optional - warnings. This function is a workaround for this behavior. - Users should explicitly enable these warnings. - """ - if code[:3] != "Y09": - # Normal warnings are safe for emission. - return True - - if self.options is None: - return True - - for i in range(2, len(code) + 1): - if code[:i] in self.options.select: - return True - - return False - # Please keep error code lists in README and CHANGELOG up to date Y001 = "Y001 Name of private {} must start with _" @@ -892,7 +869,5 @@ def should_warn(self, code): 'Y025 Use "from collections.abc import Set as AbstractSet" ' 'to avoid confusion with "builtins.set"' ) +Y026 = "Y026 Use typing_extensions.TypeAlias for type aliases" Y028 = "Y028 Use class-based syntax for NamedTuples" -Y093 = "Y093 Use typing_extensions.TypeAlias for type aliases" - -DISABLED_BY_DEFAULT = [Y093] diff --git a/tests/aliases.pyi b/tests/aliases.pyi index 6e4f93fc..193addef 100644 --- a/tests/aliases.pyi +++ b/tests/aliases.pyi @@ -1,7 +1,6 @@ -# flags: --select=Y017,Y093 from typing import TypeAlias, ParamSpec as _ParamSpec, _Alias, TypedDict -X = int # Y093 Use typing_extensions.TypeAlias for type aliases +X = int # Y026 Use typing_extensions.TypeAlias for type aliases X: TypeAlias = int a = b = int # Y017 Only simple assignments allowed diff --git a/tests/del.pyi b/tests/del.pyi index d92a95a0..f2f11d0b 100644 --- a/tests/del.pyi +++ b/tests/del.pyi @@ -1,8 +1,8 @@ -from typing import Union +from typing import Union, TypeAlias -ManyStr = list[EitherStr] -EitherStr = Union[str, bytes] +ManyStr: TypeAlias = list[EitherStr] +EitherStr: TypeAlias = Union[str, bytes] def function(accepts: EitherStr) -> None: diff --git a/tests/forward_refs.pyi b/tests/forward_refs.pyi index e3497fd8..e40d189d 100644 --- a/tests/forward_refs.pyi +++ b/tests/forward_refs.pyi @@ -1,8 +1,8 @@ -from typing import Optional, Union +from typing import Optional, Union, TypeAlias -MaybeCStr = Optional[CStr] -CStr = Union[C, str] +MaybeCStr: TypeAlias = Optional[CStr] +CStr: TypeAlias = Union[C, str] __version__ = ... # type: str __author__ = ... # type: str @@ -12,14 +12,14 @@ def make_default_c() -> C: class D(C): - parent = None # type: C + parent: C def __init__(self) -> None: ... class C: - other = None # type: C + other: C def __init__(self) -> None: ... diff --git a/tests/forward_refs_annassign.pyi b/tests/forward_refs_annassign.pyi index 8323693f..70573c87 100644 --- a/tests/forward_refs_annassign.pyi +++ b/tests/forward_refs_annassign.pyi @@ -1,8 +1,8 @@ -from typing import Optional, Union +from typing import Optional, Union, TypeAlias -MaybeCStr = Optional[CStr] -CStr = Union[C, str] +MaybeCStr: TypeAlias = Optional[CStr] +CStr: TypeAlias = Union[C, str] __version__: str __author__: str diff --git a/tests/quotes.pyi b/tests/quotes.pyi index e7303cc4..38f53a1f 100644 --- a/tests/quotes.pyi +++ b/tests/quotes.pyi @@ -1,4 +1,4 @@ -from typing import TypeVar, Literal, Annotated +from typing import TypeVar, Literal, Annotated, TypeAlias __all__ = ["f", "g"] @@ -22,7 +22,7 @@ def j() -> "int": # Y020 Quoted annotations should never be used in stubs ... -Alias = list["int"] # Y020 Quoted annotations should never be used in stubs +Alias: TypeAlias = list["int"] # Y020 Quoted annotations should never be used in stubs class Child(list["int"]): # Y020 Quoted annotations should never be used in stubs """Documented and guaranteed useful.""" # Y021 Docstrings should not be included in stubs diff --git a/tests/vanilla_flake8_not_clean_forward_refs.pyi b/tests/vanilla_flake8_not_clean_forward_refs.pyi index 379defb4..67d65b3c 100644 --- a/tests/vanilla_flake8_not_clean_forward_refs.pyi +++ b/tests/vanilla_flake8_not_clean_forward_refs.pyi @@ -1,9 +1,9 @@ # flags: --no-pyi-aware-file-checker -from typing import Union +from typing import Union, TypeAlias -ManyStr = list[EitherStr] # F821 undefined name 'EitherStr' -EitherStr = Union[str, bytes] +ManyStr: TypeAlias = list[EitherStr] # F821 undefined name 'EitherStr' +EitherStr: TypeAlias = Union[str, bytes] def function(accepts: EitherStr) -> None: