55from unittest .mock import MagicMock , patch
66from textwrap import dedent
77
8- import _pyrepl
9-
108from test .support import force_not_colorized
119
10+ from _pyrepl import simple_interact
1211from _pyrepl .console import InteractiveColoredConsole
1312from _pyrepl .simple_interact import _more_lines
1413
@@ -303,14 +302,9 @@ def f():
303302 self .assertEqual (count , 1 )
304303
305304
306- class TestPreExecutionHook (unittest .TestCase ):
307-
308- def test_hook_is_unset_by_default (self ):
309- self .assertIsNone (_pyrepl .pre_execution_hook )
310-
311- def _run_interactive (self , statements , * , pre_execution_hook = None ):
312- from _pyrepl .simple_interact import run_multiline_interactive_console
305+ class TestStatementSubmittedHook (unittest .TestCase ):
313306
307+ def _run_interactive (self , statements , hook ):
314308 console = InteractiveColoredConsole ()
315309 statement_iter = iter (statements )
316310
@@ -320,51 +314,37 @@ def fake_multiline_input(more_lines, ps1, ps2):
320314 except StopIteration :
321315 raise EOFError
322316
323- patches = [
324- patch (
325- "_pyrepl.simple_interact.multiline_input" ,
317+ output = io .StringIO ()
318+ with (
319+ patch .object (simple_interact , "statement_submitted_hook" , hook ),
320+ patch .object (
321+ simple_interact ,
322+ "multiline_input" ,
326323 side_effect = fake_multiline_input ,
327324 ),
328- patch ( "_pyrepl. simple_interact. _get_reader" ),
329- patch ( "_pyrepl. simple_interact. append_history_file" ),
325+ patch . object ( simple_interact , " _get_reader" ),
326+ patch . object ( simple_interact , " append_history_file" ),
330327 patch ("_pyrepl.readline._setup" ),
331- ]
332- if pre_execution_hook is not None :
333- patches .append (
334- patch .object (
335- _pyrepl ,
336- "pre_execution_hook" ,
337- pre_execution_hook ,
338- )
339- )
340-
341- output = io .StringIO ()
342- with contextlib .ExitStack () as stack :
343- for context_manager in patches :
344- stack .enter_context (context_manager )
345- stack .enter_context (contextlib .redirect_stdout (output ))
346- stack .enter_context (contextlib .redirect_stderr (output ))
347- run_multiline_interactive_console (console )
328+ contextlib .redirect_stdout (output ),
329+ contextlib .redirect_stderr (output ),
330+ ):
331+ simple_interact .run_multiline_interactive_console (console )
348332
349333 return output .getvalue (), console .locals
350334
351- def test_hook_called_with_statement (self ):
352- hook = MagicMock ()
353- self ._run_interactive (["x = 1" ], pre_execution_hook = hook )
354- hook .assert_called_once_with ("x = 1" )
355-
356- def test_hook_exception_does_not_break_repl (self ):
357- hook = MagicMock (side_effect = RuntimeError ("hook error" ))
358- output , namespace = self ._run_interactive (
359- ["x = 1" , "y = 2" ],
360- pre_execution_hook = hook ,
335+ def test_hook_called_before_statement_execution (self ):
336+ statement = "print('statement executed')"
337+ escape_sequence = "\x1b ]633;C\x07 "
338+ hook = MagicMock (
339+ side_effect = lambda statement : print (escape_sequence , end = "" )
361340 )
362- self .assertEqual ( hook . call_count , 2 )
363- self . assertEqual ( namespace [ "x" ], 1 )
364- self . assertEqual ( namespace [ "y" ], 2 )
365- self .assertNotIn ( "hook error" , output )
341+ output , _ = self ._run_interactive ([ statement ], hook )
342+
343+ hook . assert_called_once_with ( statement )
344+ self .assertEqual ( output , f" { escape_sequence } statement executed \n " )
366345
367346 def test_hook_not_called_for_repl_commands (self ):
368347 hook = MagicMock ()
369- self ._run_interactive (["clear" ], pre_execution_hook = hook )
348+ self ._run_interactive (["clear" ], hook )
349+
370350 hook .assert_not_called ()
0 commit comments