Skip to content

Commit 267aa43

Browse files
committed
Add MultiLineBlockMixin
`_multi_line_block_fields` is a list of strings indicating which fields contain multi-line blocks. `_get_multi_line_blocks` dynamically accesses these attributes the first time it is called and then caches the resulting references so as to avoid repeated expensive attribute lookups.
1 parent 45dede4 commit 267aa43

File tree

3 files changed

+58
-206
lines changed

3 files changed

+58
-206
lines changed

astroid/mixins.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,41 @@ def real_name(self, asname):
131131
raise exceptions.AttributeInferenceError(
132132
'Could not find original name for {attribute} in {target!r}',
133133
target=self, attribute=asname)
134+
135+
136+
class MultiLineBlockMixin:
137+
def _get_multi_line_blocks(self):
138+
try:
139+
return self._multi_line_blocks
140+
except AttributeError:
141+
self._multi_line_blocks = tuple(
142+
getattr(self, field)
143+
for field in self._multi_line_block_fields
144+
)
145+
146+
return self._multi_line_blocks
147+
148+
def _get_return_nodes_skip_functions(self):
149+
blocks = self._get_multi_line_blocks()
150+
151+
for block in blocks:
152+
for child_node in block:
153+
if child_node.is_function:
154+
continue
155+
yield from child_node._get_return_nodes_skip_functions()
156+
157+
def _get_yield_nodes_skip_lambdas(self):
158+
blocks = self._get_multi_line_blocks()
159+
160+
for block in blocks:
161+
for child_node in block:
162+
if child_node.is_lambda:
163+
continue
164+
yield from child_node._get_yield_nodes_skip_lambdas()
165+
166+
def _get_assign_nodes(self):
167+
blocks = self._get_multi_line_blocks()
168+
169+
for block in blocks:
170+
for child_node in block:
171+
yield from child_node._get_assign_nodes()

astroid/node_classes.py

Lines changed: 18 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -2741,7 +2741,8 @@ def get_children(self):
27412741
yield from ()
27422742

27432743

2744-
class ExceptHandler(mixins.AssignTypeMixin, Statement):
2744+
class ExceptHandler(mixins.MultiLineBlockMixin,
2745+
mixins.AssignTypeMixin, Statement):
27452746
"""Class representing an :class:`ast.ExceptHandler`. node.
27462747
27472748
An :class:`ExceptHandler` is an ``except`` block on a try-except.
@@ -2758,6 +2759,7 @@ class ExceptHandler(mixins.AssignTypeMixin, Statement):
27582759
[<ExceptHandler l.4 at 0x7f23b2e9e860>]
27592760
"""
27602761
_astroid_fields = ('type', 'name', 'body',)
2762+
_multi_line_block_fields = ('body',)
27612763
type = None
27622764
"""The types that the block handles.
27632765
@@ -2828,18 +2830,6 @@ def catch(self, exceptions): # pylint: disable=redefined-outer-name
28282830
return True
28292831
return False
28302832

2831-
def _get_return_nodes_skip_functions(self):
2832-
for child_node in self.body:
2833-
if child_node.is_function:
2834-
continue
2835-
yield from child_node._get_return_nodes_skip_functions()
2836-
2837-
def _get_yield_nodes_skip_lambdas(self):
2838-
for child_node in self.body:
2839-
if child_node.is_lambda:
2840-
continue
2841-
yield from child_node._get_yield_nodes_skip_lambdas()
2842-
28432833

28442834
class Exec(Statement):
28452835
"""Class representing the ``exec`` statement.
@@ -2910,14 +2900,16 @@ def postinit(self, dims=None):
29102900
self.dims = dims
29112901

29122902

2913-
class For(mixins.BlockRangeMixIn, mixins.AssignTypeMixin, Statement):
2903+
class For(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn,
2904+
mixins.AssignTypeMixin, Statement):
29142905
"""Class representing an :class:`ast.For` node.
29152906
29162907
>>> node = astroid.extract_node('for thing in things: print(thing)')
29172908
>>> node
29182909
<For l.1 at 0x7f23b2e8cf28>
29192910
"""
29202911
_astroid_fields = ('target', 'iter', 'body', 'orelse',)
2912+
_multi_line_block_fields = ('body', 'orelse')
29212913
target = None
29222914
"""What the loop assigns to.
29232915
@@ -2983,35 +2975,6 @@ def get_children(self):
29832975
yield from self.body
29842976
yield from self.orelse
29852977

2986-
def _get_assign_nodes(self):
2987-
for child_node in self.body:
2988-
yield from child_node._get_assign_nodes()
2989-
2990-
for child_node in self.orelse:
2991-
yield from child_node._get_assign_nodes()
2992-
2993-
def _get_return_nodes_skip_functions(self):
2994-
for child_node in self.body:
2995-
if child_node.is_function:
2996-
continue
2997-
yield from child_node._get_return_nodes_skip_functions()
2998-
2999-
for child_node in self.orelse:
3000-
if child_node.is_function:
3001-
continue
3002-
yield from child_node._get_return_nodes_skip_functions()
3003-
3004-
def _get_yield_nodes_skip_lambdas(self):
3005-
for child_node in self.body:
3006-
if child_node.is_lambda:
3007-
continue
3008-
yield from child_node._get_yield_nodes_skip_lambdas()
3009-
3010-
for child_node in self.orelse:
3011-
if child_node.is_lambda:
3012-
continue
3013-
yield from child_node._get_yield_nodes_skip_lambdas()
3014-
30152978

30162979
class AsyncFor(For):
30172980
"""Class representing an :class:`ast.AsyncFor` node.
@@ -3214,14 +3177,15 @@ def get_children(self):
32143177
yield from ()
32153178

32163179

3217-
class If(mixins.BlockRangeMixIn, Statement):
3180+
class If(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement):
32183181
"""Class representing an :class:`ast.If` node.
32193182
32203183
>>> node = astroid.extract_node('if condition: print(True)')
32213184
>>> node
32223185
<If l.1 at 0x7f23b2e9dd30>
32233186
"""
32243187
_astroid_fields = ('test', 'body', 'orelse')
3188+
_multi_line_block_fields = ('body', 'orelse')
32253189
test = None
32263190
"""The condition that the statement tests.
32273191
@@ -3285,35 +3249,6 @@ def get_children(self):
32853249
yield from self.body
32863250
yield from self.orelse
32873251

3288-
def _get_assign_nodes(self):
3289-
for child_node in self.body:
3290-
yield from child_node._get_assign_nodes()
3291-
3292-
for child_node in self.orelse:
3293-
yield from child_node._get_assign_nodes()
3294-
3295-
def _get_return_nodes_skip_functions(self):
3296-
for child_node in self.body:
3297-
if child_node.is_function:
3298-
continue
3299-
yield from child_node._get_return_nodes_skip_functions()
3300-
3301-
for child_node in self.orelse:
3302-
if child_node.is_function:
3303-
continue
3304-
yield from child_node._get_return_nodes_skip_functions()
3305-
3306-
def _get_yield_nodes_skip_lambdas(self):
3307-
for child_node in self.body:
3308-
if child_node.is_lambda:
3309-
continue
3310-
yield from child_node._get_yield_nodes_skip_lambdas()
3311-
3312-
for child_node in self.orelse:
3313-
if child_node.is_lambda:
3314-
continue
3315-
yield from child_node._get_yield_nodes_skip_lambdas()
3316-
33173252

33183253
class IfExp(NodeNG):
33193254
"""Class representing an :class:`ast.IfExp` node.
@@ -3952,7 +3887,7 @@ def get_children(self):
39523887
yield self.slice
39533888

39543889

3955-
class TryExcept(mixins.BlockRangeMixIn, Statement):
3890+
class TryExcept(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement):
39563891
"""Class representing an :class:`ast.TryExcept` node.
39573892
39583893
>>> node = astroid.extract_node('''
@@ -3965,6 +3900,7 @@ class TryExcept(mixins.BlockRangeMixIn, Statement):
39653900
<TryExcept l.2 at 0x7f23b2e9d908>
39663901
"""
39673902
_astroid_fields = ('body', 'handlers', 'orelse',)
3903+
_multi_line_block_fields = ('body', 'orelse')
39683904
body = None
39693905
"""The contents of the block to catch exceptions from.
39703906
@@ -4026,38 +3962,9 @@ def get_children(self):
40263962
yield from self.handlers or ()
40273963
yield from self.orelse or ()
40283964

4029-
def _get_assign_nodes(self):
4030-
for child_node in self.body:
4031-
yield from child_node._get_assign_nodes()
4032-
4033-
for child_node in self.orelse:
4034-
yield from child_node._get_assign_nodes()
4035-
4036-
def _get_return_nodes_skip_functions(self):
4037-
for child_node in self.body:
4038-
if child_node.is_function:
4039-
continue
4040-
yield from child_node._get_return_nodes_skip_functions()
4041-
4042-
for child_node in self.orelse or ():
4043-
if child_node.is_function:
4044-
continue
4045-
for matching in child_node._get_return_nodes_skip_functions():
4046-
yield matching
4047-
4048-
def _get_yield_nodes_skip_lambdas(self):
4049-
for child_node in self.body:
4050-
if child_node.is_lambda:
4051-
continue
4052-
yield from child_node._get_yield_nodes_skip_lambdas()
4053-
4054-
for child_node in self.orelse:
4055-
if child_node.is_lambda:
4056-
continue
4057-
yield from child_node._get_yield_nodes_skip_lambdas()
4058-
40593965

4060-
class TryFinally(mixins.BlockRangeMixIn, Statement):
3966+
class TryFinally(mixins.MultiLineBlockMixin,
3967+
mixins.BlockRangeMixIn, Statement):
40613968
"""Class representing an :class:`ast.TryFinally` node.
40623969
40633970
>>> node = astroid.extract_node('''
@@ -4072,6 +3979,7 @@ class TryFinally(mixins.BlockRangeMixIn, Statement):
40723979
<TryFinally l.2 at 0x7f23b2e41d68>
40733980
"""
40743981
_astroid_fields = ('body', 'finalbody',)
3982+
_multi_line_block_fields = ('body', 'finalbody')
40753983
body = None
40763984
"""The try-except that the finally is attached to.
40773985
@@ -4116,36 +4024,6 @@ def get_children(self):
41164024
yield from self.body
41174025
yield from self.finalbody
41184026

4119-
def _get_assign_nodes(self):
4120-
for child_node in self.body:
4121-
yield from child_node._get_assign_nodes()
4122-
4123-
for child_node in self.finalbody:
4124-
yield from child_node._get_assign_nodes()
4125-
4126-
def _get_return_nodes_skip_functions(self):
4127-
for child_node in self.body:
4128-
if child_node.is_function:
4129-
continue
4130-
yield from child_node._get_return_nodes_skip_functions()
4131-
4132-
for child_node in self.finalbody:
4133-
if child_node.is_function:
4134-
continue
4135-
for matching in child_node._get_return_nodes_skip_functions():
4136-
yield matching
4137-
4138-
def _get_yield_nodes_skip_lambdas(self):
4139-
for child_node in self.body:
4140-
if child_node.is_lambda:
4141-
continue
4142-
yield from child_node._get_yield_nodes_skip_lambdas()
4143-
4144-
for child_node in self.finalbody:
4145-
if child_node.is_lambda:
4146-
continue
4147-
yield from child_node._get_yield_nodes_skip_lambdas()
4148-
41494027

41504028
class Tuple(_BaseContainer):
41514029
"""Class representing an :class:`ast.Tuple` node.
@@ -4268,7 +4146,7 @@ def get_children(self):
42684146
yield self.operand
42694147

42704148

4271-
class While(mixins.BlockRangeMixIn, Statement):
4149+
class While(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement):
42724150
"""Class representing an :class:`ast.While` node.
42734151
42744152
>>> node = astroid.extract_node('''
@@ -4279,6 +4157,7 @@ class While(mixins.BlockRangeMixIn, Statement):
42794157
<While l.2 at 0x7f23b2e4e390>
42804158
"""
42814159
_astroid_fields = ('test', 'body', 'orelse',)
4160+
_multi_line_block_fields = ('body', 'orelse')
42824161
test = None
42834162
"""The condition that the loop tests.
42844163
@@ -4337,38 +4216,9 @@ def get_children(self):
43374216
yield from self.body
43384217
yield from self.orelse
43394218

4340-
def _get_assign_nodes(self):
4341-
for child_node in self.body:
4342-
yield from child_node._get_assign_nodes()
4343-
4344-
for child_node in self.orelse:
4345-
yield from child_node._get_assign_nodes()
43464219

4347-
def _get_return_nodes_skip_functions(self):
4348-
for child_node in self.body:
4349-
if child_node.is_function:
4350-
continue
4351-
yield from child_node._get_return_nodes_skip_functions()
4352-
4353-
for child_node in self.orelse:
4354-
if child_node.is_function:
4355-
continue
4356-
for matching in child_node._get_return_nodes_skip_functions():
4357-
yield matching
4358-
4359-
def _get_yield_nodes_skip_lambdas(self):
4360-
for child_node in self.body:
4361-
if child_node.is_lambda:
4362-
continue
4363-
yield from child_node._get_yield_nodes_skip_lambdas()
4364-
4365-
for child_node in self.orelse:
4366-
if child_node.is_lambda:
4367-
continue
4368-
yield from child_node._get_yield_nodes_skip_lambdas()
4369-
4370-
4371-
class With(mixins.BlockRangeMixIn, mixins.AssignTypeMixin, Statement):
4220+
class With(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn,
4221+
mixins.AssignTypeMixin, Statement):
43724222
"""Class representing an :class:`ast.With` node.
43734223
43744224
>>> node = astroid.extract_node('''
@@ -4379,6 +4229,7 @@ class With(mixins.BlockRangeMixIn, mixins.AssignTypeMixin, Statement):
43794229
<With l.2 at 0x7f23b2e4e710>
43804230
"""
43814231
_astroid_fields = ('items', 'body')
4232+
_multi_line_block_fields = ('body',)
43824233
items = None
43834234
"""The pairs of context managers and the names they are assigned to.
43844235
@@ -4424,22 +4275,6 @@ def get_children(self):
44244275
for elt in self.body:
44254276
yield elt
44264277

4427-
def _get_assign_nodes(self):
4428-
for child_node in self.body:
4429-
yield from child_node._get_assign_nodes()
4430-
4431-
def _get_return_nodes_skip_functions(self):
4432-
for child_node in self.body:
4433-
if child_node.is_function:
4434-
continue
4435-
yield from child_node._get_return_nodes_skip_functions()
4436-
4437-
def _get_yield_nodes_skip_lambdas(self):
4438-
for child_node in self.body:
4439-
if child_node.is_lambda:
4440-
continue
4441-
yield from child_node._get_yield_nodes_skip_lambdas()
4442-
44434278

44444279
class AsyncWith(With):
44454280
"""Asynchronous ``with`` built with the ``async`` keyword."""

0 commit comments

Comments
 (0)