Skip to content

Commit 6c33b58

Browse files
committed
Refactor transcript from history implementation and test
1 parent 23824e8 commit 6c33b58

File tree

3 files changed

+71
-89
lines changed

3 files changed

+71
-89
lines changed

cmd2/cmd2.py

Lines changed: 63 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3002,65 +3002,7 @@ def do_history(self, args):
30023002
except Exception as e:
30033003
self.perror('Saving {!r} - {}'.format(args.output_file, e), traceback_war=False)
30043004
elif args.transcript:
3005-
# Save the current echo state, and turn it off. We inject commands into the
3006-
# output using a different mechanism
3007-
saved_echo = self.echo
3008-
self.echo = False
3009-
3010-
# Redirect stdout to the transcript file
3011-
saved_self_stdout = self.stdout
3012-
3013-
# The problem with supporting regular expressions in transcripts
3014-
# is that they shouldn't be processed in the command, just the output.
3015-
# In addition, when we generate a transcript, any slashes in the output
3016-
# are not really intended to indicate regular expressions, so they should
3017-
# be escaped.
3018-
#
3019-
# We have to jump through some hoops here in order to catch the commands
3020-
# separately from the output and escape the slashes in the output.
3021-
transcript = ''
3022-
for history_item in history:
3023-
# build the command, complete with prompts. When we replay
3024-
# the transcript, it looks for the prompts to separate
3025-
# the command from the output
3026-
first = True
3027-
command = ''
3028-
for line in history_item.splitlines():
3029-
if first:
3030-
command += '{}{}\n'.format(self.prompt, line)
3031-
first = False
3032-
else:
3033-
command += '{}{}\n'.format(self.continuation_prompt, line)
3034-
transcript += command
3035-
# create a new string buffer and set it to stdout to catch the output
3036-
# of the command
3037-
membuf = io.StringIO()
3038-
self.stdout = membuf
3039-
# then run the command and let the output go into our buffer
3040-
self.onecmd_plus_hooks(history_item)
3041-
# rewind the buffer to the beginning
3042-
membuf.seek(0)
3043-
# get the output out of the buffer
3044-
output = membuf.read()
3045-
# and add the regex-escaped output to the transcript
3046-
transcript += output.replace('/', '\/')
3047-
3048-
# Restore stdout to its original state
3049-
self.stdout = saved_self_stdout
3050-
# Set echo back to its original state
3051-
self.echo = saved_echo
3052-
3053-
# finally, we can write the transcript out to the file
3054-
with open(args.transcript, 'w') as fout:
3055-
fout.write(transcript)
3056-
3057-
# and let the user know what we did
3058-
if len(history) > 1:
3059-
plural = 'commands and their outputs'
3060-
else:
3061-
plural = 'command and its output'
3062-
msg = '{} {} saved to transcript file {!r}'
3063-
self.pfeedback(msg.format(len(history), plural, args.transcript))
3005+
self._generate_transcript(history, args.transcript)
30643006
else:
30653007
# Display the history items retrieved
30663008
for hi in history:
@@ -3069,6 +3011,68 @@ def do_history(self, args):
30693011
else:
30703012
self.poutput(hi.pr())
30713013

3014+
def _generate_transcript(self, history, transcript_file):
3015+
"""Generate a transcript file from a given history of commands."""
3016+
# Save the current echo state, and turn it off. We inject commands into the
3017+
# output using a different mechanism
3018+
saved_echo = self.echo
3019+
self.echo = False
3020+
3021+
# Redirect stdout to the transcript file
3022+
saved_self_stdout = self.stdout
3023+
3024+
# The problem with supporting regular expressions in transcripts
3025+
# is that they shouldn't be processed in the command, just the output.
3026+
# In addition, when we generate a transcript, any slashes in the output
3027+
# are not really intended to indicate regular expressions, so they should
3028+
# be escaped.
3029+
#
3030+
# We have to jump through some hoops here in order to catch the commands
3031+
# separately from the output and escape the slashes in the output.
3032+
transcript = ''
3033+
for history_item in history:
3034+
# build the command, complete with prompts. When we replay
3035+
# the transcript, we look for the prompts to separate
3036+
# the command from the output
3037+
first = True
3038+
command = ''
3039+
for line in history_item.splitlines():
3040+
if first:
3041+
command += '{}{}\n'.format(self.prompt, line)
3042+
first = False
3043+
else:
3044+
command += '{}{}\n'.format(self.continuation_prompt, line)
3045+
transcript += command
3046+
# create a new string buffer and set it to stdout to catch the output
3047+
# of the command
3048+
membuf = io.StringIO()
3049+
self.stdout = membuf
3050+
# then run the command and let the output go into our buffer
3051+
self.onecmd_plus_hooks(history_item)
3052+
# rewind the buffer to the beginning
3053+
membuf.seek(0)
3054+
# get the output out of the buffer
3055+
output = membuf.read()
3056+
# and add the regex-escaped output to the transcript
3057+
transcript += output.replace('/', '\/')
3058+
3059+
# Restore stdout to its original state
3060+
self.stdout = saved_self_stdout
3061+
# Set echo back to its original state
3062+
self.echo = saved_echo
3063+
3064+
# finally, we can write the transcript out to the file
3065+
with open(transcript_file, 'w') as fout:
3066+
fout.write(transcript)
3067+
3068+
# and let the user know what we did
3069+
if len(history) > 1:
3070+
plural = 'commands and their outputs'
3071+
else:
3072+
plural = 'command and its output'
3073+
msg = '{} {} saved to transcript file {!r}'
3074+
self.pfeedback(msg.format(len(history), plural, transcript_file))
3075+
30723076
@with_argument_list
30733077
def do_edit(self, arglist):
30743078
"""Edit a file in a text editor.

tests/test_transcript.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,16 @@ def test_transcript(request, capsys, filename, feedback_to_output):
129129
def test_history_transcript(request, capsys):
130130
app = CmdLineApp()
131131
app.stdout = StdOut()
132-
run_cmd(app, 'help')
133-
run_cmd(app, 'orate this is\na multiline\ncommand;\n')
132+
run_cmd(app, 'orate this is\na /multiline/\ncommand;\n')
134133
run_cmd(app, 'speak /tmp/file.txt is not a regex')
135134

136-
# Get location of the expected transcript
137-
test_dir = os.path.dirname(request.module.__file__)
138-
expected_fname = os.path.join(test_dir, 'transcripts', 'expected_history.txt')
139-
with open(expected_fname) as f:
140-
lines = f.readlines()
141-
# trim off the first 7 lines so we can have a comment in the
142-
# expected_history.txt file explaining what it is
143-
expected = ''.join(lines[7:])
135+
expected = r"""(Cmd) orate this is
136+
> a /multiline/
137+
> command;
138+
this is a \/multiline\/ command
139+
(Cmd) speak /tmp/file.txt is not a regex
140+
\/tmp\/file.txt is not a regex
141+
"""
144142

145143
# make a tmp file
146144
fd, history_fname = tempfile.mkstemp(prefix='', suffix='.txt')

tests/transcripts/expected_history.txt

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)