|
1 | 1 | from blib2to3.pgen2 import token |
2 | 2 | from ast import literal_eval |
3 | 3 | from semmle.python import ast |
| 4 | +from semmle.util import get_analysis_major_version |
4 | 5 | from blib2to3.pgen2.parse import ParseError |
5 | 6 | import sys |
6 | 7 |
|
@@ -981,7 +982,20 @@ def visit_except_clause(self, node): |
981 | 982 | if len(node.children) > 1: |
982 | 983 | type = self.visit(node.children[1], LOAD) |
983 | 984 | if len(node.children) > 3: |
984 | | - name = self.visit(node.children[3], STORE) |
| 985 | + # The grammar rule `'except' [test [(',' | 'as') test]]` is shared |
| 986 | + # between two incompatible readings of a fourth child, so the |
| 987 | + # separator token and the analysis version together decide: |
| 988 | + # `except A as e:` binds an alias, in every version; |
| 989 | + # `except A, e:` binds an alias when extracting Python 2, where |
| 990 | + # that is the canonical idiom; |
| 991 | + # `except A, B:` is an unparenthesized tuple of exception types |
| 992 | + # otherwise -- PEP 758, Python 3.14+. |
| 993 | + if is_token(node.children[2], "as") or get_analysis_major_version() == 2: |
| 994 | + name = self.visit(node.children[3], STORE) |
| 995 | + else: |
| 996 | + elts = [type, self.visit(node.children[3], LOAD)] |
| 997 | + type = ast.Tuple(elts, LOAD) |
| 998 | + set_location(type, node.children[1].start, node.children[3].end) |
985 | 999 | return type, name |
986 | 1000 |
|
987 | 1001 | def visit_del_stmt(self, node): |
|
0 commit comments