From 368bd1800bf256a72f5651e8e3d84e8b6765d985 Mon Sep 17 00:00:00 2001 From: Alex Lambert Date: Thu, 25 Mar 2021 10:37:07 -0400 Subject: [PATCH 1/2] Only change builtin types in `UseTypesFromTypingRule` *Problem* `UseTypesFromTypingRule` incorrectly changed `list` to `List` in this real-world snippet: ``` from typing import List as list from graphene import List def function(a: list[int]) -> List[int]: return [] ``` *Solution* Refine the check to confirm the node is a builtin --- fixit/rules/use_types_from_typing.py | 35 +++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/fixit/rules/use_types_from_typing.py b/fixit/rules/use_types_from_typing.py index b3d4d86a..2e52d272 100644 --- a/fixit/rules/use_types_from_typing.py +++ b/fixit/rules/use_types_from_typing.py @@ -6,7 +6,10 @@ from typing import Set import libcst -from libcst.metadata import ScopeProvider +from libcst.metadata import ( + QualifiedNameProvider, + ScopeProvider, +) from fixit import ( CstContext, @@ -23,6 +26,7 @@ ) BUILTINS_TO_REPLACE: Set[str] = {"dict", "list", "set", "tuple"} +QUALIFIED_BUILTINS_TO_REPLACE: Set[str] = {f"builtins.{s}" for s in BUILTINS_TO_REPLACE} class UseTypesFromTypingRule(CstLintRule): @@ -31,7 +35,10 @@ class UseTypesFromTypingRule(CstLintRule): since the type system doesn't recognize the latter as a valid type. """ - METADATA_DEPENDENCIES = (ScopeProvider,) + METADATA_DEPENDENCIES = ( + QualifiedNameProvider, + ScopeProvider, + ) VALID = [ Valid( """ @@ -58,6 +65,15 @@ def function() -> bool: return Dict == List """ ), + Valid( + """ + from typing import List as list + from graphene import List + + def function(a: list[int]) -> List[int]: + return [] + """ + ), ] INVALID = [ Invalid( @@ -115,7 +131,20 @@ def leave_Annotation(self, original_node: libcst.Annotation) -> None: self.annotation_counter -= 1 def visit_Name(self, node: libcst.Name) -> None: - if self.annotation_counter > 0 and node.value in BUILTINS_TO_REPLACE: + # Avoid a false-positive in this scenario: + # + # ``` + # from typing import List as list + # from graphene import List + # ``` + qualified_names = self.get_metadata(QualifiedNameProvider, node, set()) + + is_builtin_type = node.value in BUILTINS_TO_REPLACE and all( + qualified_name.name in QUALIFIED_BUILTINS_TO_REPLACE + for qualified_name in qualified_names + ) + + if self.annotation_counter > 0 and is_builtin_type: correct_type = node.value.title() scope = self.get_metadata(ScopeProvider, node) replacement = None From c9f4909230d8802a1d1115b65b29fb2ccb4915a7 Mon Sep 17 00:00:00 2001 From: Alex Lambert Date: Thu, 25 Mar 2021 11:57:18 -0400 Subject: [PATCH 2/2] formatting --- fixit/rules/use_types_from_typing.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fixit/rules/use_types_from_typing.py b/fixit/rules/use_types_from_typing.py index 2e52d272..a64d7f25 100644 --- a/fixit/rules/use_types_from_typing.py +++ b/fixit/rules/use_types_from_typing.py @@ -6,10 +6,7 @@ from typing import Set import libcst -from libcst.metadata import ( - QualifiedNameProvider, - ScopeProvider, -) +from libcst.metadata import QualifiedNameProvider, ScopeProvider from fixit import ( CstContext,