Skip to content

Commit 2568e58

Browse files
committed
Add Try node
1 parent 42f261d commit 2568e58

File tree

12 files changed

+133
-181
lines changed

12 files changed

+133
-181
lines changed

ChangeLog

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

135135
Refs #2154
136136

137+
* Add new ``nodes.Try`` to better match Python AST. Replaces the ``TryExcept``
138+
and ``TryFinally`` nodes which have been removed.
139+
137140

138141
What's New in astroid 2.15.5?
139142
=============================

astroid/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,7 @@
158158
Slice,
159159
Starred,
160160
Subscript,
161-
TryExcept,
162-
TryFinally,
161+
Try,
163162
TryStar,
164163
Tuple,
165164
UnaryOp,

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
@@ -71,8 +71,7 @@
7171
Slice,
7272
Starred,
7373
Subscript,
74-
TryExcept,
75-
TryFinally,
74+
Try,
7675
TryStar,
7776
Tuple,
7877
UnaryOp,

astroid/nodes/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@
7979
Slice,
8080
Starred,
8181
Subscript,
82-
TryExcept,
83-
TryFinally,
82+
Try,
8483
TryStar,
8584
Tuple,
8685
UnaryOp,
@@ -189,8 +188,7 @@
189188
Slice,
190189
Starred,
191190
Subscript,
192-
TryExcept,
193-
TryFinally,
191+
Try,
194192
TryStar,
195193
Tuple,
196194
UnaryOp,
@@ -281,8 +279,7 @@
281279
"Starred",
282280
"Statement",
283281
"Subscript",
284-
"TryExcept",
285-
"TryFinally",
282+
"Try",
286283
"TryStar",
287284
"Tuple",
288285
"UnaryOp",

astroid/nodes/as_string.py

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

488-
def visit_tryexcept(self, node) -> str:
489-
"""return an astroid.TryExcept node as string"""
488+
def visit_try(self, node) -> str:
489+
"""return an astroid.Try node as string"""
490490
trys = [f"try:\n{self._stmt_list(node.body)}"]
491491
for handler in node.handlers:
492492
trys.append(handler.accept(self))
493493
if node.orelse:
494494
trys.append(f"else:\n{self._stmt_list(node.orelse)}")
495+
if node.finalbody:
496+
trys.append(f"finally:\n{self._stmt_list(node.finalbody)}")
495497
return "\n".join(trys)
496498

497-
def visit_tryfinally(self, node) -> str:
498-
"""return an astroid.TryFinally node as string"""
499-
return "try:\n{}\nfinally:\n{}".format(
500-
self._stmt_list(node.body), self._stmt_list(node.finalbody)
501-
)
502-
503499
def visit_trystar(self, node) -> str:
504500
"""return an astroid.TryStar node as string"""
505501
trys = [f"try:\n{self._stmt_list(node.body)}"]

astroid/nodes/node_classes.py

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

30283028

3029-
class TryExcept(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3030-
"""Class representing an :class:`ast.TryExcept` node.
3029+
class Try(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3030+
"""Class representing a :class:`ast.Try` node.
30313031
30323032
>>> import astroid
30333033
>>> node = astroid.extract_node('''
30343034
try:
30353035
do_something()
30363036
except Exception as error:
30373037
print("Error!")
3038+
finally:
3039+
print("Cleanup!")
30383040
''')
30393041
>>> node
3040-
<TryExcept l.2 at 0x7f23b2e9d908>
3042+
<Try l.2 at 0x7f23b2e41d68>
30413043
"""
30423044

3043-
_astroid_fields = ("body", "handlers", "orelse")
3044-
_multi_line_block_fields = ("body", "handlers", "orelse")
3045-
3046-
body: list[NodeNG]
3047-
"""The contents of the block to catch exceptions from."""
3048-
3049-
handlers: list[ExceptHandler]
3050-
"""The exception handlers."""
3051-
3052-
orelse: list[NodeNG]
3053-
"""The contents of the ``else`` block."""
3054-
3055-
def postinit(
3056-
self,
3057-
body: list[NodeNG],
3058-
handlers: list[ExceptHandler],
3059-
orelse: list[NodeNG],
3060-
) -> None:
3061-
self.body = body
3062-
self.handlers = handlers
3063-
self.orelse = orelse
3064-
3065-
def _infer_name(self, frame, name):
3066-
return name
3067-
3068-
def block_range(self, lineno: int) -> tuple[int, int]:
3069-
"""Get a range from the given line number to where this node ends.
3070-
3071-
:param lineno: The line number to start the range at.
3072-
3073-
:returns: The range of line numbers that this node belongs to,
3074-
starting at the given line number.
3075-
"""
3076-
last = None
3077-
for exhandler in self.handlers:
3078-
if exhandler.type and lineno == exhandler.type.fromlineno:
3079-
return lineno, lineno
3080-
if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3081-
return lineno, exhandler.body[-1].tolineno
3082-
if last is None:
3083-
last = exhandler.body[0].fromlineno - 1
3084-
return self._elsed_block_range(lineno, self.orelse, last)
3085-
3086-
def get_children(self):
3087-
yield from self.body
3088-
3089-
yield from self.handlers or ()
3090-
yield from self.orelse or ()
3091-
3092-
3093-
class TryFinally(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3094-
"""Class representing an :class:`ast.TryFinally` node.
3095-
3096-
>>> import astroid
3097-
>>> node = astroid.extract_node('''
3098-
try:
3099-
do_something()
3100-
except Exception as error:
3101-
print("Error!")
3102-
finally:
3103-
print("Cleanup!")
3104-
''')
3105-
>>> node
3106-
<TryFinally l.2 at 0x7f23b2e41d68>
3107-
"""
3108-
3109-
_astroid_fields = ("body", "finalbody")
3110-
_multi_line_block_fields = ("body", "finalbody")
3045+
_astroid_fields = ("body", "handlers", "orelse", "finalbody")
3046+
_multi_line_block_fields = ("body", "handlers", "orelse", "finalbody")
31113047

31123048
def __init__(
31133049
self,
3050+
*,
31143051
lineno: int | None = None,
31153052
col_offset: int | None = None,
3116-
parent: NodeNG | None = None,
3117-
*,
31183053
end_lineno: int | None = None,
31193054
end_col_offset: int | None = None,
3055+
parent: NodeNG | None = None,
31203056
) -> None:
31213057
"""
31223058
:param lineno: The line that this node appears on in the source code.
@@ -3131,8 +3067,14 @@ def __init__(
31313067
:param end_col_offset: The end column this node appears on in the
31323068
source code. Note: This is after the last symbol.
31333069
"""
3134-
self.body: list[NodeNG | TryExcept] = []
3135-
"""The try-except that the finally is attached to."""
3070+
self.body: list[NodeNG] = []
3071+
"""The contents of the block to catch exceptions from."""
3072+
3073+
self.handlers: list[ExceptHandler] = []
3074+
"""The exception handlers."""
3075+
3076+
self.orelse: list[NodeNG] = []
3077+
"""The contents of the ``else`` block."""
31363078

31373079
self.finalbody: list[NodeNG] = []
31383080
"""The contents of the ``finally`` block."""
@@ -3147,40 +3089,62 @@ def __init__(
31473089

31483090
def postinit(
31493091
self,
3150-
body: list[NodeNG | TryExcept] | None = None,
3092+
*,
3093+
body: list[NodeNG] | None = None,
3094+
handlers: list[ExceptHandler] | None = None,
3095+
orelse: list[NodeNG] | None = None,
31513096
finalbody: list[NodeNG] | None = None,
31523097
) -> None:
31533098
"""Do some setup after initialisation.
31543099
3155-
:param body: The try-except that the finally is attached to.
3100+
:param body: The contents of the block to catch exceptions from.
3101+
3102+
:param handlers: The exception handlers.
3103+
3104+
:param orelse: The contents of the ``else`` block.
31563105
31573106
:param finalbody: The contents of the ``finally`` block.
31583107
"""
3159-
if body is not None:
3108+
if body:
31603109
self.body = body
3161-
if finalbody is not None:
3110+
if handlers:
3111+
self.handlers = handlers
3112+
if orelse:
3113+
self.orelse = orelse
3114+
if finalbody:
31623115
self.finalbody = finalbody
31633116

3164-
def block_range(self, lineno: int) -> tuple[int, int]:
3165-
"""Get a range from the given line number to where this node ends.
3166-
3167-
:param lineno: The line number to start the range at.
3117+
def _infer_name(self, frame, name):
3118+
return name
31683119

3169-
:returns: The range of line numbers that this node belongs to,
3170-
starting at the given line number.
3171-
"""
3172-
child = self.body[0]
3173-
# py2.5 try: except: finally:
3174-
if (
3175-
isinstance(child, TryExcept)
3176-
and child.fromlineno == self.fromlineno
3177-
and child.tolineno >= lineno > self.fromlineno
3178-
):
3179-
return child.block_range(lineno)
3180-
return self._elsed_block_range(lineno, self.finalbody)
3120+
def block_range(self, lineno: int) -> tuple[int, int]:
3121+
"""Get a range from a given line number to where this node ends."""
3122+
if lineno == self.fromlineno:
3123+
return lineno, lineno
3124+
if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno:
3125+
# Inside try body - return from lineno till end of try body
3126+
return lineno, self.body[-1].tolineno
3127+
for exhandler in self.handlers:
3128+
if exhandler.type and lineno == exhandler.type.fromlineno:
3129+
return lineno, lineno
3130+
if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3131+
return lineno, exhandler.body[-1].tolineno
3132+
if self.orelse:
3133+
if self.orelse[0].fromlineno - 1 == lineno:
3134+
return lineno, lineno
3135+
if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno:
3136+
return lineno, self.orelse[-1].tolineno
3137+
if self.finalbody:
3138+
if self.finalbody[0].fromlineno - 1 == lineno:
3139+
return lineno, lineno
3140+
if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno:
3141+
return lineno, self.finalbody[-1].tolineno
3142+
return lineno, self.tolineno
31813143

31823144
def get_children(self):
31833145
yield from self.body
3146+
yield from self.handlers
3147+
yield from self.orelse
31843148
yield from self.finalbody
31853149

31863150

astroid/nodes/node_ng.py

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

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

580580
def _infer(

0 commit comments

Comments
 (0)