Skip to content

Commit

Permalink
Merge branch 'use_primitive_types_branch' of https://github.com/Insta…
Browse files Browse the repository at this point in the history
…gram/Fixit into use_primitive_types_branch
  • Loading branch information
Anuar Navarro Hawach committed Aug 21, 2024
2 parents a26fbde + 4b2a33a commit 23fc8fd
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 162 deletions.
43 changes: 43 additions & 0 deletions docs/guide/builtins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Built-in Rules
- :class:`UseAssertIn`
- :class:`UseAssertIsNotNone`
- :class:`UseAsyncSleepInAsyncDef`
- :class:`UseBuiltInsTypes`
- :class:`UseClsInClassmethod`
- :class:`UseFstring`
- :class:`UseTypesFromTyping`
Expand Down Expand Up @@ -1007,6 +1008,48 @@ Built-in Rules
from time import sleep
async def func():
sleep(1)
.. class:: UseBuiltInsTypes

Enforces the use of built-in types in type annotations in place
of `typing.{typing_type}` for simplicity and consistency.

.. attribute:: AUTOFIX
:type: Yes

.. attribute:: PYTHON_VERSION
:type: '>= 3.10'

.. attribute:: VALID

.. code:: python
def function(list: list[str]) -> None:
pass
.. code:: python
def function() -> None:
thing: dict[str, str] = {}
.. attribute:: INVALID

.. code:: python
def function(list: List[str]) -> None:
pass
# suggested fix
def function(list: list[str]) -> None:
pass
.. code:: python
def func() -> None:
thing: Dict[str, str] = {}
# suggested fix
def func() -> None:
thing: dict[str, str] = {}
.. class:: UseClsInClassmethod

Enforces using ``cls`` as the first argument in a ``@classmethod``.
Expand Down
2 changes: 1 addition & 1 deletion src/fixit/rules/no_namedtuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def leave_ClassDef(self, original_node: cst.ClassDef) -> None:

def partition_bases(
self, original_bases: Sequence[cst.Arg]
) -> tuple[Optional[cst.Arg], List[cst.Arg]]:
) -> Tuple[Optional[cst.Arg], List[cst.Arg]]:
# Returns a tuple of NamedTuple base object if it exists, and a list of non-NamedTuple bases
namedtuple_base: Optional[cst.Arg] = None
new_bases: List[cst.Arg] = []
Expand Down
123 changes: 123 additions & 0 deletions src/fixit/rules/use_builtins_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

from typing import Set

import libcst
from libcst.metadata import QualifiedNameProvider

from fixit import Invalid, LintRule, Valid

REPLACE_TYPING_TYPE_ANNOTATION: str = (
"You are using typing.{typing_type} as a type annotation "
+ "but you should use builtins.{builtin_type} instead."
)

TYPING_TO_BUILTINS: Set[str] = {"List", "Dict", "Set", "Tuple"}
QUALIFIED_TYPING_TO_BUILTINS: Set[str] = {f"typing.{s}" for s in TYPING_TO_BUILTINS}

class UseBuiltInsTypes(LintRule):
"""
Enforces the use of built-in types in type annotations in place
of `typing.{typing_type}` for simplicity and consistency.
"""

PYTHON_VERSION = ">= 3.10"

METADATA_DEPENDENCIES = (
QualifiedNameProvider,
)

VALID = [
Valid(
"""
def function(list: list[str]) -> None:
pass
"""
),
Valid(
"""
def function() -> None:
thing: dict[str, str] = {}
"""
),
Valid(
"""
def function() -> None:
thing: tuple[str]
"""
),
]

INVALID = [
Invalid(
"""
def function(list: List[str]) -> None:
pass
""",
expected_replacement="""
def function(list: list[str]) -> None:
pass
""",
),
Invalid(
"""
def func() -> None:
thing: Dict[str, str] = {}
""",
expected_replacement="""
def func() -> None:
thing: dict[str, str] = {}
""",
),
Invalid(
"""
def function(list: list[str]) -> List[str]:
pass
""",
expected_replacement="""
def function(list: list[str]) -> list[str]:
pass
""",
),
Invalid(
"""
def func() -> None:
thing: Tuple[str]
""",
expected_replacement="""
def func() -> None:
thing: tuple[str]
""",
),
]

def __init__(self) -> None:
super().__init__()
self.annotation_counter: int = 0

def visit_Annotation(self, node: libcst.Annotation) -> None:
self.annotation_counter += 1

def leave_Annotation(self, original_node: libcst.Annotation) -> None:
self.annotation_counter -= 1

def visit_Name(self, node: libcst.Name) -> None:
qualified_names = self.get_metadata(QualifiedNameProvider, node, set())

is_typing_type = node.value in TYPING_TO_BUILTINS and all(
qualified_name.name in QUALIFIED_TYPING_TO_BUILTINS
for qualified_name in qualified_names
)

if self.annotation_counter > 0 and is_typing_type:
builtin_type = node.value.lower()
self.report(
node,
REPLACE_TYPING_TYPE_ANNOTATION.format(
typing_type=node.value, builtin_type=builtin_type
),
replacement=node.with_changes(value=builtin_type),
)
161 changes: 0 additions & 161 deletions src/fixit/rules/use_primitive_types.py

This file was deleted.

0 comments on commit 23fc8fd

Please sign in to comment.