Skip to content

Commit 22eb0c1

Browse files
authored
Handle multi-line annotations correctly (#118)
1 parent 3f40d2a commit 22eb0c1

File tree

2 files changed

+83
-23
lines changed

2 files changed

+83
-23
lines changed

auto_typing_final/transform.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ def _match_exact_identifier(node: SgNode, imports_result: ImportsResult, identif
115115
return None
116116

117117

118-
def _strip_identifier_from_type_annotation( # noqa: C901, PLR0911
118+
def _strip_value_from_type_annotation_that_is_indeed_inside_given_identifier(
119119
node: SgNode, imports_result: ImportsResult, identifier_name: str
120-
) -> tuple[str, str] | None:
120+
) -> str | None:
121121
type_node_children: Final = node.children()
122122
if len(type_node_children) != 1:
123123
return None
@@ -127,55 +127,54 @@ def _strip_identifier_from_type_annotation( # noqa: C901, PLR0911
127127
if kind == "subscript":
128128
match tuple((child.kind(), child) for child in inner_type_node.children()):
129129
case (("attribute", attribute), ("[", _), *kinds_and_nodes, ("]", _)):
130-
if existing_final := _match_exact_identifier(attribute, imports_result, identifier_name):
131-
return existing_final, "".join(node.text() for _, node in kinds_and_nodes)
130+
if _match_exact_identifier(attribute, imports_result, identifier_name):
131+
return "".join(node.text() for _, node in kinds_and_nodes)
132132
elif kind == "generic_type" and imports_result.has_from_import:
133133
match tuple((child.kind(), child) for child in inner_type_node.children()):
134134
case (("identifier", identifier), ("type_parameter", type_parameter)):
135135
if identifier.text() != identifier_name:
136136
return None
137137
match tuple((inner_child.kind(), inner_child) for inner_child in type_parameter.children()):
138138
case (("[", _), *kinds_and_nodes, ("]", _)):
139-
return identifier_name, "".join(node.text() for _, node in kinds_and_nodes)
140-
elif kind == "identifier" and inner_type_node.text() == identifier_name:
141-
return identifier_name, ""
142-
elif kind == "attribute" and (
143-
existing_final := _match_exact_identifier(inner_type_node, imports_result, identifier_name)
139+
return "".join(node.text() for _, node in kinds_and_nodes)
140+
elif (kind == "identifier" and inner_type_node.text() == identifier_name) or (
141+
kind == "attribute" and _match_exact_identifier(inner_type_node, imports_result, identifier_name)
144142
):
145-
return existing_final, ""
143+
return ""
146144
return None
147145

148146

149-
def _make_changed_text_from_operation( # noqa: C901
147+
def _make_changed_text_from_operation(
150148
operation: Operation, final_value: str, imports_result: ImportsResult, identifier_name: str
151149
) -> Iterable[tuple[SgNode, str]]:
152150
match operation:
153151
case AddFinal(assignment):
154152
match assignment:
155153
case EditableAssignmentWithoutAnnotation(node, left, right):
156154
yield node, f"{left}: {final_value} = {right}"
157-
case EditableAssignmentWithAnnotation(node, left, annotation, right):
158-
match _strip_identifier_from_type_annotation(annotation, imports_result, identifier_name):
159-
case None:
160-
yield node, f"{left}: {final_value}[{annotation.text()}] = {right}"
161-
case existing_final, "":
162-
yield node, f"{left}: {existing_final} = {right}"
163-
case existing_final, new_annotation:
164-
yield node, f"{left}: {existing_final}[{new_annotation}] = {right}"
165-
155+
case EditableAssignmentWithAnnotation(node, left, annotation, right) if (
156+
_strip_value_from_type_annotation_that_is_indeed_inside_given_identifier(
157+
annotation, imports_result, identifier_name
158+
)
159+
is None
160+
):
161+
yield node, f"{left}: {final_value}[{annotation.text()}] = {right}"
166162
case RemoveFinal(assignments):
167163
for assignment in assignments:
168164
match assignment:
169165
case EditableAssignmentWithoutAnnotation(node, left, right):
170166
yield node, node.text()
171167
case EditableAssignmentWithAnnotation(node, left, annotation, right):
172-
match _strip_identifier_from_type_annotation(annotation, imports_result, identifier_name):
173-
case _, "":
168+
match _strip_value_from_type_annotation_that_is_indeed_inside_given_identifier(
169+
annotation, imports_result, identifier_name
170+
):
171+
case "":
174172
yield node, f"{left} = {right}"
175-
case _, new_annotation:
173+
case str(new_annotation):
176174
yield node, f"{left}: {new_annotation} = {right}"
177175

178176

177+
# TODO: make dataclasses frozen and all other stuff # noqa: FIX002, TD002, TD003
179178
@dataclass
180179
class Edit:
181180
node: SgNode

tests/test_main.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,67 @@ def f():
779779
a = 1
780780
a = 2
781781
b: Final = 1
782+
""",
783+
IMPORT_STYLES_TO_IMPORT_CONFIGS["final"],
784+
),
785+
(
786+
"""
787+
from typing import Final
788+
789+
def f():
790+
a: Final[
791+
int
792+
] = 1
793+
---
794+
from typing import Final
795+
796+
def f():
797+
a: Final[
798+
int
799+
] = 1
800+
""",
801+
IMPORT_STYLES_TO_IMPORT_CONFIGS["final"],
802+
),
803+
(
804+
"""
805+
from typing import Annotated
806+
807+
def f():
808+
a: Annotated[
809+
int,
810+
"hello",
811+
] = 1
812+
a = 2
813+
---
814+
from typing import Annotated
815+
816+
def f():
817+
a: Annotated[
818+
int,
819+
"hello",
820+
] = 1
821+
a = 2
822+
""",
823+
IMPORT_STYLES_TO_IMPORT_CONFIGS["final"],
824+
),
825+
(
826+
"""
827+
from typing import Annotated
828+
829+
def f():
830+
a: Annotated[
831+
int,
832+
"hello"
833+
] = 1
834+
---
835+
from typing import Final
836+
from typing import Annotated
837+
838+
def f():
839+
a: Final[Annotated[
840+
int,
841+
"hello"
842+
]] = 1
782843
""",
783844
IMPORT_STYLES_TO_IMPORT_CONFIGS["final"],
784845
),

0 commit comments

Comments
 (0)