Detect if a block of code need to be wrapped in an `async def` Attempt to parse the block of code, it it compile we're fine. Otherwise we wrap if and try to compile. If it works, assume it should be async. Otherwise Return False. Not handled yet: If the block of code has a return
(cell: str)
| 139 | |
| 140 | |
| 141 | def _should_be_async(cell: str) -> bool: |
| 142 | """Detect if a block of code need to be wrapped in an `async def` |
| 143 | |
| 144 | Attempt to parse the block of code, it it compile we're fine. |
| 145 | Otherwise we wrap if and try to compile. |
| 146 | |
| 147 | If it works, assume it should be async. Otherwise Return False. |
| 148 | |
| 149 | Not handled yet: If the block of code has a return statement as the top |
| 150 | level, it will be seen as async. This is a know limitation. |
| 151 | """ |
| 152 | if sys.version_info > (3, 8): |
| 153 | try: |
| 154 | code = compile(cell, "<>", "exec", flags=getattr(ast,'PyCF_ALLOW_TOP_LEVEL_AWAIT', 0x0)) |
| 155 | return inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE |
| 156 | except (SyntaxError, MemoryError): |
| 157 | return False |
| 158 | try: |
| 159 | # we can't limit ourself to ast.parse, as it __accepts__ to parse on |
| 160 | # 3.7+, but just does not _compile_ |
| 161 | code = compile(cell, "<>", "exec") |
| 162 | except (SyntaxError, MemoryError): |
| 163 | try: |
| 164 | parse_tree = _async_parse_cell(cell) |
| 165 | |
| 166 | # Raise a SyntaxError if there are top-level return or yields |
| 167 | v = _AsyncSyntaxErrorVisitor() |
| 168 | v.visit(parse_tree) |
| 169 | |
| 170 | except (SyntaxError, MemoryError): |
| 171 | return False |
| 172 | return True |
| 173 | return False |