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

Disambiguate between str and enum member args to typing.Literal #7414

Merged
merged 5 commits into from
Sep 12, 2022
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
4 changes: 4 additions & 0 deletions doc/whatsnew/fragments/3299.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix bug in scanning of names inside arguments to `typing.Literal`.
See https://peps.python.org/pep-0586/#literals-enums-and-forward-references for details.

Refs #3299
21 changes: 9 additions & 12 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2919,28 +2919,25 @@ def visit_const(self, node: nodes.Const) -> None:
return
if not utils.is_node_in_type_annotation_context(node):
return
if not node.value.isidentifier():
try:
annotation = extract_node(node.value)
self._store_type_annotation_node(annotation)
except ValueError:
# e.g. node.value is white space
return
except astroid.AstroidSyntaxError:
# e.g. "?" or ":" in typing.Literal["?", ":"]
return

# Check if parent's or grandparent's first child is typing.Literal
parent = node.parent
if isinstance(parent, nodes.Tuple):
parent = parent.parent

if isinstance(parent, nodes.Subscript):
origin = next(parent.get_children(), None)
if origin is not None and utils.is_typing_literal(origin):
return

self._type_annotation_names.append(node.value)
try:
annotation = extract_node(node.value)
self._store_type_annotation_node(annotation)
except ValueError:
# e.g. node.value is white space
pass
except astroid.AstroidSyntaxError:
# e.g. "?" or ":" in typing.Literal["?", ":"]
pass


def register(linter: PyLinter) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def example3(_: "os.PathLike[str]") -> None:
def example4(_: "PathLike[str]") -> None:
"""unused-import shouldn't be emitted for PathLike."""

# pylint shouldn't crash with the following strings in a type annotation context
example5: Set[""]
lggruspe marked this conversation as resolved.
Show resolved Hide resolved
example6: Set[" "]
example7: Set["?"]

class Class:
"""unused-import shouldn't be emitted for Namespace"""
cls: "Namespace"
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

from argparse import ArgumentParser # [unused-import]
from argparse import Namespace # [unused-import]
from typing import Literal as Lit
import http # [unused-import]
from http import HTTPStatus
import typing as t
from typing import Literal as Lit

# str inside Literal shouldn't be treated as names
example1: t.Literal["ArgumentParser", Lit["Namespace", "ArgumentParser"]]
Expand All @@ -18,3 +20,8 @@ def unused_variable_example():

# pylint shouldn't crash with the following strings in a type annotation context
example3: Lit["", " ", "?"] = "?"


# See https://peps.python.org/pep-0586/#literals-enums-and-forward-references
example4: t.Literal["http.HTTPStatus.OK", "http.HTTPStatus.NOT_FOUND"]
example5: "t.Literal[HTTPStatus.OK, HTTPStatus.NOT_FOUND]"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
unused-import:3:0:3:35::Unused ArgumentParser imported from argparse:UNDEFINED
unused-import:4:0:4:30::Unused Namespace imported from argparse:UNDEFINED
unused-variable:13:4:13:9:unused_variable_example:Unused variable 'hello':UNDEFINED
unused-variable:14:4:14:9:unused_variable_example:Unused variable 'world':UNDEFINED
unused-import:5:0:5:11::Unused import http:UNDEFINED
unused-variable:15:4:15:9:unused_variable_example:Unused variable 'hello':UNDEFINED
unused-variable:16:4:16:9:unused_variable_example:Unused variable 'world':UNDEFINED