Skip to content

Commit ab84ee6

Browse files
Fix handling of arg prompt and add tests for it
- and for `unrecoverable` exceptions
1 parent 707bd38 commit ab84ee6

File tree

2 files changed

+49
-39
lines changed

2 files changed

+49
-39
lines changed

Lib/_pyrepl/reader.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,10 @@ def get_prompt(self, lineno: int, cursor_on_line: bool) -> str:
551551
"""Return what should be in the left-hand margin for line
552552
'lineno'."""
553553
if self.arg is not None and cursor_on_line:
554-
prompt = self.__get_prompt_str(f"(arg: {self.arg}) ", DEFAULT_PS1)
554+
prompt = DEFAULT_PS1
555+
arg = self.__get_prompt_str(self.arg, "")
556+
if arg:
557+
prompt = f"(arg: {self.arg}) "
555558
elif self.paste_mode and not self.in_bracketed_paste:
556559
prompt = "(paste) "
557560
elif "\n" in self.buffer:

Lib/test/test_pyrepl/test_reader.py

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -281,15 +281,15 @@ def test_prompt_length(self):
281281
self.assertEqual(l, 5)
282282

283283
def test_prompt_ps1_raise_exception(self):
284-
# Handles simple ASCII prompt
284+
# Handles exceptions from ps1 prompt
285285
class Prompt:
286286
def __str__(self): 1/0
287287

288288
def prepare_reader_keep_prompts(*args, **kwargs):
289289
reader = prepare_reader(*args, **kwargs)
290290
del reader.get_prompt
291291
reader.ps1 = Prompt()
292-
reader.ps2 = "+++ "
292+
reader.ps2 = "... "
293293
reader.ps3 = "... "
294294
reader.ps4 = ""
295295
reader.can_colorize = False
@@ -305,23 +305,23 @@ def prepare_reader_keep_prompts(*args, **kwargs):
305305
prompt = reader.get_prompt(0, False)
306306
self.assertEqual(prompt, DEFAULT_PS1)
307307

308-
def test_prompt_ps2_raise_exception(self):
309-
# Handles simple ASCII prompt
308+
def test_prompt_ps2_ps3_ps4_raise_exception(self):
309+
# Handles exceptions from ps2, ps3 and ps4 prompts
310310
class Prompt:
311311
def __str__(self): 1/0
312312

313313
def prepare_reader_keep_prompts(*args, **kwargs):
314314
reader = prepare_reader(*args, **kwargs)
315315
del reader.get_prompt
316-
reader.ps1 = "+++ "
316+
reader.ps1 = Prompt()
317317
reader.ps2 = Prompt()
318-
reader.ps3 = "--- "
319-
reader.ps4 = "~~~ "
318+
reader.ps3 = Prompt()
319+
reader.ps4 = Prompt()
320320
reader.can_colorize = False
321321
reader.paste_mode = False
322322
return reader
323323

324-
events = code_to_events("if some_condition:\nsome_function()")
324+
events = code_to_events("if some_condition:\nsome_function()\nsome_function()")
325325
reader, _ = handle_events_narrow_console(
326326
events,
327327
prepare_reader=prepare_reader_keep_prompts,
@@ -330,43 +330,22 @@ def prepare_reader_keep_prompts(*args, **kwargs):
330330
prompt = reader.get_prompt(0, False)
331331
self.assertEqual(prompt, DEFAULT_PS2)
332332

333-
def test_prompt_ps3_raise_exception(self):
334-
# Handles simple ASCII prompt
335-
class Prompt:
336-
def __str__(self): 1/0
337-
338-
def prepare_reader_keep_prompts(*args, **kwargs):
339-
reader = prepare_reader(*args, **kwargs)
340-
del reader.get_prompt
341-
reader.ps1 = "+++ "
342-
reader.ps2 = "--- "
343-
reader.ps3 = Prompt()
344-
reader.ps4 = ""
345-
reader.can_colorize = False
346-
reader.paste_mode = False
347-
return reader
348-
349-
events = code_to_events("if some_condition:\nsome_function()")
350-
reader, _ = handle_events_narrow_console(
351-
events,
352-
prepare_reader=prepare_reader_keep_prompts,
353-
)
354-
355333
prompt = reader.get_prompt(1, False)
356334
self.assertEqual(prompt, DEFAULT_PS3)
357335

358-
def test_prompt_ps4_raise_exception(self):
359-
# Handles simple ASCII prompt
336+
prompt = reader.get_prompt(2, False)
337+
self.assertEqual(prompt, DEFAULT_PS4)
338+
339+
def test_prompt_arg_raise_exception(self):
340+
# Handles exceptions from arg prompt
360341
class Prompt:
361342
def __str__(self): 1/0
362343

344+
def __rmul__(self, b): return b
345+
363346
def prepare_reader_keep_prompts(*args, **kwargs):
364347
reader = prepare_reader(*args, **kwargs)
365348
del reader.get_prompt
366-
reader.ps1 = "+++ "
367-
reader.ps2 = "--- "
368-
reader.ps3 = "~~~ "
369-
reader.ps4 = Prompt()
370349
reader.can_colorize = False
371350
reader.paste_mode = False
372351
return reader
@@ -377,8 +356,36 @@ def prepare_reader_keep_prompts(*args, **kwargs):
377356
prepare_reader=prepare_reader_keep_prompts,
378357
)
379358

380-
prompt = reader.get_prompt(1, False)
381-
self.assertEqual(prompt, DEFAULT_PS4)
359+
reader.arg = Prompt()
360+
prompt = reader.get_prompt(0, True)
361+
self.assertEqual(prompt, DEFAULT_PS1)
362+
363+
def test_prompt_raise_exception(self):
364+
# Tests unrecoverable exceptions from prompts
365+
cases = [
366+
(MemoryError, "No memory for prompt"),
367+
(SystemError, "System error for prompt"),
368+
]
369+
for cls, msg in cases:
370+
with self.subTest(msg):
371+
372+
class Prompt:
373+
def __str__(self): raise cls(msg)
374+
375+
def prepare_reader_keep_prompts(*args, **kwargs):
376+
reader = prepare_reader(*args, **kwargs)
377+
del reader.get_prompt
378+
reader.ps1 = Prompt()
379+
reader.can_colorize = False
380+
reader.paste_mode = False
381+
return reader
382+
383+
with self.assertRaisesRegex(cls, msg):
384+
events = code_to_events("a=1")
385+
handle_events_narrow_console(
386+
events,
387+
prepare_reader=prepare_reader_keep_prompts,
388+
)
382389

383390
def test_completions_updated_on_key_press(self):
384391
namespace = {"itertools": itertools}

0 commit comments

Comments
 (0)