Skip to content

Commit db4de99

Browse files
committed
Fix false positive no-member in except * handler
1 parent 9256b31 commit db4de99

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

astroid/protocols.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,11 +527,21 @@ def excepthandler_assigned_stmts(
527527
) -> Any:
528528
from astroid import objects # pylint: disable=import-outside-toplevel
529529

530-
for assigned in node_classes.unpack_infer(self.type):
531-
if isinstance(assigned, nodes.ClassDef):
532-
assigned = objects.ExceptionInstance(assigned)
530+
def _generate_assigned():
531+
for assigned in node_classes.unpack_infer(self.type):
532+
if isinstance(assigned, nodes.ClassDef):
533+
assigned = objects.ExceptionInstance(assigned)
533534

535+
yield assigned
536+
537+
if isinstance(self.parent, node_classes.TryStar):
538+
# except * handler has assigned ExceptionGroup
539+
eg = nodes.ClassDef('ExceptionGroup', self.lineno, self.col_offset, self, end_lineno=self.end_lineno, end_col_offset=self.end_col_offset)
540+
assigned = objects.ExceptionInstance(eg)
541+
assigned.instance_attrs['exceptions'] = [nodes.List.from_elements(_generate_assigned())]
534542
yield assigned
543+
else:
544+
yield from _generate_assigned()
535545
return {
536546
"node": self,
537547
"unknown": node,

tests/test_group_exceptions.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
For,
1212
Name,
1313
Try,
14+
List,
1415
Uninferable,
1516
bases,
1617
extract_node,
@@ -93,6 +94,7 @@ def test_star_exceptions() -> None:
9394
assert final.value.args[0].value == 0
9495

9596

97+
9698
@pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher")
9799
def test_star_exceptions_infer_name() -> None:
98100
trystar = extract_node(
@@ -108,3 +110,31 @@ def test_star_exceptions_infer_name() -> None:
108110
stmts = bases._infer_stmts([trystar], context)
109111
assert list(stmts) == [Uninferable]
110112
assert context.lookupname == name
113+
114+
115+
@pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher")
116+
def test_star_exceptions_infer_exceptions() -> None:
117+
code = textwrap.dedent(
118+
"""
119+
try:
120+
raise ExceptionGroup("group", [ValueError(654), TypeError(10)])
121+
except* ValueError as ve:
122+
print(e.exceptions)
123+
except* TypeError as te:
124+
print(e.exceptions)
125+
else:
126+
sys.exit(127)
127+
finally:
128+
sys.exit(0)"""
129+
)
130+
node = extract_node(code)
131+
assert isinstance(node, TryStar)
132+
inferred_ve = next(node.handlers[0].statement().name.infer())
133+
assert inferred_ve.name =='ExceptionGroup'
134+
assert isinstance(inferred_ve.getattr('exceptions')[0], List)
135+
assert inferred_ve.getattr('exceptions')[0].elts[0].pytype() == 'builtins.ValueError'
136+
137+
inferred_te = next(node.handlers[1].statement().name.infer())
138+
assert inferred_te.name =='ExceptionGroup'
139+
assert isinstance(inferred_te.getattr('exceptions')[0], List)
140+
assert inferred_te.getattr('exceptions')[0].elts[0].pytype() == 'builtins.TypeError'

0 commit comments

Comments
 (0)