@@ -229,7 +229,7 @@ def pyreadline_remove_history_item(pos):
229229 pass
230230
231231
232- __version__ = '0.8.7 '
232+ __version__ = '0.8.8 '
233233
234234# Pyparsing enablePackrat() can greatly speed up parsing, but problems have been seen in Python 3 in the past
235235pyparsing .ParserElement .enablePackrat ()
@@ -2470,7 +2470,7 @@ def onecmd_plus_hooks(self, line):
24702470 if self .timing :
24712471 self .pfeedback ('Elapsed: %s' % str (datetime .datetime .now () - timestart ))
24722472 finally :
2473- if self .allow_redirection :
2473+ if self .allow_redirection and self . redirecting :
24742474 self ._restore_output (statement )
24752475 except EmptyStatement :
24762476 pass
@@ -2586,7 +2586,11 @@ def _redirect_output(self, statement):
25862586 mode = 'w'
25872587 if statement .parsed .output == 2 * self .redirector :
25882588 mode = 'a'
2589- sys .stdout = self .stdout = open (os .path .expanduser (statement .parsed .outputTo ), mode )
2589+ try :
2590+ sys .stdout = self .stdout = open (os .path .expanduser (statement .parsed .outputTo ), mode )
2591+ except (FILE_NOT_FOUND_ERROR , IOError ) as ex :
2592+ self .perror ('Not Redirecting because - {}' .format (ex ), traceback_war = False )
2593+ self .redirecting = False
25902594 else :
25912595 sys .stdout = self .stdout = tempfile .TemporaryFile (mode = "w+" )
25922596 if statement .parsed .output == '>>' :
@@ -3638,34 +3642,7 @@ def do_history(self, args):
36383642 except Exception as e :
36393643 self .perror ('Saving {!r} - {}' .format (args .output_file , e ), traceback_war = False )
36403644 elif args .transcript :
3641- # Make sure echo is on so commands print to standard out
3642- saved_echo = self .echo
3643- self .echo = True
3644-
3645- # Redirect stdout to the transcript file
3646- saved_self_stdout = self .stdout
3647- self .stdout = open (args .transcript , 'w' )
3648-
3649- # Run all of the commands in the history with output redirected to transcript and echo on
3650- self .runcmds_plus_hooks (history )
3651-
3652- # Restore stdout to its original state
3653- self .stdout .close ()
3654- self .stdout = saved_self_stdout
3655-
3656- # Set echo back to its original state
3657- self .echo = saved_echo
3658-
3659- # Post-process the file to escape un-escaped "/" regex escapes
3660- with open (args .transcript , 'r' ) as fin :
3661- data = fin .read ()
3662- post_processed_data = data .replace ('/' , '\/' )
3663- with open (args .transcript , 'w' ) as fout :
3664- fout .write (post_processed_data )
3665-
3666- plural = 's' if len (history ) > 1 else ''
3667- self .pfeedback ('{} command{} and outputs saved to transcript file {!r}' .format (len (history ), plural ,
3668- args .transcript ))
3645+ self ._generate_transcript (history , args .transcript )
36693646 else :
36703647 # Display the history items retrieved
36713648 for hi in history :
@@ -3674,6 +3651,73 @@ def do_history(self, args):
36743651 else :
36753652 self .poutput (hi .pr ())
36763653
3654+ def _generate_transcript (self , history , transcript_file ):
3655+ """Generate a transcript file from a given history of commands."""
3656+ # Save the current echo state, and turn it off. We inject commands into the
3657+ # output using a different mechanism
3658+ import io
3659+
3660+ saved_echo = self .echo
3661+ self .echo = False
3662+
3663+ # Redirect stdout to the transcript file
3664+ saved_self_stdout = self .stdout
3665+
3666+ # The problem with supporting regular expressions in transcripts
3667+ # is that they shouldn't be processed in the command, just the output.
3668+ # In addition, when we generate a transcript, any slashes in the output
3669+ # are not really intended to indicate regular expressions, so they should
3670+ # be escaped.
3671+ #
3672+ # We have to jump through some hoops here in order to catch the commands
3673+ # separately from the output and escape the slashes in the output.
3674+ transcript = ''
3675+ for history_item in history :
3676+ # build the command, complete with prompts. When we replay
3677+ # the transcript, we look for the prompts to separate
3678+ # the command from the output
3679+ first = True
3680+ command = ''
3681+ for line in history_item .splitlines ():
3682+ if first :
3683+ command += '{}{}\n ' .format (self .prompt , line )
3684+ first = False
3685+ else :
3686+ command += '{}{}\n ' .format (self .continuation_prompt , line )
3687+ transcript += command
3688+ # create a new string buffer and set it to stdout to catch the output
3689+ # of the command
3690+ membuf = io .StringIO ()
3691+ self .stdout = membuf
3692+ # then run the command and let the output go into our buffer
3693+ self .onecmd_plus_hooks (history_item )
3694+ # rewind the buffer to the beginning
3695+ membuf .seek (0 )
3696+ # get the output out of the buffer
3697+ output = membuf .read ()
3698+ # and add the regex-escaped output to the transcript
3699+ transcript += output .replace ('/' , '\/' )
3700+
3701+ # Restore stdout to its original state
3702+ self .stdout = saved_self_stdout
3703+ # Set echo back to its original state
3704+ self .echo = saved_echo
3705+
3706+ # finally, we can write the transcript out to the file
3707+ try :
3708+ with open (transcript_file , 'w' ) as fout :
3709+ fout .write (transcript )
3710+ except (FILE_NOT_FOUND_ERROR , IOError ) as ex :
3711+ self .perror ('Failed to save transcript: {}' .format (ex ), traceback_war = False )
3712+ else :
3713+ # and let the user know what we did
3714+ if len (history ) > 1 :
3715+ plural = 'commands and their outputs'
3716+ else :
3717+ plural = 'command and its output'
3718+ msg = '{} {} saved to transcript file {!r}'
3719+ self .pfeedback (msg .format (len (history ), plural , transcript_file ))
3720+
36773721 @with_argument_list
36783722 def do_edit (self , arglist ):
36793723 """Edit a file in a text editor.
0 commit comments