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

Fix Y053 false positives inside Literal and Annotated slices #497

Merged
merged 5 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## Unreleased

Bugfixes
* Don't emit Y053 for long strings inside `Literal` slices or
metadata strings inside `Annotated` slices.

## 24.6.0

Bugfixes
Expand Down
2 changes: 1 addition & 1 deletion ERRORCODES.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ The following warnings are currently emitted by default:
| <a id="Y050" href="#Y050">Y050</a> | Prefer `typing_extensions.Never` over `typing.NoReturn` for argument annotations. | Style
| <a id="Y051" href="#Y051">Y051</a> | Y051 detects redundant unions between `Literal` types and builtin supertypes. For example, `Literal[5]` is redundant in the union `int \| Literal[5]`, and `Literal[True]` is redundant in the union `Literal[True] \| bool`. | Redundant code
| <a id="Y052" href="#Y052">Y052</a> | Y052 disallows assignments to constant values where the assignment does not have a type annotation. For example, `x = 0` in the global namespace is ambiguous in a stub, as there are four different types that could be inferred for the variable `x`: `int`, `Final[int]`, `Literal[0]`, or `Final[Literal[0]]`. Enum members are excluded from this check, as are various special assignments such as `__all__` and `__match_args__`. | Correctness
| <a id="Y053" href="#Y053">Y053</a> | Only string and bytes literals <=50 characters long are permitted. | Style
| <a id="Y053" href="#Y053">Y053</a> | Only string and bytes literals <=50 characters long are permitted. (There are some exceptions, such as `Literal` subscripts, metadata strings inside `Annotated` subscripts, and strings passed to `@deprecated`.) | Style
| <a id="Y054" href="#Y054">Y054</a> | Only numeric literals with a string representation <=10 characters long are permitted. | Style
| <a id="Y055" href="#Y055">Y055</a> | Unions of the form `type[X] \| type[Y]` can be simplified to `type[X \| Y]`. Similarly, `Union[type[X], type[Y]]` can be simplified to `type[Union[X, Y]]`. | Style
| <a id="Y056" href="#Y056">Y056</a> | Do not call methods such as `.append()`, `.extend()` or `.remove()` on `__all__`. Different type checkers have varying levels of support for calling these methods on `__all__`. Use `+=` instead, which is known to be supported by all major type checkers. | Correctness
Expand Down
5 changes: 3 additions & 2 deletions pyi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1563,7 +1563,8 @@ def _visit_typing_Literal(self, node: ast.Subscript) -> None:
suggestion = f"Literal[{new_literal_slice}] | None"
self.error(analysis.none_members[0], Y061.format(suggestion=suggestion))

self.visit(node.slice)
with self.long_strings_allowed.enabled():
self.visit(node.slice)

def _visit_slice_tuple(self, node: ast.Tuple, parent: str | None) -> None:
if parent == "Union":
Expand All @@ -1573,7 +1574,7 @@ def _visit_slice_tuple(self, node: ast.Tuple, parent: str | None) -> None:
# Allow literals, except in the first argument
if len(node.elts) > 1:
self.visit(node.elts[0])
with self.string_literals_allowed.enabled():
with self.string_literals_allowed.enabled(), self.long_strings_allowed.enabled():
for elt in node.elts[1:]:
self.visit(elt)
else:
Expand Down
8 changes: 8 additions & 0 deletions tests/defaults.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import math
import os
import sys
from typing import Annotated, Literal, TypeAlias

import _typeshed
from _typeshed import SupportsRead, SupportsWrite, sentinel
Expand Down Expand Up @@ -84,3 +85,10 @@ def f40(x: int, /) -> None: ...
def f41(x: int, /, y: "int") -> None: ... # Y020 Quoted annotations should never be used in stubs
def f42(x: str = "y", /) -> None: ...
def f43(x: str = os.pathsep, /) -> None: ... # Y011 Only simple default values allowed for typed arguments

# Long strings inside `Literal` or `Annotated` slices are okay
def f44(x: Literal["loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"]) -> None: ...
def f55(x: Annotated[str, "metadataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]) -> None: ...

X: TypeAlias = Literal["llllllllllllllllllllllllllonggggggggggggggggggggggggggggggggggggggggg"]
Y: TypeAlias = Annotated[int, "verrrrrrrrrrrrrrrrrrrry looooooooooooooongggggggggggggggggggggggggggggggggggg"]
14 changes: 13 additions & 1 deletion tests/pep695_py312.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@

import typing
from collections.abc import Iterator
from typing import Any, NamedTuple, NoReturn, Protocol, Self, TypedDict
from typing import (
Annotated,
Any,
Literal,
NamedTuple,
NoReturn,
Protocol,
Self,
TypedDict,
)

type lowercase_alias = str | int # Y042 Type aliases should use the CamelCase naming convention
type _LooksLikeATypeVarT = str | int # Y043 Bad name for a type alias (the "T" suffix implies a TypeVar)
Expand Down Expand Up @@ -66,3 +75,6 @@ class _UnusedPEP695Protocol[T](Protocol): # Y046 Protocol "_UnusedPEP695Protoco

class _UnusedPEP695TypedDict[T](TypedDict): # Y049 TypedDict "_UnusedPEP695TypedDict" is not used
x: T

type X = Literal["Y053 will not be emitted here despite it being a very long string literal, because it is inside a `Literal` slice"]
type Y = Annotated[int, "look at me, very long string literal, but it's okay because it's an `Annotated` metadata string"]