##// END OF EJS Templates
Major cleanups and changes, see changelog/changeset for full details.
fperez -
r60:35e7be3d
parent child
Show More
@@ -2,12 +2,12
2 """
2 """
3 Logger class for IPython's logging facilities.
3 Logger class for IPython's logging facilities.
4
4
5 $Id: Logger.py 958 2005-12-27 23:17:51Z fperez $
5 $Id: Logger.py 966 2005-12-29 08:34:07Z fperez $
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
9 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
10 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
10 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
@@ -24,61 +24,96 __license__ = Release.license
24 # Python standard modules
24 # Python standard modules
25 import glob
25 import glob
26 import os
26 import os
27 import sys
27 import time
28
29 # Homebrewed
30 from IPython.genutils import *
31
28
32 #****************************************************************************
29 #****************************************************************************
33 # FIXME: The logger class shouldn't be a mixin, it throws too many things into
30 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
34 # the InteractiveShell namespace. Rather make it a standalone tool, and create
31 # ipython and does input cache management. Finish cleanup later...
35 # a Logger instance in InteractiveShell that uses it. Doing this will require
32
36 # tracking down a *lot* of nasty uses of the Logger attributes in
33 class Logger(object):
37 # InteractiveShell, but will clean up things quite a bit.
34 """A Logfile class with different policies for file creation"""
38
35
39 class Logger:
36 def __init__(self,shell,logfname='Logger.log',loghead='',logmode='over'):
40 """A Logfile Mixin class with different policies for file creation"""
37
41
42 # FIXME: once this isn't a mixin, log_ns should just be 'namespace', since the
43 # names won't collide anymore.
44 def __init__(self,log_ns):
45 self._i00,self._i,self._ii,self._iii = '','','',''
38 self._i00,self._i,self._ii,self._iii = '','','',''
46 self.do_full_cache = 0 # FIXME. There's also a do_full.. in OutputCache
47 self.log_ns = log_ns
48 # defaults
49 self.LOGMODE = 'backup'
50 self.defname = 'logfile'
51
52 def create_log(self,header='',fname='',defname='.Logger.log'):
53 """Generate a new log-file with a default header"""
54 if fname:
55 self.LOG = fname
56
39
57 if self.LOG:
40 # this is the full ipython instance, we need some attributes from it
58 self.logfname = self.LOG
41 # which won't exist until later. What a mess, clean up later...
59 else:
42 self.shell = shell
60 self.logfname = defname
43
44 self.logfname = logfname
45 self.loghead = loghead
46 self.logmode = logmode
47 self.logfile = None
48
49 # whether to also log output
50 self.log_output = False
51
52 # whether to put timestamps before each log entry
53 self.timestamp = False
54
55 # activity control flags
56 self.log_active = False
57
58 # logmode is a validated property
59 def _set_mode(self,mode):
60 if mode not in ['append','backup','global','over','rotate']:
61 raise ValueError,'invalid log mode %s given' % mode
62 self._logmode = mode
63
64 def _get_mode(self):
65 return self._logmode
66
67 logmode = property(_get_mode,_set_mode)
68
69 def logstart(self,logfname=None,loghead=None,logmode=None,
70 log_output=False,timestamp=False):
71 """Generate a new log-file with a default header.
72
73 Raises RuntimeError if the log has already been started"""
74
75 if self.logfile is not None:
76 raise RuntimeError('Log file is already active: %s' %
77 self.logfname)
61
78
62 if self.LOGMODE == 'over':
79 self.log_active = True
63 if os.path.isfile(self.logfname):
80
64 os.remove(self.logfname)
81 # The three parameters can override constructor defaults
65 self.logfile = open(self.logfname,'w')
82 if logfname: self.logfname = logfname
66 if self.LOGMODE == 'backup':
83 if loghead: self.loghead = loghead
67 if os.path.isfile(self.logfname):
84 if logmode: self.logmode = logmode
85 self.timestamp = timestamp
86 self.log_output = log_output
87
88 # init depending on the log mode requested
89 isfile = os.path.isfile
90 logmode = self.logmode
91
92 if logmode == 'append':
93 self.logfile = open(self.logfname,'a')
94
95 elif logmode == 'backup':
96 if isfile(self.logfname):
68 backup_logname = self.logfname+'~'
97 backup_logname = self.logfname+'~'
69 # Manually remove any old backup, since os.rename may fail
98 # Manually remove any old backup, since os.rename may fail
70 # under Windows.
99 # under Windows.
71 if os.path.isfile(backup_logname):
100 if isfile(backup_logname):
72 os.remove(backup_logname)
101 os.remove(backup_logname)
73 os.rename(self.logfname,backup_logname)
102 os.rename(self.logfname,backup_logname)
74 self.logfile = open(self.logfname,'w')
103 self.logfile = open(self.logfname,'w')
75 elif self.LOGMODE == 'global':
104
76 self.logfname = os.path.join(self.home_dir, self.defname)
105 elif logmode == 'global':
106 self.logfname = os.path.join(self.shell.home_dir,self.logfname)
77 self.logfile = open(self.logfname, 'a')
107 self.logfile = open(self.logfname, 'a')
78 self.LOG = self.logfname
108
79 elif self.LOGMODE == 'rotate':
109 elif logmode == 'over':
80 if os.path.isfile(self.logfname):
110 if isfile(self.logfname):
81 if os.path.isfile(self.logfname+'.001~'):
111 os.remove(self.logfname)
112 self.logfile = open(self.logfname,'w')
113
114 elif logmode == 'rotate':
115 if isfile(self.logfname):
116 if isfile(self.logfname+'.001~'):
82 old = glob.glob(self.logfname+'.*~')
117 old = glob.glob(self.logfname+'.*~')
83 old.sort()
118 old.sort()
84 old.reverse()
119 old.reverse()
@@ -88,71 +123,56 class Logger:
88 os.rename(f, root+'.'+`num`.zfill(3)+'~')
123 os.rename(f, root+'.'+`num`.zfill(3)+'~')
89 os.rename(self.logfname, self.logfname+'.001~')
124 os.rename(self.logfname, self.logfname+'.001~')
90 self.logfile = open(self.logfname,'w')
125 self.logfile = open(self.logfname,'w')
91 elif self.LOGMODE == 'append':
92 self.logfile = open(self.logfname,'a')
93
126
94 if self.LOGMODE != 'append':
127 if logmode != 'append':
95 self.logfile.write(header)
128 self.logfile.write(self.loghead)
96 self.logfile.flush()
97
129
98 def logstart(self, header='',parameter_s = ''):
130 self.logfile.flush()
99 if not hasattr(self, 'LOG'):
100 logfname = self.LOG or parameter_s or './'+self.defname
101 self.create_log(header,logfname)
102 elif parameter_s and hasattr(self,'logfname') and \
103 parameter_s != self.logfname:
104 self.close_log()
105 self.create_log(header,parameter_s)
106
107 self._dolog = 1
108
131
109 def switch_log(self,val):
132 def switch_log(self,val):
110 """Switch logging on/off. val should be ONLY 0 or 1."""
133 """Switch logging on/off. val should be ONLY a boolean."""
111
134
112 if not val in [0,1]:
135 if val not in [False,True,0,1]:
113 raise ValueError, \
136 raise ValueError, \
114 'Call switch_log ONLY with 0 or 1 as argument, not with:',val
137 'Call switch_log ONLY with a boolean argument, not with:',val
115
138
116 label = {0:'OFF',1:'ON'}
139 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
117
140
118 try:
141 if self.logfile is None:
119 _ = self.logfile
120 except AttributeError:
121 print """
142 print """
122 Logging hasn't been started yet (use %logstart for that).
143 Logging hasn't been started yet (use logstart for that).
123
144
124 %logon/%logoff are for temporarily starting and stopping logging for a logfile
145 %logon/%logoff are for temporarily starting and stopping logging for a logfile
125 which already exists. But you must first start the logging process with
146 which already exists. But you must first start the logging process with
126 %logstart (optionally giving a logfile name)."""
147 %logstart (optionally giving a logfile name)."""
127
148
128 else:
149 else:
129 if self._dolog == val:
150 if self.log_active == val:
130 print 'Logging is already',label[val]
151 print 'Logging is already',label[val]
131 else:
152 else:
132 print 'Switching logging',label[val]
153 print 'Switching logging',label[val]
133 self._dolog = 1 - self._dolog
154 self.log_active = not self.log_active
155 self.log_active_out = self.log_active
134
156
135 def logstate(self):
157 def logstate(self):
136 """Print a status message about the logger."""
158 """Print a status message about the logger."""
137 try:
159 if self.logfile is None:
138 logfile = self.logfname
139 except:
140 print 'Logging has not been activated.'
160 print 'Logging has not been activated.'
141 else:
161 else:
142 state = self._dolog and 'active' or 'temporarily suspended'
162 state = self.log_active and 'active' or 'temporarily suspended'
143 print """
163 print 'Filename :',self.logfname
144 File:\t%s
164 print 'Mode :',self.logmode
145 Mode:\t%s
165 print 'Output logging:',self.log_output
146 State:\t%s """ % (logfile,self.LOGMODE,state)
166 print 'Timestamping :',self.timestamp
167 print 'State :',state
147
168
148
149 def log(self, line,continuation=None):
169 def log(self, line,continuation=None):
150 """Write the line to a log and create input cache variables _i*."""
170 """Write the line to a log and create input cache variables _i*."""
151
171
152 # update the auto _i tables
172 # update the auto _i tables
153 #print '***logging line',line # dbg
173 #print '***logging line',line # dbg
154 #print '***cache_count', self.outputcache.prompt_count # dbg
174 #print '***cache_count', self.shell.outputcache.prompt_count # dbg
155 input_hist = self.log_ns['_ih']
175 input_hist = self.shell.user_ns['_ih']
156 if not continuation and line:
176 if not continuation and line:
157 self._iii = self._ii
177 self._iii = self._ii
158 self._ii = self._i
178 self._ii = self._i
@@ -164,24 +184,38 State:\t%s """ % (logfile,self.LOGMODE,state)
164
184
165 # hackish access to top-level namespace to create _i1,_i2... dynamically
185 # hackish access to top-level namespace to create _i1,_i2... dynamically
166 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
186 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
167 if self.do_full_cache:
187 if self.shell.outputcache.do_full_cache:
168 in_num = self.outputcache.prompt_count
188 in_num = self.shell.outputcache.prompt_count
169 # add blank lines if the input cache fell out of sync. This can happen
189 # add blank lines if the input cache fell out of sync. This can
170 # for embedded instances which get killed via C-D and then get resumed.
190 # happen for embedded instances which get killed via C-D and then
191 # get resumed.
171 while in_num >= len(input_hist):
192 while in_num >= len(input_hist):
172 input_hist.append('\n')
193 input_hist.append('\n')
173 new_i = '_i%s' % in_num
194 new_i = '_i%s' % in_num
174 if continuation:
195 if continuation:
175 self._i00 = '%s%s\n' % (self.log_ns[new_i],line)
196 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line)
176 input_hist[in_num] = self._i00
197 input_hist[in_num] = self._i00
177 to_main[new_i] = self._i00
198 to_main[new_i] = self._i00
178 self.log_ns.update(to_main)
199 self.shell.user_ns.update(to_main)
179
200 self.log_write(line)
180 if self._dolog and line:
201
181 self.logfile.write(line+'\n')
202 def log_write(self,data,kind='input'):
203 """Write data to the log file, if active"""
204
205 if self.log_active and data:
206 write = self.logfile.write
207 if kind=='input':
208 if self.timestamp:
209 write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
210 time.localtime()))
211 write('%s\n' % data)
212 elif kind=='output' and self.log_output:
213 odata = '\n'.join(['#[Out]# %s' % s
214 for s in data.split('\n')])
215 write('%s\n' % odata)
182 self.logfile.flush()
216 self.logfile.flush()
183
217
184 def close_log(self):
218 def close_log(self):
185 if hasattr(self, 'logfile'):
219 self.logfile.close()
186 self.logfile.close()
220 self.logfile = None
187 self.logfname = ''
221 self.logfname = ''
@@ -1,7 +1,7
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Magic functions for InteractiveShell.
2 """Magic functions for InteractiveShell.
3
3
4 $Id: Magic.py 965 2005-12-28 23:23:09Z fperez $"""
4 $Id: Magic.py 966 2005-12-29 08:34:07Z fperez $"""
5
5
6 #*****************************************************************************
6 #*****************************************************************************
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
@@ -48,33 +48,8 from IPython.PyColorize import Parser
48 from IPython.Struct import Struct
48 from IPython.Struct import Struct
49 from IPython.genutils import *
49 from IPython.genutils import *
50
50
51 # Globals to be set later by Magic constructor
52 MAGIC_PREFIX = ''
53 MAGIC_ESCAPE = ''
54
55 #***************************************************************************
51 #***************************************************************************
56 # Utility functions
52 # Utility functions
57 def magic2python(cmd):
58 """Convert a command string of magic syntax to valid Python code."""
59
60 if cmd.startswith('#'+MAGIC_ESCAPE) or \
61 cmd.startswith(MAGIC_ESCAPE):
62 if cmd[0]=='#':
63 cmd = cmd[1:]
64 # we need to return the proper line end later
65 if cmd[-1] == '\n':
66 endl = '\n'
67 else:
68 endl = ''
69 try:
70 func,args = cmd[1:].split(' ',1)
71 except:
72 func,args = cmd[1:].rstrip(),''
73 args = args.replace('"','\\"').replace("'","\\'").rstrip()
74 return '%s%s ("%s")%s' % (MAGIC_PREFIX,func,args,endl)
75 else:
76 return cmd
77
78 def on_off(tag):
53 def on_off(tag):
79 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
54 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
80 return ['OFF','ON'][tag]
55 return ['OFF','ON'][tag]
@@ -82,22 +57,15 def on_off(tag):
82
57
83 #****************************************************************************
58 #****************************************************************************
84 # Utility classes
59 # Utility classes
85 class Macro:
60 class Macro(list):
86 """Simple class to store the value of macros as strings.
61 """Simple class to store the value of macros as strings.
87
62
88 This allows us to later exec them by checking when something is an
63 This allows us to later exec them by checking when something is an
89 instance of this class."""
64 instance of this class."""
90
91 def __init__(self,cmds):
92 """Build a macro from a list of commands."""
93
65
94 # Since the list may include multi-line entries, first make sure that
66 def __init__(self,data):
95 # they've been all broken up before passing it to magic2python
67 list.__init__(self,data)
96 cmdlist = map(magic2python,''.join(cmds).split('\n'))
68 self.value = ''.join(data)
97 self.value = '\n'.join(cmdlist)
98
99 def __str__(self):
100 return self.value
101
69
102 #***************************************************************************
70 #***************************************************************************
103 # Main class implementing Magic functionality
71 # Main class implementing Magic functionality
@@ -120,21 +88,18 class Magic:
120 # some utility functions
88 # some utility functions
121
89
122 def __init__(self,shell):
90 def __init__(self,shell):
123 # XXX This is hackish, clean up later to avoid these messy globals
124 global MAGIC_PREFIX, MAGIC_ESCAPE
125
91
126 self.options_table = {}
92 self.options_table = {}
127 MAGIC_PREFIX = shell.name+'.magic_'
128 MAGIC_ESCAPE = shell.ESC_MAGIC
129 if profile is None:
93 if profile is None:
130 self.magic_prun = self.profile_missing_notice
94 self.magic_prun = self.profile_missing_notice
95 self.shell = shell
131
96
132 def profile_missing_notice(self, *args, **kwargs):
97 def profile_missing_notice(self, *args, **kwargs):
133 error("""\
98 error("""\
134 The profile module could not be found. If you are a Debian user,
99 The profile module could not be found. If you are a Debian user,
135 it has been removed from the standard Debian package because of its non-free
100 it has been removed from the standard Debian package because of its non-free
136 license. To use profiling, please install"python2.3-profiler" from non-free.""")
101 license. To use profiling, please install"python2.3-profiler" from non-free.""")
137
102
138 def default_option(self,fn,optstr):
103 def default_option(self,fn,optstr):
139 """Make an entry in the options_table for fn, with value optstr"""
104 """Make an entry in the options_table for fn, with value optstr"""
140
105
@@ -168,10 +133,6 license. To use profiling, please install"python2.3-profiler" from non-free.""")
168 out.sort()
133 out.sort()
169 return out
134 return out
170
135
171 def set_shell(self,shell):
172 self.shell = shell
173 self.alias_table = shell.alias_table
174
175 def extract_input_slices(self,slices):
136 def extract_input_slices(self,slices):
176 """Return as a string a set of input history slices.
137 """Return as a string a set of input history slices.
177
138
@@ -496,17 +457,17 Currently the magic system has the following functions:\n"""
496
457
497 This feature is only available if numbered prompts are in use."""
458 This feature is only available if numbered prompts are in use."""
498
459
499 if not self.do_full_cache:
460 if not self.shell.outputcache.do_full_cache:
500 print 'This feature is only available if numbered prompts are in use.'
461 print 'This feature is only available if numbered prompts are in use.'
501 return
462 return
502 opts,args = self.parse_options(parameter_s,'n',mode='list')
463 opts,args = self.parse_options(parameter_s,'n',mode='list')
503
464
504 default_length = 40
465 default_length = 40
505 if len(args) == 0:
466 if len(args) == 0:
506 final = self.outputcache.prompt_count
467 final = self.shell.outputcache.prompt_count
507 init = max(1,final-default_length)
468 init = max(1,final-default_length)
508 elif len(args) == 1:
469 elif len(args) == 1:
509 final = self.outputcache.prompt_count
470 final = self.shell.outputcache.prompt_count
510 init = max(1,final-int(args[0]))
471 init = max(1,final-int(args[0]))
511 elif len(args) == 2:
472 elif len(args) == 2:
512 init,final = map(int,args)
473 init,final = map(int,args)
@@ -562,11 +523,8 Currently the magic system has the following functions:\n"""
562 if input != 'ipmagic("r")\n' and \
523 if input != 'ipmagic("r")\n' and \
563 (input.startswith(start) or input.startswith(start_magic)):
524 (input.startswith(start) or input.startswith(start_magic)):
564 #print 'match',`input` # dbg
525 #print 'match',`input` # dbg
565 if input.startswith(esc_magic):
566 input = magic2python(input)
567 #print 'modified',`input` # dbg
568 print 'Executing:',input,
526 print 'Executing:',input,
569 exec input in self.shell.user_ns
527 self.shell.runlines(input)
570 return
528 return
571 print 'No previous input matching `%s` found.' % start
529 print 'No previous input matching `%s` found.' % start
572
530
@@ -788,8 +746,8 Currently the magic system has the following functions:\n"""
788 typelist = parameter_s.split()
746 typelist = parameter_s.split()
789 for i in self.shell.user_ns.keys():
747 for i in self.shell.user_ns.keys():
790 if not (i.startswith('_') or i.startswith('_i')) \
748 if not (i.startswith('_') or i.startswith('_i')) \
791 and not (self.internal_ns.has_key(i) or
749 and not (self.shell.internal_ns.has_key(i) or
792 self.user_config_ns.has_key(i)):
750 self.shell.user_config_ns.has_key(i)):
793 if typelist:
751 if typelist:
794 if type(user_ns[i]).__name__ in typelist:
752 if type(user_ns[i]).__name__ in typelist:
795 out.append(i)
753 out.append(i)
@@ -946,9 +904,9 Currently the magic system has the following functions:\n"""
946 def magic_logstart(self,parameter_s=''):
904 def magic_logstart(self,parameter_s=''):
947 """Start logging anywhere in a session.
905 """Start logging anywhere in a session.
948
906
949 %logstart [log_name [log_mode]]
907 %logstart [-o|-t] [log_name [log_mode]]
950
908
951 If no name is given, it defaults to a file named 'ipython.log' in your
909 If no name is given, it defaults to a file named 'ipython_log.py' in your
952 current directory, in 'rotate' mode (see below).
910 current directory, in 'rotate' mode (see below).
953
911
954 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
912 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
@@ -956,67 +914,86 Currently the magic system has the following functions:\n"""
956
914
957 %logstart takes a second optional parameter: logging mode. This can be one
915 %logstart takes a second optional parameter: logging mode. This can be one
958 of (note that the modes are given unquoted):\\
916 of (note that the modes are given unquoted):\\
959 over: overwrite existing log.\\
960 backup: rename (if exists) to name~ and start name.\\
961 append: well, that says it.\\
917 append: well, that says it.\\
918 backup: rename (if exists) to name~ and start name.\\
919 global: single logfile in your home dir, appended to.\\
920 over : overwrite existing log.\\
962 rotate: create rotating logs name.1~, name.2~, etc.
921 rotate: create rotating logs name.1~, name.2~, etc.
963 """
964
922
965 #FIXME. This function should all be moved to the Logger class.
923 Options:
924
925 -o: log also IPython's output. In this mode, all commands which
926 generate an Out[NN] prompt are recorded to the logfile, right after
927 their corresponding input line. The output lines are always
928 prepended with a #[Out]# marker, so that the log remains valid
929 Python code.
930
931 -t: put timestamps before each input line logged (these are put in
932 comments)."""
966
933
967 valid_modes = qw('over backup append rotate')
934 opts,par = self.parse_options(parameter_s,'ot')
968 if self.LOG:
935 log_output = 'o' in opts
969 print 'Logging is already in place. Logfile:',self.LOG
936 timestamp = 't' in opts
970 return
971
937
972 par = parameter_s.strip()
938 rc = self.shell.rc
973 if not par:
939 logger = self.shell.logger
974 logname = self.LOGDEF
940
975 logmode = 'rotate' # use rotate for the auto-generated logs
941 # if no args are given, the defaults set in the logger constructor by
976 else:
942 # ipytohn remain valid
943 if par:
977 try:
944 try:
978 logname,logmode = par.split()
945 logfname,logmode = par.split()
979 except:
946 except:
980 try:
947 logfname = par
981 logname = par
948 logmode = 'backup'
982 logmode = 'backup'
949 else:
983 except:
950 logfname = logger.logfname
984 warn('Usage: %log [log_name [log_mode]]')
951 logmode = logger.logmode
985 return
952 # put logfname into rc struct as if it had been called on the command
986 if not logmode in valid_modes:
953 # line, so it ends up saved in the log header Save it in case we need
987 warn('Logging NOT activated.\n'
954 # to restore it...
988 'Usage: %log [log_name [log_mode]]\n'
955 old_logfile = rc.opts.get('logfile','')
989 'Valid modes: '+str(valid_modes))
956 if logfname:
990 return
957 logfname = os.path.expanduser(logfname)
991
958 rc.opts.logfile = logfname
992 # If we made it this far, I think we're ok:
959 loghead = self.shell.loghead_tpl % (rc.opts,rc.args)
993 print 'Activating auto-logging.'
994 print 'Current session state plus future input saved to:',logname
995 print 'Logging mode: ',logmode
996 # put logname into rc struct as if it had been called on the command line,
997 # so it ends up saved in the log header
998 # Save it in case we need to restore it...
999 old_logfile = self.shell.rc.opts.get('logfile','')
1000 logname = os.path.expanduser(logname)
1001 self.shell.rc.opts.logfile = logname
1002 self.LOGMODE = logmode # FIXME: this should be set through a function.
1003 try:
960 try:
1004 header = str(self.LOGHEAD)
961 started = logger.logstart(logfname,loghead,logmode,
1005 self.create_log(header,logname)
962 log_output,timestamp)
1006 self.logstart(header,logname)
1007 except:
963 except:
1008 self.LOG = '' # we are NOT logging, something went wrong
964 rc.opts.logfile = old_logfile
1009 self.shell.rc.opts.logfile = old_logfile
965 warn("Couldn't start log: %s" % sys.exc_info()[1])
1010 warn("Couldn't start log: "+str(sys.exc_info()[1]))
966 else:
1011 else: # log input history up to this point
967 # log input history up to this point, optionally interleaving
1012 self.logfile.write(self.shell.user_ns['_ih'][1:])
968 # output if requested
1013 self.logfile.flush()
969
1014
970 if timestamp:
971 # disable timestamping for the previous history, since we've
972 # lost those already (no time machine here).
973 logger.timestamp = False
974 if log_output:
975 log_write = logger.log_write
976 input_hist = self.shell.input_hist
977 output_hist = self.shell.output_hist
978 for n in range(1,len(input_hist)-1):
979 log_write(input_hist[n].rstrip())
980 if n in output_hist:
981 log_write(repr(output_hist[n]),'output')
982 else:
983 logger.log_write(self.shell.input_hist[1:])
984 if timestamp:
985 # re-enable timestamping
986 logger.timestamp = True
987
988 print ('Activating auto-logging. '
989 'Current session state plus future input saved.')
990 logger.logstate()
991
1015 def magic_logoff(self,parameter_s=''):
992 def magic_logoff(self,parameter_s=''):
1016 """Temporarily stop logging.
993 """Temporarily stop logging.
1017
994
1018 You must have previously started logging."""
995 You must have previously started logging."""
1019 self.switch_log(0)
996 self.shell.logger.switch_log(0)
1020
997
1021 def magic_logon(self,parameter_s=''):
998 def magic_logon(self,parameter_s=''):
1022 """Restart logging.
999 """Restart logging.
@@ -1026,12 +1003,12 Currently the magic system has the following functions:\n"""
1026 must use the %logstart function, which allows you to specify an
1003 must use the %logstart function, which allows you to specify an
1027 optional log filename."""
1004 optional log filename."""
1028
1005
1029 self.switch_log(1)
1006 self.shell.logger.switch_log(1)
1030
1007
1031 def magic_logstate(self,parameter_s=''):
1008 def magic_logstate(self,parameter_s=''):
1032 """Print the status of the logging system."""
1009 """Print the status of the logging system."""
1033
1010
1034 self.logstate()
1011 self.shell.logger.logstate()
1035
1012
1036 def magic_pdb(self, parameter_s=''):
1013 def magic_pdb(self, parameter_s=''):
1037 """Control the calling of the pdb interactive debugger.
1014 """Control the calling of the pdb interactive debugger.
@@ -1047,24 +1024,18 Currently the magic system has the following functions:\n"""
1047
1024
1048 if par:
1025 if par:
1049 try:
1026 try:
1050 pdb = {'off':0,'0':0,'on':1,'1':1}[par]
1027 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
1051 except KeyError:
1028 except KeyError:
1052 print 'Incorrect argument. Use on/1, off/0, or nothing for a toggle.'
1029 print ('Incorrect argument. Use on/1, off/0, '
1030 'or nothing for a toggle.')
1053 return
1031 return
1054 else:
1055 self.shell.InteractiveTB.call_pdb = pdb
1056 else:
1032 else:
1033 # toggle
1057 new_pdb = not self.shell.InteractiveTB.call_pdb
1034 new_pdb = not self.shell.InteractiveTB.call_pdb
1058 self.shell.InteractiveTB.call_pdb = new_pdb
1059 if self.shell.isthreaded:
1060 try:
1061 self.sys_excepthook.call_pdb = new_pdb
1062 except:
1063 warn('Failed to activate pdb for threaded exception handler')
1064
1065 print 'Automatic pdb calling has been turned',on_off(new_pdb)
1066
1067
1035
1036 # set on the shell
1037 self.shell.call_pdb = new_pdb
1038 print 'Automatic pdb calling has been turned',on_off(new_pdb)
1068
1039
1069 def magic_prun(self, parameter_s ='',user_mode=1,
1040 def magic_prun(self, parameter_s ='',user_mode=1,
1070 opts=None,arg_lst=None,prog_ns=None):
1041 opts=None,arg_lst=None,prog_ns=None):
@@ -1606,12 +1577,12 Currently the magic system has the following functions:\n"""
1606 args = parameter_s.split()
1577 args = parameter_s.split()
1607 name,ranges = args[0], args[1:]
1578 name,ranges = args[0], args[1:]
1608 #print 'rng',ranges # dbg
1579 #print 'rng',ranges # dbg
1609 cmds = self.extract_input_slices(ranges)
1580 lines = self.extract_input_slices(ranges)
1610 macro = Macro(cmds)
1581 macro = Macro(lines)
1611 self.shell.user_ns.update({name:macro})
1582 self.shell.user_ns.update({name:macro})
1612 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
1583 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
1613 print 'Macro contents:'
1584 print 'Macro contents:'
1614 print str(macro).rstrip(),
1585 print macro
1615
1586
1616 def magic_save(self,parameter_s = ''):
1587 def magic_save(self,parameter_s = ''):
1617 """Save a set of lines to a given filename.
1588 """Save a set of lines to a given filename.
@@ -1906,17 +1877,18 Currently the magic system has the following functions:\n"""
1906 warn('Error changing %s exception modes.\n%s' %
1877 warn('Error changing %s exception modes.\n%s' %
1907 (name,sys.exc_info()[1]))
1878 (name,sys.exc_info()[1]))
1908
1879
1880 shell = self.shell
1909 new_mode = parameter_s.strip().capitalize()
1881 new_mode = parameter_s.strip().capitalize()
1910 try:
1882 try:
1911 self.InteractiveTB.set_mode(mode=new_mode)
1883 shell.InteractiveTB.set_mode(mode=new_mode)
1912 print 'Exception reporting mode:',self.InteractiveTB.mode
1884 print 'Exception reporting mode:',shell.InteractiveTB.mode
1913 except:
1885 except:
1914 xmode_switch_err('user')
1886 xmode_switch_err('user')
1915
1887
1916 # threaded shells use a special handler in sys.excepthook
1888 # threaded shells use a special handler in sys.excepthook
1917 if self.isthreaded:
1889 if shell.isthreaded:
1918 try:
1890 try:
1919 self.shell.sys_excepthook.set_mode(mode=new_mode)
1891 shell.sys_excepthook.set_mode(mode=new_mode)
1920 except:
1892 except:
1921 xmode_switch_err('threaded')
1893 xmode_switch_err('threaded')
1922
1894
@@ -1961,37 +1933,39 http://starship.python.net/crew/theller/ctypes
1961 Defaulting color scheme to 'NoColor'"""
1933 Defaulting color scheme to 'NoColor'"""
1962 new_scheme = 'NoColor'
1934 new_scheme = 'NoColor'
1963 warn(msg)
1935 warn(msg)
1936 # local shortcut
1937 shell = self.shell
1964
1938
1965 # Set prompt colors
1939 # Set prompt colors
1966 try:
1940 try:
1967 self.shell.outputcache.set_colors(new_scheme)
1941 shell.outputcache.set_colors(new_scheme)
1968 except:
1942 except:
1969 color_switch_err('prompt')
1943 color_switch_err('prompt')
1970 else:
1944 else:
1971 self.shell.rc.colors = \
1945 shell.rc.colors = \
1972 self.shell.outputcache.color_table.active_scheme_name
1946 shell.outputcache.color_table.active_scheme_name
1973 # Set exception colors
1947 # Set exception colors
1974 try:
1948 try:
1975 self.shell.InteractiveTB.set_colors(scheme = new_scheme)
1949 shell.InteractiveTB.set_colors(scheme = new_scheme)
1976 self.shell.SyntaxTB.set_colors(scheme = new_scheme)
1950 shell.SyntaxTB.set_colors(scheme = new_scheme)
1977 except:
1951 except:
1978 color_switch_err('exception')
1952 color_switch_err('exception')
1979
1953
1980 # threaded shells use a verbose traceback in sys.excepthook
1954 # threaded shells use a verbose traceback in sys.excepthook
1981 if self.isthreaded:
1955 if shell.isthreaded:
1982 try:
1956 try:
1983 self.shell.sys_excepthook.set_colors(scheme=new_scheme)
1957 shell.sys_excepthook.set_colors(scheme=new_scheme)
1984 except:
1958 except:
1985 color_switch_err('system exception handler')
1959 color_switch_err('system exception handler')
1986
1960
1987 # Set info (for 'object?') colors
1961 # Set info (for 'object?') colors
1988 if self.shell.rc.color_info:
1962 if shell.rc.color_info:
1989 try:
1963 try:
1990 self.shell.inspector.set_active_scheme(new_scheme)
1964 shell.inspector.set_active_scheme(new_scheme)
1991 except:
1965 except:
1992 color_switch_err('object inspector')
1966 color_switch_err('object inspector')
1993 else:
1967 else:
1994 self.shell.inspector.set_active_scheme('NoColor')
1968 shell.inspector.set_active_scheme('NoColor')
1995
1969
1996 def magic_color_info(self,parameter_s = ''):
1970 def magic_color_info(self,parameter_s = ''):
1997 """Toggle color_info.
1971 """Toggle color_info.
@@ -2284,7 +2258,7 Defaulting color scheme to 'NoColor'"""
2284 else:
2258 else:
2285 self.shell.user_ns['_dh'].append(os.getcwd())
2259 self.shell.user_ns['_dh'].append(os.getcwd())
2286 else:
2260 else:
2287 os.chdir(self.home_dir)
2261 os.chdir(self.shell.home_dir)
2288 self.shell.user_ns['_dh'].append(os.getcwd())
2262 self.shell.user_ns['_dh'].append(os.getcwd())
2289 if not 'q' in opts:
2263 if not 'q' in opts:
2290 print self.shell.user_ns['_dh'][-1]
2264 print self.shell.user_ns['_dh'][-1]
@@ -2323,7 +2297,6 Defaulting color scheme to 'NoColor'"""
2323 def magic_env(self, parameter_s=''):
2297 def magic_env(self, parameter_s=''):
2324 """List environment variables."""
2298 """List environment variables."""
2325
2299
2326 # environ is an instance of UserDict
2327 return os.environ.data
2300 return os.environ.data
2328
2301
2329 def magic_pushd(self, parameter_s=''):
2302 def magic_pushd(self, parameter_s=''):
@@ -2335,11 +2308,12 Defaulting color scheme to 'NoColor'"""
2335 %pushd with no arguments does a %pushd to your home directory.
2308 %pushd with no arguments does a %pushd to your home directory.
2336 """
2309 """
2337 if parameter_s == '': parameter_s = '~'
2310 if parameter_s == '': parameter_s = '~'
2338 if len(self.dir_stack)>0 and os.path.expanduser(parameter_s) != \
2311 dir_s = self.shell.dir_stack
2339 os.path.expanduser(self.dir_stack[0]):
2312 if len(dir_s)>0 and os.path.expanduser(parameter_s) != \
2313 os.path.expanduser(self.shell.dir_stack[0]):
2340 try:
2314 try:
2341 self.magic_cd(parameter_s)
2315 self.magic_cd(parameter_s)
2342 self.dir_stack.insert(0,os.getcwd().replace(self.home_dir,'~'))
2316 dir_s.insert(0,os.getcwd().replace(self.home_dir,'~'))
2343 self.magic_dirs()
2317 self.magic_dirs()
2344 except:
2318 except:
2345 print 'Invalid directory'
2319 print 'Invalid directory'
@@ -2349,18 +2323,18 Defaulting color scheme to 'NoColor'"""
2349 def magic_popd(self, parameter_s=''):
2323 def magic_popd(self, parameter_s=''):
2350 """Change to directory popped off the top of the stack.
2324 """Change to directory popped off the top of the stack.
2351 """
2325 """
2352 if len (self.dir_stack) > 1:
2326 if len (self.shell.dir_stack) > 1:
2353 self.dir_stack.pop(0)
2327 self.shell.dir_stack.pop(0)
2354 self.magic_cd(self.dir_stack[0])
2328 self.magic_cd(self.shell.dir_stack[0])
2355 print self.dir_stack[0]
2329 print self.shell.dir_stack[0]
2356 else:
2330 else:
2357 print "You can't remove the starting directory from the stack:",\
2331 print "You can't remove the starting directory from the stack:",\
2358 self.dir_stack
2332 self.shell.dir_stack
2359
2333
2360