diff --git a/IPython/Logger.py b/IPython/Logger.py index b3a58c1..4cbc5a3 100644 --- a/IPython/Logger.py +++ b/IPython/Logger.py @@ -2,7 +2,7 @@ """ Logger class for IPython's logging facilities. -$Id: Logger.py 1077 2006-01-24 18:15:27Z vivainio $ +$Id: Logger.py 1335 2006-05-30 06:02:44Z fperez $ """ #***************************************************************************** @@ -46,6 +46,9 @@ class Logger(object): self.logmode = logmode self.logfile = None + # Whether to log raw or processed input + self.log_raw_input = False + # whether to also log output self.log_output = False @@ -67,7 +70,7 @@ class Logger(object): logmode = property(_get_mode,_set_mode) def logstart(self,logfname=None,loghead=None,logmode=None, - log_output=False,timestamp=False): + log_output=False,timestamp=False,log_raw_input=False): """Generate a new log-file with a default header. Raises RuntimeError if the log has already been started""" @@ -78,12 +81,15 @@ class Logger(object): self.log_active = True - # The three parameters can override constructor defaults - if logfname: self.logfname = logfname - if loghead: self.loghead = loghead - if logmode: self.logmode = logmode + # The parameters can override constructor defaults + if logfname is not None: self.logfname = logfname + if loghead is not None: self.loghead = loghead + if logmode is not None: self.logmode = logmode + + # Parameters not part of the constructor self.timestamp = timestamp self.log_output = log_output + self.log_raw_input = log_raw_input # init depending on the log mode requested isfile = os.path.isfile @@ -166,11 +172,22 @@ which already exists. But you must first start the logging process with print 'Timestamping :',self.timestamp print 'State :',state - def log(self, line,continuation=None): - """Write the line to a log and create input cache variables _i*.""" + def log(self,line_ori,line_mod,continuation=None): + """Write the line to a log and create input cache variables _i*. + + Inputs: + + - line_ori: unmodified input line from the user. This is not + necessarily valid Python. + + - line_mod: possibly modified input, such as the transformations made + by input prefilters or input handlers of various kinds. This should + always be valid Python. + + - continuation: if True, indicates this is part of multi-line input.""" # update the auto _i tables - #print '***logging line',line # dbg + #print '***logging line',line_mod # dbg #print '***cache_count', self.shell.outputcache.prompt_count # dbg try: input_hist = self.shell.user_ns['_ih'] @@ -178,13 +195,13 @@ which already exists. But you must first start the logging process with print 'userns:',self.shell.user_ns.keys() return - if not continuation and line: + if not continuation and line_mod: self._iii = self._ii self._ii = self._i self._i = self._i00 # put back the final \n of every input line - self._i00 = line+'\n' - #print 'Logging input:<%s>' % line # dbg + self._i00 = line_mod+'\n' + #print 'Logging input:<%s>' % line_mod # dbg input_hist.append(self._i00) #print '---[%s]' % (len(input_hist)-1,) # dbg @@ -205,11 +222,17 @@ which already exists. But you must first start the logging process with in_num = self.shell.outputcache.prompt_count = last_num new_i = '_i%s' % in_num if continuation: - self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line) + self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod) input_hist[in_num] = self._i00 to_main[new_i] = self._i00 self.shell.user_ns.update(to_main) - self.log_write(line) + + # Write the log line, but decide which one according to the + # log_raw_input flag, set when the log is started. + if self.log_raw_input: + self.log_write(line_ori) + else: + self.log_write(line_mod) def log_write(self,data,kind='input'): """Write data to the log file, if active""" diff --git a/IPython/Magic.py b/IPython/Magic.py index 9727ebe..2af8129 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 1322 2006-05-24 07:51:39Z fperez $""" +$Id: Magic.py 1335 2006-05-30 06:02:44Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -991,7 +991,7 @@ Currently the magic system has the following functions:\n""" def magic_logstart(self,parameter_s=''): """Start logging anywhere in a session. - %logstart [-o|-t] [log_name [log_mode]] + %logstart [-o|-r|-t] [log_name [log_mode]] If no name is given, it defaults to a file named 'ipython_log.py' in your current directory, in 'rotate' mode (see below). @@ -1020,11 +1020,18 @@ Currently the magic system has the following functions:\n""" awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py + -r: log 'raw' input. Normally, IPython's logs contain the processed + input, so that user lines are logged in their final form, converted + into valid Python. For example, %Exit is logged as + '_ip.magic("Exit"). If the -r flag is given, all input is logged + exactly as typed, with no transformations applied. + -t: put timestamps before each input line logged (these are put in comments).""" - opts,par = self.parse_options(parameter_s,'ot') + opts,par = self.parse_options(parameter_s,'ort') log_output = 'o' in opts + log_raw_input = 'r' in opts timestamp = 't' in opts rc = self.shell.rc @@ -1051,7 +1058,7 @@ Currently the magic system has the following functions:\n""" loghead = self.shell.loghead_tpl % (rc.opts,rc.args) try: started = logger.logstart(logfname,loghead,logmode, - log_output,timestamp) + log_output,timestamp,log_raw_input) except: rc.opts.logfile = old_logfile warn("Couldn't start log: %s" % sys.exc_info()[1]) @@ -1063,16 +1070,21 @@ Currently the magic system has the following functions:\n""" # disable timestamping for the previous history, since we've # lost those already (no time machine here). logger.timestamp = False + + if log_raw_input: + input_hist = self.shell.input_hist_raw + else: + input_hist = self.shell.input_hist + if log_output: log_write = logger.log_write - input_hist = self.shell.input_hist output_hist = self.shell.output_hist for n in range(1,len(input_hist)-1): log_write(input_hist[n].rstrip()) if n in output_hist: log_write(repr(output_hist[n]),'output') else: - logger.log_write(self.shell.input_hist[1:]) + logger.log_write(input_hist[1:]) if timestamp: # re-enable timestamping logger.timestamp = True diff --git a/IPython/iplib.py b/IPython/iplib.py index 41d114c..8c75deb 100644 --- a/IPython/iplib.py +++ b/IPython/iplib.py @@ -6,7 +6,7 @@ Requires Python 2.3 or newer. This file contains all the classes and helper functions specific to IPython. -$Id: iplib.py 1334 2006-05-30 03:36:04Z fperez $ +$Id: iplib.py 1335 2006-05-30 06:02:44Z fperez $ """ #***************************************************************************** @@ -2031,7 +2031,7 @@ want to merge them back into the new files.""" % locals() # aliases won't work in indented sections. transformed = self.transform_alias(iFun, theRest) line_out = '%s_ip.system(%s)' % (pre, make_quoted_expr( transformed )) - self.log(line_out,continue_prompt) + self.log(line,line_out,continue_prompt) return line_out def handle_shell_escape(self, line, continue_prompt=None, @@ -2053,7 +2053,7 @@ want to merge them back into the new files.""" % locals() cmd=line.lstrip().lstrip('!') line_out = '%s_ip.system(%s)' % (pre,make_quoted_expr(cmd)) # update cache/log and return - self.log(line_out,continue_prompt) + self.log(line,line_out,continue_prompt) return line_out def handle_magic(self, line, continue_prompt=None, @@ -2062,7 +2062,7 @@ want to merge them back into the new files.""" % locals() cmd = '%s_ip.magic(%s)' % (pre,make_quoted_expr(iFun + " " + theRest)) - self.log(cmd,continue_prompt) + self.log(line,cmd,continue_prompt) #print 'in handle_magic, cmd=<%s>' % cmd # dbg return cmd @@ -2074,7 +2074,7 @@ want to merge them back into the new files.""" % locals() # This should only be active for single-line input! if continue_prompt: - self.log(line,continue_prompt) + self.log(line,line,continue_prompt) return line auto_rewrite = True @@ -2115,7 +2115,7 @@ want to merge them back into the new files.""" % locals() print >>Term.cout, self.outputcache.prompt1.auto_rewrite() + newcmd # log what is now valid Python, not the actual user input (without the # final newline) - self.log(newcmd,continue_prompt) + self.log(line,newcmd,continue_prompt) return newcmd def handle_help(self, line, continue_prompt=None, @@ -2136,7 +2136,7 @@ want to merge them back into the new files.""" % locals() line = line[1:] elif line[-1]==self.ESC_HELP: line = line[:-1] - self.log('#?'+line) + self.log(line,'#?'+line,continue_prompt) if line: self.magic_pinfo(line) else: diff --git a/doc/ChangeLog b/doc/ChangeLog index e3e4f07..246c473 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,9 @@ +2006-05-30 Fernando Perez + + * IPython/Logger.py (Logger.logstart): add option to log raw input + instead of the processed one. A -r flag was added to the + %logstart magic used for controlling logging. + 2006-05-29 Fernando Perez * IPython/iplib.py (InteractiveShell.__init__): add check for the