Skip to content

Commit e91a3b5

Browse files
Add Try node (#1867)
Co-authored-by: Jacob Walls <[email protected]>
1 parent a7ab088 commit e91a3b5

File tree

12 files changed

+135
-187
lines changed

12 files changed

+135
-187
lines changed

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ Release date: TBA
183183

184184
Refs #2154
185185

186+
* Add new ``nodes.Try`` to better match Python AST. Replaces the ``TryExcept``
187+
and ``TryFinally`` nodes which have been removed.
188+
186189
* Publicize ``NodeNG.repr_name()`` to facilitate finding a node's nice name.
187190

188191
Refs pylint-dev/pylint#8598

astroid/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@
155155
Slice,
156156
Starred,
157157
Subscript,
158-
TryExcept,
159-
TryFinally,
158+
Try,
160159
TryStar,
161160
Tuple,
162161
UnaryOp,

astroid/node_classes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@
7070
Slice,
7171
Starred,
7272
Subscript,
73-
TryExcept,
74-
TryFinally,
73+
Try,
7574
TryStar,
7675
Tuple,
7776
UnaryOp,

astroid/nodes/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@
7676
Slice,
7777
Starred,
7878
Subscript,
79-
TryExcept,
80-
TryFinally,
79+
Try,
8180
TryStar,
8281
Tuple,
8382
TypeAlias,
@@ -188,8 +187,7 @@
188187
Slice,
189188
Starred,
190189
Subscript,
191-
TryExcept,
192-
TryFinally,
190+
Try,
193191
TryStar,
194192
Tuple,
195193
TypeAlias,
@@ -283,8 +281,7 @@
283281
"Slice",
284282
"Starred",
285283
"Subscript",
286-
"TryExcept",
287-
"TryFinally",
284+
"Try",
288285
"TryStar",
289286
"Tuple",
290287
"TypeAlias",

astroid/nodes/as_string.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -491,21 +491,17 @@ def visit_subscript(self, node) -> str:
491491
idxstr = idxstr[1:-1]
492492
return f"{self._precedence_parens(node, node.value)}[{idxstr}]"
493493

494-
def visit_tryexcept(self, node) -> str:
495-
"""return an astroid.TryExcept node as string"""
494+
def visit_try(self, node) -> str:
495+
"""return an astroid.Try node as string"""
496496
trys = [f"try:\n{self._stmt_list(node.body)}"]
497497
for handler in node.handlers:
498498
trys.append(handler.accept(self))
499499
if node.orelse:
500500
trys.append(f"else:\n{self._stmt_list(node.orelse)}")
501+
if node.finalbody:
502+
trys.append(f"finally:\n{self._stmt_list(node.finalbody)}")
501503
return "\n".join(trys)
502504

503-
def visit_tryfinally(self, node) -> str:
504-
"""return an astroid.TryFinally node as string"""
505-
return "try:\n{}\nfinally:\n{}".format(
506-
self._stmt_list(node.body), self._stmt_list(node.finalbody)
507-
)
508-
509505
def visit_trystar(self, node) -> str:
510506
"""return an astroid.TryStar node as string"""
511507
trys = [f"try:\n{self._stmt_list(node.body)}"]

astroid/nodes/node_classes.py

Lines changed: 63 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def are_exclusive(stmt1, stmt2, exceptions: list[str] | None = None) -> bool:
143143
previous = stmt2
144144
for node in stmt2.node_ancestors():
145145
if node in stmt1_parents:
146-
# if the common parent is a If or TryExcept statement, look if
146+
# if the common parent is a If or Try statement, look if
147147
# nodes are in exclusive branches
148148
if isinstance(node, If) and exceptions is None:
149149
c2attr, c2node = node.locate_child(previous)
@@ -155,7 +155,7 @@ def are_exclusive(stmt1, stmt2, exceptions: list[str] | None = None) -> bool:
155155
if c1attr != c2attr:
156156
# different `If` branches (`If.body` and `If.orelse`)
157157
return True
158-
elif isinstance(node, TryExcept):
158+
elif isinstance(node, Try):
159159
c2attr, c2node = node.locate_child(previous)
160160
c1attr, c1node = node.locate_child(children[node])
161161
if c1node is not c2node:
@@ -3720,97 +3720,33 @@ def infer_lhs(self, context: InferenceContext | None = None, **kwargs: Any):
37203720
return self._infer_subscript(context, **kwargs)
37213721

37223722

3723-
class TryExcept(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3724-
"""Class representing an :class:`ast.TryExcept` node.
3723+
class Try(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3724+
"""Class representing a :class:`ast.Try` node.
37253725
37263726
>>> import astroid
37273727
>>> node = astroid.extract_node('''
37283728
try:
37293729
do_something()
37303730
except Exception as error:
37313731
print("Error!")
3732+
finally:
3733+
print("Cleanup!")
37323734
''')
37333735
>>> node
3734-
<TryExcept l.2 at 0x7f23b2e9d908>
3736+
<Try l.2 at 0x7f23b2e41d68>
37353737
"""
37363738

3737-
_astroid_fields = ("body", "handlers", "orelse")
3738-
_multi_line_block_fields = ("body", "handlers", "orelse")
3739-
3740-
body: list[NodeNG]
3741-
"""The contents of the block to catch exceptions from."""
3742-
3743-
handlers: list[ExceptHandler]
3744-
"""The exception handlers."""
3745-
3746-
orelse: list[NodeNG]
3747-
"""The contents of the ``else`` block."""
3748-
3749-
def postinit(
3750-
self,
3751-
body: list[NodeNG],
3752-
handlers: list[ExceptHandler],
3753-
orelse: list[NodeNG],
3754-
) -> None:
3755-
self.body = body
3756-
self.handlers = handlers
3757-
self.orelse = orelse
3758-
3759-
def _infer_name(self, frame, name):
3760-
return name
3761-
3762-
def block_range(self, lineno: int) -> tuple[int, int]:
3763-
"""Get a range from the given line number to where this node ends.
3764-
3765-
:param lineno: The line number to start the range at.
3766-
3767-
:returns: The range of line numbers that this node belongs to,
3768-
starting at the given line number.
3769-
"""
3770-
last = None
3771-
for exhandler in self.handlers:
3772-
if exhandler.type and lineno == exhandler.type.fromlineno:
3773-
return lineno, lineno
3774-
if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3775-
return lineno, exhandler.body[-1].tolineno
3776-
if last is None:
3777-
last = exhandler.body[0].fromlineno - 1
3778-
return self._elsed_block_range(lineno, self.orelse, last)
3779-
3780-
def get_children(self):
3781-
yield from self.body
3782-
3783-
yield from self.handlers or ()
3784-
yield from self.orelse or ()
3785-
3786-
3787-
class TryFinally(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3788-
"""Class representing an :class:`ast.TryFinally` node.
3789-
3790-
>>> import astroid
3791-
>>> node = astroid.extract_node('''
3792-
try:
3793-
do_something()
3794-
except Exception as error:
3795-
print("Error!")
3796-
finally:
3797-
print("Cleanup!")
3798-
''')
3799-
>>> node
3800-
<TryFinally l.2 at 0x7f23b2e41d68>
3801-
"""
3802-
3803-
_astroid_fields = ("body", "finalbody")
3804-
_multi_line_block_fields = ("body", "finalbody")
3739+
_astroid_fields = ("body", "handlers", "orelse", "finalbody")
3740+
_multi_line_block_fields = ("body", "handlers", "orelse", "finalbody")
38053741

38063742
def __init__(
38073743
self,
3808-
lineno: int | None = None,
3809-
col_offset: int | None = None,
3810-
parent: NodeNG | None = None,
38113744
*,
3812-
end_lineno: int | None = None,
3813-
end_col_offset: int | None = None,
3745+
lineno: int,
3746+
col_offset: int,
3747+
end_lineno: int,
3748+
end_col_offset: int,
3749+
parent: NodeNG,
38143750
) -> None:
38153751
"""
38163752
:param lineno: The line that this node appears on in the source code.
@@ -3825,8 +3761,14 @@ def __init__(
38253761
:param end_col_offset: The end column this node appears on in the
38263762
source code. Note: This is after the last symbol.
38273763
"""
3828-
self.body: list[NodeNG | TryExcept] = []
3829-
"""The try-except that the finally is attached to."""
3764+
self.body: list[NodeNG] = []
3765+
"""The contents of the block to catch exceptions from."""
3766+
3767+
self.handlers: list[ExceptHandler] = []
3768+
"""The exception handlers."""
3769+
3770+
self.orelse: list[NodeNG] = []
3771+
"""The contents of the ``else`` block."""
38303772

38313773
self.finalbody: list[NodeNG] = []
38323774
"""The contents of the ``finally`` block."""
@@ -3841,40 +3783,58 @@ def __init__(
38413783

38423784
def postinit(
38433785
self,
3844-
body: list[NodeNG | TryExcept] | None = None,
3845-
finalbody: list[NodeNG] | None = None,
3786+
*,
3787+
body: list[NodeNG],
3788+
handlers: list[ExceptHandler],
3789+
orelse: list[NodeNG],
3790+
finalbody: list[NodeNG],
38463791
) -> None:
38473792
"""Do some setup after initialisation.
38483793
3849-
:param body: The try-except that the finally is attached to.
3794+
:param body: The contents of the block to catch exceptions from.
3795+
3796+
:param handlers: The exception handlers.
3797+
3798+
:param orelse: The contents of the ``else`` block.
38503799
38513800
:param finalbody: The contents of the ``finally`` block.
38523801
"""
3853-
if body is not None:
3854-
self.body = body
3855-
if finalbody is not None:
3856-
self.finalbody = finalbody
3857-
3858-
def block_range(self, lineno: int) -> tuple[int, int]:
3859-
"""Get a range from the given line number to where this node ends.
3802+
self.body = body
3803+
self.handlers = handlers
3804+
self.orelse = orelse
3805+
self.finalbody = finalbody
38603806

3861-
:param lineno: The line number to start the range at.
3807+
def _infer_name(self, frame, name):
3808+
return name
38623809

3863-
:returns: The range of line numbers that this node belongs to,
3864-
starting at the given line number.
3865-
"""
3866-
child = self.body[0]
3867-
# py2.5 try: except: finally:
3868-
if (
3869-
isinstance(child, TryExcept)
3870-
and child.fromlineno == self.fromlineno
3871-
and child.tolineno >= lineno > self.fromlineno
3872-
):
3873-
return child.block_range(lineno)
3874-
return self._elsed_block_range(lineno, self.finalbody)
3810+
def block_range(self, lineno: int) -> tuple[int, int]:
3811+
"""Get a range from a given line number to where this node ends."""
3812+
if lineno == self.fromlineno:
3813+
return lineno, lineno
3814+
if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno:
3815+
# Inside try body - return from lineno till end of try body
3816+
return lineno, self.body[-1].tolineno
3817+
for exhandler in self.handlers:
3818+
if exhandler.type and lineno == exhandler.type.fromlineno:
3819+
return lineno, lineno
3820+
if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3821+
return lineno, exhandler.body[-1].tolineno
3822+
if self.orelse:
3823+
if self.orelse[0].fromlineno - 1 == lineno:
3824+
return lineno, lineno
3825+
if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno:
3826+
return lineno, self.orelse[-1].tolineno
3827+
if self.finalbody:
3828+
if self.finalbody[0].fromlineno - 1 == lineno:
3829+
return lineno, lineno
3830+
if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno:
3831+
return lineno, self.finalbody[-1].tolineno
3832+
return lineno, self.tolineno
38753833

38763834
def get_children(self):
38773835
yield from self.body
3836+
yield from self.handlers
3837+
yield from self.orelse
38783838
yield from self.finalbody
38793839

38803840

astroid/nodes/node_ng.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ def _get_yield_nodes_skip_lambdas(self):
573573
yield from ()
574574

575575
def _infer_name(self, frame, name):
576-
# overridden for ImportFrom, Import, Global, TryExcept, TryStar and Arguments
576+
# overridden for ImportFrom, Import, Global, Try, TryStar and Arguments
577577
pass
578578

579579
def _infer(

astroid/nodes/scoped_nodes/scoped_nodes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ def _infer(
15311531
# We also don't want to pass parent if the definition is within a Try node
15321532
if isinstance(
15331533
self.parent,
1534-
(node_classes.TryExcept, node_classes.TryFinally, node_classes.If),
1534+
(node_classes.Try, node_classes.If),
15351535
):
15361536
property_already_in_parent_locals = True
15371537

0 commit comments

Comments
 (0)