summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven D'Aprano <steve@pearwood.info>2016-08-23 15:42:15 (GMT)
committerSteven D'Aprano <steve@pearwood.info>2016-08-23 15:42:15 (GMT)
commit6877ed3560aef64391657f634cbe00d16023201a (patch)
tree8509396753039f785fb8e07f9224b78871247357
parentf4d28d43857295cab4dc82a2bc50f5e8c90123ef (diff)
downloadcpython-6877ed3560aef64391657f634cbe00d16023201a.zip
cpython-6877ed3560aef64391657f634cbe00d16023201a.tar.gz
cpython-6877ed3560aef64391657f634cbe00d16023201a.tar.bz2
Issue #27573 make the exit message configurable.
-rw-r--r--Doc/library/code.rst18
-rw-r--r--Lib/code.py17
-rw-r--r--Lib/test/test_code_module.py20
3 files changed, 46 insertions, 9 deletions
diff --git a/Doc/library/code.rst b/Doc/library/code.rst
index c573087..4cce1fa 100644
--- a/Doc/library/code.rst
+++ b/Doc/library/code.rst
@@ -30,15 +30,19 @@ build applications which provide an interactive interpreter prompt.
``sys.ps1`` and ``sys.ps2``, and input buffering.
-.. function:: interact(banner=None, readfunc=None, local=None)
+.. function:: interact(banner=None, readfunc=None, local=None, exitmsg=None)
Convenience function to run a read-eval-print loop. This creates a new
instance of :class:`InteractiveConsole` and sets *readfunc* to be used as
the :meth:`InteractiveConsole.raw_input` method, if provided. If *local* is
provided, it is passed to the :class:`InteractiveConsole` constructor for
use as the default namespace for the interpreter loop. The :meth:`interact`
- method of the instance is then run with *banner* passed as the banner to
- use, if provided. The console object is discarded after use.
+ method of the instance is then run with *banner* and *exitmsg* passed as the
+ banner and exit message to use, if provided. The console object is discarded
+ after use.
+
+ .. versionchanged:: 3.6
+ Added *exitmsg* parameter.
.. function:: compile_command(source, filename="<input>", symbol="single")
@@ -136,7 +140,7 @@ The :class:`InteractiveConsole` class is a subclass of
interpreter objects as well as the following additions.
-.. method:: InteractiveConsole.interact(banner=None)
+.. method:: InteractiveConsole.interact(banner=None, exitmsg=None)
Closely emulate the interactive Python console. The optional *banner* argument
specify the banner to print before the first interaction; by default it prints a
@@ -144,11 +148,15 @@ interpreter objects as well as the following additions.
by the class name of the console object in parentheses (so as not to confuse
this with the real interpreter -- since it's so close!).
+ The optional *exitmsg* argument specifies an exit message printed when exiting.
+ Pass the empty string to suppress the exit message. If *exitmsg* is not given or
+ None, a default message is printed.
+
.. versionchanged:: 3.4
To suppress printing any banner, pass an empty string.
.. versionchanged:: 3.6
- Now prints a brief message when exiting.
+ Print an exit message when exiting.
.. method:: InteractiveConsole.push(line)
diff --git a/Lib/code.py b/Lib/code.py
index c8b7204..23295f4 100644
--- a/Lib/code.py
+++ b/Lib/code.py
@@ -186,7 +186,7 @@ class InteractiveConsole(InteractiveInterpreter):
"""Reset the input buffer."""
self.buffer = []
- def interact(self, banner=None):
+ def interact(self, banner=None, exitmsg=None):
"""Closely emulate the interactive Python console.
The optional banner argument specifies the banner to print
@@ -196,6 +196,11 @@ class InteractiveConsole(InteractiveInterpreter):
to confuse this with the real interpreter -- since it's so
close!).
+ The optional exitmsg argument specifies the exit message
+ printed when exiting. Pass the empty string to suppress
+ printing an exit message. If exitmsg is not given or None,
+ a default message is printed.
+
"""
try:
sys.ps1
@@ -230,7 +235,10 @@ class InteractiveConsole(InteractiveInterpreter):
self.write("\nKeyboardInterrupt\n")
self.resetbuffer()
more = 0
- self.write('now exiting %s...\n' % self.__class__.__name__)
+ if exitmsg is None:
+ self.write('now exiting %s...\n' % self.__class__.__name__)
+ elif exitmsg != '':
+ self.write('%s\n' % exitmsg)
def push(self, line):
"""Push a line to the interpreter.
@@ -268,7 +276,7 @@ class InteractiveConsole(InteractiveInterpreter):
-def interact(banner=None, readfunc=None, local=None):
+def interact(banner=None, readfunc=None, local=None, exitmsg=None):
"""Closely emulate the interactive Python interpreter.
This is a backwards compatible interface to the InteractiveConsole
@@ -280,6 +288,7 @@ def interact(banner=None, readfunc=None, local=None):
banner -- passed to InteractiveConsole.interact()
readfunc -- if not None, replaces InteractiveConsole.raw_input()
local -- passed to InteractiveInterpreter.__init__()
+ exitmsg -- passed to InteractiveConsole.interact()
"""
console = InteractiveConsole(local)
@@ -290,7 +299,7 @@ def interact(banner=None, readfunc=None, local=None):
import readline
except ImportError:
pass
- console.interact(banner)
+ console.interact(banner, exitmsg)
if __name__ == "__main__":
diff --git a/Lib/test/test_code_module.py b/Lib/test/test_code_module.py
index 08ba3f3..1a8f699 100644
--- a/Lib/test/test_code_module.py
+++ b/Lib/test/test_code_module.py
@@ -80,6 +80,7 @@ class TestInteractiveConsole(unittest.TestCase):
self.assertEqual(len(self.stderr.method_calls), 2)
def test_exit_msg(self):
+ # default exit message
self.infunc.side_effect = EOFError('Finished')
self.console.interact(banner='')
self.assertEqual(len(self.stderr.method_calls), 2)
@@ -87,6 +88,25 @@ class TestInteractiveConsole(unittest.TestCase):
expected = 'now exiting InteractiveConsole...\n'
self.assertEqual(err_msg, ['write', (expected,), {}])
+ # no exit message
+ self.stderr.reset_mock()
+ self.infunc.side_effect = EOFError('Finished')
+ self.console.interact(banner='', exitmsg='')
+ self.assertEqual(len(self.stderr.method_calls), 1)
+
+ # custom exit message
+ self.stderr.reset_mock()
+ message = (
+ 'bye! \N{GREEK SMALL LETTER ZETA}\N{CYRILLIC SMALL LETTER ZHE}'
+ )
+ self.infunc.side_effect = EOFError('Finished')
+ self.console.interact(banner='', exitmsg=message)
+ self.assertEqual(len(self.stderr.method_calls), 2)
+ err_msg = self.stderr.method_calls[1]
+ expected = message + '\n'
+ self.assertEqual(err_msg, ['write', (expected,), {}])
+
+
def test_cause_tb(self):
self.infunc.side_effect = ["raise ValueError('') from AttributeError",
EOFError('Finished')]