@@ -2815,32 +2815,74 @@ def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures
28152815 shell_futures = shell_futures ,
28162816 )
28172817
2818- # run_cell_async is async, but may not actually need and eventloop.
2818+ # run_cell_async is async, but may not actually need an eventloop.
28192819 # when this is the case, we want to run it using the pseudo_sync_runner
28202820 # so that code can invoke eventloops (for example via the %run , and
28212821 # `%paste` magic.
2822+ if self .should_run_async (raw_cell ):
2823+ runner = self .loop_runner
2824+ else :
2825+
2826+ runner = _pseudo_sync_runner
2827+
28222828 try :
2823- interactivity = coro .send (None )
2824- except StopIteration as exc :
2825- return exc .value
2829+ return runner (coro )
2830+ except Exception as e :
2831+ info = ExecutionInfo (raw_cell , store_history , silent , shell_futures )
2832+ result = ExecutionResult (info )
2833+ result .error_in_exec = e
2834+ self .showtraceback (running_compiled_code = True )
2835+ return result
2836+ return
28262837
2827- # if code was not async, sending `None` was actually executing the code.
2828- if isinstance (interactivity , ExecutionResult ):
2829- return interactivity
2838+ def should_run_async (self , raw_cell : str ) -> bool :
2839+ """Return whether a cell should be run asynchronously
28302840
2831- if interactivity == 'async' :
2832- try :
2833- return self .loop_runner (coro )
2834- except Exception as e :
2835- info = ExecutionInfo (raw_cell , store_history , silent , shell_futures )
2836- result = ExecutionResult (info )
2837- result .error_in_exec = e
2838- self .showtraceback (running_compiled_code = True )
2839- return result
2840- return _pseudo_sync_runner (coro )
2841+ Parameters
2842+ ----------
2843+ cell: str
2844+ The code to be executed
2845+
2846+ Returns
2847+ -------
2848+ result: bool
2849+ Whether the code should be run asynchronously or not
2850+ """
2851+ if not self .autoawait :
2852+ return False
2853+ try :
2854+ cell = self .transform_cell (raw_cell )
2855+ except Exception :
2856+ # any exception during transform will be raised
2857+ # prior to execution
2858+ return False
2859+ return _should_be_async (cell )
2860+
2861+ def transform_cell (self , raw_cell : str ) -> str :
2862+ """Transform a raw cell into Python code to be executed
2863+
2864+ Parameters
2865+ ----------
2866+ raw_cell: str
2867+ The IPython-syntax code to be executed
2868+
2869+ Returns
2870+ -------
2871+ cell: str
2872+ Transformed Python code to be executed
2873+ """
2874+ # Static input transformations
2875+ cell = self .input_transformer_manager .transform_cell (raw_cell )
2876+ if len (cell .splitlines ()) == 1 :
2877+ # Dynamic transformations - only applied for single line commands
2878+ with self .builtin_trap :
2879+ # use prefilter_lines to handle trailing newlines
2880+ # restore trailing newline for ast.parse
2881+ cell = self .prefilter_manager .prefilter_lines (cell ) + '\n '
2882+ return cell
28412883
28422884 @asyncio .coroutine
2843- def run_cell_async (self , raw_cell :str , store_history = False , silent = False , shell_futures = True ) -> ExecutionResult :
2885+ def run_cell_async (self , raw_cell : str , store_history = False , silent = False , shell_futures = True ) -> ExecutionResult :
28442886 """Run a complete IPython cell asynchronously.
28452887
28462888 Parameters
@@ -2895,24 +2937,13 @@ def error_before_exec(value):
28952937 # prefilter_manager) raises an exception, we store it in this variable
28962938 # so that we can display the error after logging the input and storing
28972939 # it in the history.
2898- preprocessing_exc_tuple = None
28992940 try :
2900- # Static input transformations
2901- cell = self . input_transformer_manager . transform_cell ( raw_cell )
2902- except SyntaxError :
2941+ cell = self . transform_cell ( raw_cell )
2942+ except Exception :
2943+ cell = raw_cell
29032944 preprocessing_exc_tuple = sys .exc_info ()
2904- cell = raw_cell # cell has to exist so it can be stored/logged
29052945 else :
2906- if len (cell .splitlines ()) == 1 :
2907- # Dynamic transformations - only applied for single line commands
2908- with self .builtin_trap :
2909- try :
2910- # use prefilter_lines to handle trailing newlines
2911- # restore trailing newline for ast.parse
2912- cell = self .prefilter_manager .prefilter_lines (cell ) + '\n '
2913- except Exception :
2914- # don't allow prefilter errors to crash IPython
2915- preprocessing_exc_tuple = sys .exc_info ()
2946+ preprocessing_exc_tuple = None
29162947
29172948 # Store raw and processed history
29182949 if store_history :
@@ -2941,7 +2972,7 @@ def error_before_exec(value):
29412972 with self .display_trap :
29422973 # Compile to bytecode
29432974 try :
2944- if self .autoawait and _should_be_async (cell ):
2975+ if self .should_run_async (cell ):
29452976 # the code AST below will not be user code: we wrap it
29462977 # in an `async def`. This will likely make some AST
29472978 # transformer below miss some transform opportunity and
@@ -2987,12 +3018,10 @@ def error_before_exec(value):
29873018 interactivity = "none" if silent else self .ast_node_interactivity
29883019 if _run_async :
29893020 interactivity = 'async'
2990- # yield interactivity so let run_cell decide whether to use
2991- # an async loop_runner
2992- yield interactivity
3021+
29933022 has_raised = yield from self .run_ast_nodes (code_ast .body , cell_name ,
29943023 interactivity = interactivity , compiler = compiler , result = result )
2995-
3024+
29963025 self .last_execution_succeeded = not has_raised
29973026 self .last_execution_result = result
29983027
@@ -3008,7 +3037,7 @@ def error_before_exec(value):
30083037 self .execution_count += 1
30093038
30103039 return result
3011-
3040+
30123041 def transform_ast (self , node ):
30133042 """Apply the AST transformations from self.ast_transformers
30143043
0 commit comments