Show More
@@ -80,6 +80,40 b' def _asyncify(code: str) -> str:' | |||
|
80 | 80 | return res |
|
81 | 81 | |
|
82 | 82 | |
|
83 | class _AsyncSyntaxErrorVisitor(ast.NodeVisitor): | |
|
84 | """ | |
|
85 | Find syntax errors that would be an error in an async repl, but because | |
|
86 | the implementation involves wrapping the repl in an async function, it | |
|
87 | is erroneously allowed (e.g. yield or return at the top level) | |
|
88 | """ | |
|
89 | def generic_visit(self, node): | |
|
90 | func_types = (ast.FunctionDef, ast.AsyncFunctionDef) | |
|
91 | invalid_types = (ast.Return, ast.Yield, ast.YieldFrom) | |
|
92 | ||
|
93 | if isinstance(node, func_types): | |
|
94 | return # Don't recurse into functions | |
|
95 | elif isinstance(node, invalid_types): | |
|
96 | raise SyntaxError() | |
|
97 | else: | |
|
98 | super().generic_visit(node) | |
|
99 | ||
|
100 | ||
|
101 | def _async_parse_cell(cell: str) -> ast.AST: | |
|
102 | """ | |
|
103 | This is a compatibility shim for pre-3.7 when async outside of a function | |
|
104 | is a syntax error at the parse stage. | |
|
105 | ||
|
106 | It will return an abstract syntax tree parsed as if async and await outside | |
|
107 | of a function were not a syntax error. | |
|
108 | """ | |
|
109 | if sys.version_info < (3, 7): | |
|
110 | # Prior to 3.7 you need to asyncify before parse | |
|
111 | wrapped_parse_tree = ast.parse(_asyncify(cell)) | |
|
112 | return wrapped_parse_tree.body[0].body[0] | |
|
113 | else: | |
|
114 | return ast.parse(cell) | |
|
115 | ||
|
116 | ||
|
83 | 117 | def _should_be_async(cell: str) -> bool: |
|
84 | 118 | """Detect if a block of code need to be wrapped in an `async def` |
|
85 | 119 | |
@@ -99,8 +133,12 b' def _should_be_async(cell: str) -> bool:' | |||
|
99 | 133 | return False |
|
100 | 134 | except SyntaxError: |
|
101 | 135 | try: |
|
102 |
|
|
|
103 | # TODO verify ast has not "top level" return or yield. | |
|
136 | parse_tree = _async_parse_cell(cell) | |
|
137 | ||
|
138 | # Raise a SyntaxError if there are top-level return or yields | |
|
139 | v = _AsyncSyntaxErrorVisitor() | |
|
140 | v.visit(parse_tree) | |
|
141 | ||
|
104 | 142 | except SyntaxError: |
|
105 | 143 | return False |
|
106 | 144 | return True |
General Comments 0
You need to be logged in to leave comments.
Login now