Skip to content

Commit e189246

Browse files
committed
Add Try node
1 parent 1336ee4 commit e189246

File tree

12 files changed

+135
-182
lines changed

12 files changed

+135
-182
lines changed

ChangeLog

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

100100
Refs #2141
101101

102+
* Add new ``nodes.Try`` to better match Python AST. Replaces the ``TryExcept``
103+
and ``TryFinally`` nodes which have been removed.
104+
102105

103106
What's New in astroid 2.15.4?
104107
=============================

astroid/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,7 @@
161161
Slice,
162162
Starred,
163163
Subscript,
164-
TryExcept,
165-
TryFinally,
164+
Try,
166165
Tuple,
167166
UnaryOp,
168167
Unknown,

astroid/inference.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ def infer_functiondef(
12601260
isinstance(val, objects.Property) for val in parent_frame.locals[self.name]
12611261
)
12621262
# We also don't want to pass parent if the definition is within a Try node
1263-
if isinstance(self.parent, (nodes.TryExcept, nodes.TryFinally, nodes.If)):
1263+
if isinstance(self.parent, (nodes.Try, nodes.If)):
12641264
property_already_in_parent_locals = True
12651265

12661266
prop_func = objects.Property(

astroid/node_classes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@
7474
Slice,
7575
Starred,
7676
Subscript,
77-
TryExcept,
78-
TryFinally,
77+
Try,
7978
Tuple,
8079
UnaryOp,
8180
Unknown,

astroid/nodes/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@
8282
Slice,
8383
Starred,
8484
Subscript,
85-
TryExcept,
86-
TryFinally,
85+
Try,
8786
TryStar,
8887
Tuple,
8988
UnaryOp,
@@ -195,8 +194,7 @@
195194
Slice,
196195
Starred,
197196
Subscript,
198-
TryExcept,
199-
TryFinally,
197+
Try,
200198
Tuple,
201199
UnaryOp,
202200
Unknown,
@@ -289,8 +287,7 @@
289287
"Starred",
290288
"Statement",
291289
"Subscript",
292-
"TryExcept",
293-
"TryFinally",
290+
"Try",
294291
"Tuple",
295292
"UnaryOp",
296293
"Unknown",

astroid/nodes/as_string.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from typing import TYPE_CHECKING
1111

1212
if TYPE_CHECKING:
13+
from astroid import nodes
1314
from astroid.nodes import Const
1415
from astroid.nodes.node_classes import (
1516
Match,
@@ -480,21 +481,17 @@ def visit_subscript(self, node) -> str:
480481
idxstr = idxstr[1:-1]
481482
return f"{self._precedence_parens(node, node.value)}[{idxstr}]"
482483

483-
def visit_tryexcept(self, node) -> str:
484-
"""return an astroid.TryExcept node as string"""
484+
def visit_try(self, node: nodes.Try) -> str:
485+
"""return an astroid.Try node as string"""
485486
trys = [f"try:\n{self._stmt_list(node.body)}"]
486487
for handler in node.handlers:
487488
trys.append(handler.accept(self))
488489
if node.orelse:
489490
trys.append(f"else:\n{self._stmt_list(node.orelse)}")
491+
if node.finalbody:
492+
trys.append(f"finally:\n{self._stmt_list(node.finalbody)}")
490493
return "\n".join(trys)
491494

492-
def visit_tryfinally(self, node) -> str:
493-
"""return an astroid.TryFinally node as string"""
494-
return "try:\n{}\nfinally:\n{}".format(
495-
self._stmt_list(node.body), self._stmt_list(node.finalbody)
496-
)
497-
498495
def visit_tuple(self, node) -> str:
499496
"""return an astroid.Tuple node as string"""
500497
if len(node.elts) == 1:

astroid/nodes/node_classes.py

Lines changed: 61 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def are_exclusive(stmt1, stmt2, exceptions: list[str] | None = None) -> bool:
132132
previous = stmt2
133133
for node in stmt2.node_ancestors():
134134
if node in stmt1_parents:
135-
# if the common parent is a If or TryExcept statement, look if
135+
# if the common parent is a If or Try statement, look if
136136
# nodes are in exclusive branches
137137
if isinstance(node, If) and exceptions is None:
138138
c2attr, c2node = node.locate_child(previous)
@@ -144,7 +144,7 @@ def are_exclusive(stmt1, stmt2, exceptions: list[str] | None = None) -> bool:
144144
if c1attr != c2attr:
145145
# different `If` branches (`If.body` and `If.orelse`)
146146
return True
147-
elif isinstance(node, TryExcept):
147+
elif isinstance(node, Try):
148148
c2attr, c2node = node.locate_child(previous)
149149
c1attr, c1node = node.locate_child(children[node])
150150
if c1node is not c2node:
@@ -3110,97 +3110,33 @@ def get_children(self):
31103110
yield self.slice
31113111

31123112

3113-
class TryExcept(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3114-
"""Class representing an :class:`ast.TryExcept` node.
3113+
class Try(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3114+
"""Class representing a :class:`ast.Try` node.
31153115
31163116
>>> import astroid
31173117
>>> node = astroid.extract_node('''
31183118
try:
31193119
do_something()
31203120
except Exception as error:
31213121
print("Error!")
3122+
finally:
3123+
print("Cleanup!")
31223124
''')
31233125
>>> node
3124-
<TryExcept l.2 at 0x7f23b2e9d908>
3126+
<Try l.2 at 0x7f23b2e41d68>
31253127
"""
31263128

3127-
_astroid_fields = ("body", "handlers", "orelse")
3128-
_multi_line_block_fields = ("body", "handlers", "orelse")
3129-
3130-
body: list[NodeNG]
3131-
"""The contents of the block to catch exceptions from."""
3132-
3133-
handlers: list[ExceptHandler]
3134-
"""The exception handlers."""
3135-
3136-
orelse: list[NodeNG]
3137-
"""The contents of the ``else`` block."""
3138-
3139-
def postinit(
3140-
self,
3141-
body: list[NodeNG],
3142-
handlers: list[ExceptHandler],
3143-
orelse: list[NodeNG],
3144-
) -> None:
3145-
self.body = body
3146-
self.handlers = handlers
3147-
self.orelse = orelse
3148-
3149-
def _infer_name(self, frame, name):
3150-
return name
3151-
3152-
def block_range(self, lineno: int) -> tuple[int, int]:
3153-
"""Get a range from the given line number to where this node ends.
3154-
3155-
:param lineno: The line number to start the range at.
3156-
3157-
:returns: The range of line numbers that this node belongs to,
3158-
starting at the given line number.
3159-
"""
3160-
last = None
3161-
for exhandler in self.handlers:
3162-
if exhandler.type and lineno == exhandler.type.fromlineno:
3163-
return lineno, lineno
3164-
if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3165-
return lineno, exhandler.body[-1].tolineno
3166-
if last is None:
3167-
last = exhandler.body[0].fromlineno - 1
3168-
return self._elsed_block_range(lineno, self.orelse, last)
3169-
3170-
def get_children(self):
3171-
yield from self.body
3172-
3173-
yield from self.handlers or ()
3174-
yield from self.orelse or ()
3175-
3176-
3177-
class TryFinally(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3178-
"""Class representing an :class:`ast.TryFinally` node.
3179-
3180-
>>> import astroid
3181-
>>> node = astroid.extract_node('''
3182-
try:
3183-
do_something()
3184-
except Exception as error:
3185-
print("Error!")
3186-
finally:
3187-
print("Cleanup!")
3188-
''')
3189-
>>> node
3190-
<TryFinally l.2 at 0x7f23b2e41d68>
3191-
"""
3192-
3193-
_astroid_fields = ("body", "finalbody")
3194-
_multi_line_block_fields = ("body", "finalbody")
3129+
_astroid_fields = ("body", "handlers", "orelse", "finalbody")
3130+
_multi_line_block_fields = ("body", "handlers", "orelse", "finalbody")
31953131

31963132
def __init__(
31973133
self,
3134+
*,
31983135
lineno: int | None = None,
31993136
col_offset: int | None = None,
3200-
parent: NodeNG | None = None,
3201-
*,
32023137
end_lineno: int | None = None,
32033138
end_col_offset: int | None = None,
3139+
parent: NodeNG | None = None,
32043140
) -> None:
32053141
"""
32063142
:param lineno: The line that this node appears on in the source code.
@@ -3215,8 +3151,14 @@ def __init__(
32153151
:param end_col_offset: The end column this node appears on in the
32163152
source code. Note: This is after the last symbol.
32173153
"""
3218-
self.body: list[NodeNG | TryExcept] = []
3219-
"""The try-except that the finally is attached to."""
3154+
self.body: list[NodeNG] = []
3155+
"""The contents of the block to catch exceptions from."""
3156+
3157+
self.handlers: list[ExceptHandler] = []
3158+
"""The exception handlers."""
3159+
3160+
self.orelse: list[NodeNG] = []
3161+
"""The contents of the ``else`` block."""
32203162

32213163
self.finalbody: list[NodeNG] = []
32223164
"""The contents of the ``finally`` block."""
@@ -3231,40 +3173,62 @@ def __init__(
32313173

32323174
def postinit(
32333175
self,
3234-
body: list[NodeNG | TryExcept] | None = None,
3176+
*,
3177+
body: list[NodeNG] | None = None,
3178+
handlers: list[ExceptHandler] | None = None,
3179+
orelse: list[NodeNG] | None = None,
32353180
finalbody: list[NodeNG] | None = None,
32363181
) -> None:
32373182
"""Do some setup after initialisation.
32383183
3239-
:param body: The try-except that the finally is attached to.
3184+
:param body: The contents of the block to catch exceptions from.
3185+
3186+
:param handlers: The exception handlers.
3187+
3188+
:param orelse: The contents of the ``else`` block.
32403189
32413190
:param finalbody: The contents of the ``finally`` block.
32423191
"""
3243-
if body is not None:
3192+
if body:
32443193
self.body = body
3245-
if finalbody is not None:
3194+
if handlers:
3195+
self.handlers = handlers
3196+
if orelse:
3197+
self.orelse = orelse
3198+
if finalbody:
32463199
self.finalbody = finalbody
32473200

3248-
def block_range(self, lineno: int) -> tuple[int, int]:
3249-
"""Get a range from the given line number to where this node ends.
3250-
3251-
:param lineno: The line number to start the range at.
3201+
def _infer_name(self, frame, name):
3202+
return name
32523203

3253-
:returns: The range of line numbers that this node belongs to,
3254-
starting at the given line number.
3255-
"""
3256-
child = self.body[0]
3257-
# py2.5 try: except: finally:
3258-
if (
3259-
isinstance(child, TryExcept)
3260-
and child.fromlineno == self.fromlineno
3261-
and child.tolineno >= lineno > self.fromlineno
3262-
):
3263-
return child.block_range(lineno)
3264-
return self._elsed_block_range(lineno, self.finalbody)
3204+
def block_range(self, lineno: int) -> tuple[int, int]:
3205+
"""Get a range from a given line number to where this node ends."""
3206+
if lineno == self.fromlineno:
3207+
return lineno, lineno
3208+
if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno:
3209+
# Inside try body - return from lineno till end of try body
3210+
return lineno, self.body[-1].tolineno
3211+
for exhandler in self.handlers:
3212+
if exhandler.type and lineno == exhandler.type.fromlineno:
3213+
return lineno, lineno
3214+
if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3215+
return lineno, exhandler.body[-1].tolineno
3216+
if self.orelse:
3217+
if self.orelse[0].fromlineno - 1 == lineno:
3218+
return lineno, lineno
3219+
if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno:
3220+
return lineno, self.orelse[-1].tolineno
3221+
if self.finalbody:
3222+
if self.finalbody[0].fromlineno - 1 == lineno:
3223+
return lineno, lineno
3224+
if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno:
3225+
return lineno, self.finalbody[-1].tolineno
3226+
return lineno, self.tolineno
32653227

32663228
def get_children(self):
32673229
yield from self.body
3230+
yield from self.handlers
3231+
yield from self.orelse
32683232
yield from self.finalbody
32693233

32703234

astroid/nodes/node_ng.py

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

589589
def _infer_name(self, frame, name):
590-
# overridden for ImportFrom, Import, Global, TryExcept and Arguments
590+
# overridden for ImportFrom, Import, Global, Try, TryStar and Arguments
591591
pass
592592

593593
def _infer(

0 commit comments

Comments
 (0)