Skip to content

Commit 3928910

Browse files
committed
Added load -r flag for recording a transcript based on a script file
The load command now supports the -r/--record_transcript flag for recording a transcript file based on a script file.
1 parent 83a2872 commit 3928910

File tree

3 files changed

+46
-14
lines changed

3 files changed

+46
-14
lines changed

cmd2/cmd2.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3332,18 +3332,17 @@ def do_history(self, args: argparse.Namespace) -> None:
33323332
for hi in history:
33333333
self.poutput(hi.pr(script=args.script, expanded=args.expanded, verbose=args.verbose))
33343334

3335-
def _generate_transcript(self, history: List[HistoryItem], transcript_file: str) -> None:
3335+
def _generate_transcript(self, history: List[Union[HistoryItem, str]], transcript_file: str) -> None:
33363336
"""Generate a transcript file from a given history of commands."""
3337-
# Save the current echo state, and turn it off. We inject commands into the
3338-
# output using a different mechanism
33393337
import io
33403338

3339+
# Disable echo and redirection while we manually redirect stdout to a StringIO buffer
3340+
saved_allow_redirection = self.allow_redirection
33413341
saved_echo = self.echo
3342+
saved_stdout = self.stdout
3343+
self.allow_redirection = False
33423344
self.echo = False
33433345

3344-
# Redirect stdout to the transcript file
3345-
saved_self_stdout = self.stdout
3346-
33473346
# The problem with supporting regular expressions in transcripts
33483347
# is that they shouldn't be processed in the command, just the output.
33493348
# In addition, when we generate a transcript, any slashes in the output
@@ -3379,10 +3378,10 @@ def _generate_transcript(self, history: List[HistoryItem], transcript_file: str)
33793378
# and add the regex-escaped output to the transcript
33803379
transcript += output.replace('/', r'\/')
33813380

3382-
# Restore stdout to its original state
3383-
self.stdout = saved_self_stdout
3384-
# Set echo back to its original state
3381+
# Restore altered attributes to their original state
3382+
self.allow_redirection = saved_allow_redirection
33853383
self.echo = saved_echo
3384+
self.stdout = saved_stdout
33863385

33873386
# finally, we can write the transcript out to the file
33883387
try:
@@ -3438,9 +3437,21 @@ def do_eos(self, _: argparse.Namespace) -> None:
34383437
load_description = ("Run commands in script file that is encoded as either ASCII or UTF-8 text\n"
34393438
"\n"
34403439
"Script should contain one command per line, just like the command would be\n"
3441-
"typed in the console.")
3440+
"typed in the console.\n"
3441+
"\n"
3442+
"It loads commands from a script file into a queue and then the normal cmd2\n"
3443+
"REPL resumes control and executes the commands in the queue in FIFO order.\n"
3444+
"If you attempt to redirect/pipe a load command, it will capture the output\n"
3445+
"of the load command itself, not what it adds to the queue.\n"
3446+
"\n"
3447+
"If the -r/--record_transcript flag is used, this command instead records\n"
3448+
"the output of the script commands to a transcript for testing purposes.\n"
3449+
)
34423450

34433451
load_parser = ACArgumentParser(description=load_description)
3452+
setattr(load_parser.add_argument('-r', '--record_transcript',
3453+
help='record the output of the script as a transcript file'),
3454+
ACTION_ARG_CHOICES, ('path_complete',))
34443455
setattr(load_parser.add_argument('script_path', help="path to the script file"),
34453456
ACTION_ARG_CHOICES, ('path_complete',))
34463457

@@ -3474,11 +3485,16 @@ def do_load(self, args: argparse.Namespace) -> None:
34743485
# command queue. Add an "end of script (eos)" command to cleanup the
34753486
# self._script_dir list when done.
34763487
with open(expanded_path, encoding='utf-8') as target:
3477-
self.cmdqueue = target.read().splitlines() + ['eos'] + self.cmdqueue
3488+
script_commands = target.read().splitlines()
34783489
except OSError as ex: # pragma: no cover
34793490
self.perror("Problem accessing script from '{}': {}".format(expanded_path, ex))
34803491
return
34813492

3493+
if args.record_transcript:
3494+
self._generate_transcript(script_commands, args.record_transcript)
3495+
return
3496+
3497+
self.cmdqueue = script_commands + ['eos'] + self.cmdqueue
34823498
self._script_dir.append(os.path.dirname(expanded_path))
34833499

34843500
relative_load_description = load_description

docs/freefeatures.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ Both ASCII and UTF-8 encoded unicode text files are supported.
1919

2020
Simply include one command per line, typed exactly as you would inside a ``cmd2`` application.
2121

22+
The ``load`` command loads commands from a script file into a queue and then the normal cmd2 REPL
23+
resumes control and executes the commands in the queue in FIFO order. A side effect of this
24+
is that if you redirect/pipe the output of a load command, it will redirect the output of the ``load``
25+
command itself, but will NOT redirect the output of the command loaded from the script file.
26+
2227
.. automethod:: cmd2.cmd2.Cmd.do_load
2328

2429
.. automethod:: cmd2.cmd2.Cmd.do__relative_load

docs/transcript.rst

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ from commands that produce dynamic or variable output.
1313
Creating a transcript
1414
=====================
1515

16-
Automatically
17-
-------------
18-
A transcript can automatically generated based upon commands previously executed in the *history*::
16+
Automatically from history
17+
--------------------------
18+
A transcript can automatically generated based upon commands previously executed in the *history* using ``history -t``::
1919

2020
(Cmd) help
2121
...
@@ -32,6 +32,17 @@ This is by far the easiest way to generate a transcript.
3232
of the ``cmd2.Cmd`` class ensure that output is properly redirected when redirecting to a file, piping to a shell
3333
command, and when generating a transcript.
3434

35+
Automatically from a script file
36+
--------------------------------
37+
A transcript can also be automatically generated from a script file using ``load -r``::
38+
39+
(Cmd) load scripts/script.txt -r transcript.txt
40+
2 commands and their outputs saved to transcript file 'transcript.txt'
41+
(Cmd)
42+
43+
This is a particularly attractive option for automatically regenerating transcripts for regression testing as your ``cmd2``
44+
application changes.
45+
3546
Manually
3647
--------
3748
Here's a transcript created from ``python examples/example.py``::

0 commit comments

Comments
 (0)