1212
1313
1414import ast
15- import sys
1615import inspect
17- from textwrap import dedent , indent
1816
1917
2018class _AsyncIORunner :
21-
2219 def __call__ (self , coro ):
2320 """
2421 Handler for asyncio autoawait
@@ -28,7 +25,8 @@ def __call__(self, coro):
2825 return asyncio .get_event_loop_policy ().get_event_loop ().run_until_complete (coro )
2926
3027 def __str__ (self ):
31- return 'asyncio'
28+ return "asyncio"
29+
3230
3331_asyncio_runner = _AsyncIORunner ()
3432
@@ -74,69 +72,6 @@ def _pseudo_sync_runner(coro):
7472 )
7573
7674
77- def _asyncify (code : str ) -> str :
78- """wrap code in async def definition.
79-
80- And setup a bit of context to run it later.
81- """
82- res = dedent (
83- """
84- async def __wrapper__():
85- try:
86- {usercode}
87- finally:
88- locals()
89- """
90- ).format (usercode = indent (code , " " * 8 ))
91- return res
92-
93-
94- class _AsyncSyntaxErrorVisitor (ast .NodeVisitor ):
95- """
96- Find syntax errors that would be an error in an async repl, but because
97- the implementation involves wrapping the repl in an async function, it
98- is erroneously allowed (e.g. yield or return at the top level)
99- """
100- def __init__ (self ):
101- if sys .version_info >= (3 ,8 ):
102- raise ValueError ('DEPRECATED in Python 3.8+' )
103- self .depth = 0
104- super ().__init__ ()
105-
106- def generic_visit (self , node ):
107- func_types = (ast .FunctionDef , ast .AsyncFunctionDef )
108- invalid_types_by_depth = {
109- 0 : (ast .Return , ast .Yield , ast .YieldFrom ),
110- 1 : (ast .Nonlocal ,)
111- }
112-
113- should_traverse = self .depth < max (invalid_types_by_depth .keys ())
114- if isinstance (node , func_types ) and should_traverse :
115- self .depth += 1
116- super ().generic_visit (node )
117- self .depth -= 1
118- elif isinstance (node , invalid_types_by_depth [self .depth ]):
119- raise SyntaxError ()
120- else :
121- super ().generic_visit (node )
122-
123-
124- def _async_parse_cell (cell : str ) -> ast .AST :
125- """
126- This is a compatibility shim for pre-3.7 when async outside of a function
127- is a syntax error at the parse stage.
128-
129- It will return an abstract syntax tree parsed as if async and await outside
130- of a function were not a syntax error.
131- """
132- if sys .version_info < (3 , 7 ):
133- # Prior to 3.7 you need to asyncify before parse
134- wrapped_parse_tree = ast .parse (_asyncify (cell ))
135- return wrapped_parse_tree .body [0 ].body [0 ]
136- else :
137- return ast .parse (cell )
138-
139-
14075def _should_be_async (cell : str ) -> bool :
14176 """Detect if a block of code need to be wrapped in an `async def`
14277
@@ -148,25 +83,10 @@ def _should_be_async(cell: str) -> bool:
14883 Not handled yet: If the block of code has a return statement as the top
14984 level, it will be seen as async. This is a know limitation.
15085 """
151- if sys .version_info > (3 , 8 ):
152- try :
153- code = compile (cell , "<>" , "exec" , flags = getattr (ast ,'PyCF_ALLOW_TOP_LEVEL_AWAIT' , 0x0 ))
154- return inspect .CO_COROUTINE & code .co_flags == inspect .CO_COROUTINE
155- except (SyntaxError , MemoryError ):
156- return False
15786 try :
158- # we can't limit ourself to ast.parse, as it __accepts__ to parse on
159- # 3.7+, but just does not _compile_
160- code = compile (cell , "<>" , "exec" )
87+ code = compile (
88+ cell , "<>" , "exec" , flags = getattr (ast , "PyCF_ALLOW_TOP_LEVEL_AWAIT" , 0x0 )
89+ )
90+ return inspect .CO_COROUTINE & code .co_flags == inspect .CO_COROUTINE
16191 except (SyntaxError , MemoryError ):
162- try :
163- parse_tree = _async_parse_cell (cell )
164-
165- # Raise a SyntaxError if there are top-level return or yields
166- v = _AsyncSyntaxErrorVisitor ()
167- v .visit (parse_tree )
168-
169- except (SyntaxError , MemoryError ):
170- return False
171- return True
172- return False
92+ return False
0 commit comments