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 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 13 additions & 11 deletions pylint/checkers/variables.py
Expand Up @@ -2919,16 +2919,6 @@ 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
Expand All @@ -2940,7 +2930,19 @@ def visit_const(self, node: nodes.Const) -> None:
if origin is not None and utils.is_typing_literal(origin):
return

self._type_annotation_names.append(node.value)
if node.value.isidentifier():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why you moved this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the is_typing_literal part up to stop checking for names if the string node is an arg to Literal. As for the isidentifier check, it's probably not needed anymore. I'll push some more changes.

self._type_annotation_names.append(node.value)
return

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
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"
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]
lggruspe marked this conversation as resolved.
Show resolved Hide resolved
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]"
@@ -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