##// END OF EJS Templates
Major cleanups and changes, see changelog/changeset for full details.
fperez -
Show More
@@ -2,12 +2,12 b''
2 2 """
3 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 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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
@@ -24,61 +24,96 b' __license__ = Release.license'
24 24 # Python standard modules
25 25 import glob
26 26 import os
27 import sys
28
29 # Homebrewed
30 from IPython.genutils import *
27 import time
31 28
32 29 #****************************************************************************
33 # FIXME: The logger class shouldn't be a mixin, it throws too many things into
34 # the InteractiveShell namespace. Rather make it a standalone tool, and create
35 # a Logger instance in InteractiveShell that uses it. Doing this will require
36 # tracking down a *lot* of nasty uses of the Logger attributes in
37 # InteractiveShell, but will clean up things quite a bit.
38
39 class Logger:
40 """A Logfile Mixin class with different policies for file creation"""
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):
30 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
31 # ipython and does input cache management. Finish cleanup later...
32
33 class Logger(object):
34 """A Logfile class with different policies for file creation"""
35
36 def __init__(self,shell,logfname='Logger.log',loghead='',logmode='over'):
37
45 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
57 if self.LOG:
58 self.logfname = self.LOG
59 else:
60 self.logfname = defname
61 39
62 if self.LOGMODE == 'over':
63 if os.path.isfile(self.logfname):
64 os.remove(self.logfname)
65 self.logfile = open(self.logfname,'w')
66 if self.LOGMODE == 'backup':
67 if os.path.isfile(self.logfname):
40 # this is the full ipython instance, we need some attributes from it
41 # which won't exist until later. What a mess, clean up later...
42 self.shell = shell
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)
78
79 self.log_active = True
80
81 # The three parameters can override constructor defaults
82 if logfname: self.logfname = logfname
83 if loghead: self.loghead = loghead
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 97 backup_logname = self.logfname+'~'
69 98 # Manually remove any old backup, since os.rename may fail
70 99 # under Windows.
71 if os.path.isfile(backup_logname):
100 if isfile(backup_logname):
72 101 os.remove(backup_logname)
73 102 os.rename(self.logfname,backup_logname)
74 103 self.logfile = open(self.logfname,'w')
75 elif self.LOGMODE == 'global':
76 self.logfname = os.path.join(self.home_dir, self.defname)
104
105 elif logmode == 'global':
106 self.logfname = os.path.join(self.shell.home_dir,self.logfname)
77 107 self.logfile = open(self.logfname, 'a')
78 self.LOG = self.logfname
79 elif self.LOGMODE == 'rotate':
80 if os.path.isfile(self.logfname):
81 if os.path.isfile(self.logfname+'.001~'):
108
109 elif logmode == 'over':
110 if isfile(self.logfname):
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 117 old = glob.glob(self.logfname+'.*~')
83 118 old.sort()
84 119 old.reverse()
@@ -88,71 +123,56 b' class Logger:'
88 123 os.rename(f, root+'.'+`num`.zfill(3)+'~')
89 124 os.rename(self.logfname, self.logfname+'.001~')
90 125 self.logfile = open(self.logfname,'w')
91 elif self.LOGMODE == 'append':
92 self.logfile = open(self.logfname,'a')
93
94 if self.LOGMODE != 'append':
95 self.logfile.write(header)
96 self.logfile.flush()
97 126
98 def logstart(self, header='',parameter_s = ''):
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)
127 if logmode != 'append':
128 self.logfile.write(self.loghead)
106 129
107 self._dolog = 1
130 self.logfile.flush()
108 131
109 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 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:
119 _ = self.logfile
120 except AttributeError:
141 if self.logfile is None:
121 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 145 %logon/%logoff are for temporarily starting and stopping logging for a logfile
125 146 which already exists. But you must first start the logging process with
126 147 %logstart (optionally giving a logfile name)."""
127 148
128 149 else:
129 if self._dolog == val:
150 if self.log_active == val:
130 151 print 'Logging is already',label[val]
131 152 else:
132 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 157 def logstate(self):
136 158 """Print a status message about the logger."""
137 try:
138 logfile = self.logfname
139 except:
159 if self.logfile is None:
140 160 print 'Logging has not been activated.'
141 161 else:
142 state = self._dolog and 'active' or 'temporarily suspended'
143 print """
144 File:\t%s
145 Mode:\t%s
146 State:\t%s """ % (logfile,self.LOGMODE,state)
147
162 state = self.log_active and 'active' or 'temporarily suspended'
163 print 'Filename :',self.logfname
164 print 'Mode :',self.logmode
165 print 'Output logging:',self.log_output
166 print 'Timestamping :',self.timestamp
167 print 'State :',state
148 168
149 169 def log(self, line,continuation=None):
150 170 """Write the line to a log and create input cache variables _i*."""
151 171
152 172 # update the auto _i tables
153 173 #print '***logging line',line # dbg
154 #print '***cache_count', self.outputcache.prompt_count # dbg
155 input_hist = self.log_ns['_ih']
174 #print '***cache_count', self.shell.outputcache.prompt_count # dbg
175 input_hist = self.shell.user_ns['_ih']
156 176 if not continuation and line:
157 177 self._iii = self._ii
158 178 self._ii = self._i
@@ -164,24 +184,38 b' State:\\t%s """ % (logfile,self.LOGMODE,state)'
164 184
165 185 # hackish access to top-level namespace to create _i1,_i2... dynamically
166 186 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
167 if self.do_full_cache:
168 in_num = self.outputcache.prompt_count
169 # add blank lines if the input cache fell out of sync. This can happen
170 # for embedded instances which get killed via C-D and then get resumed.
187 if self.shell.outputcache.do_full_cache:
188 in_num = self.shell.outputcache.prompt_count
189 # add blank lines if the input cache fell out of sync. This can
190 # happen for embedded instances which get killed via C-D and then
191 # get resumed.
171 192 while in_num >= len(input_hist):
172 193 input_hist.append('\n')
173 194 new_i = '_i%s' % in_num
174 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 197 input_hist[in_num] = self._i00
177 198 to_main[new_i] = self._i00
178 self.log_ns.update(to_main)
179
180 if self._dolog and line:
181 self.logfile.write(line+'\n')
199 self.shell.user_ns.update(to_main)
200 self.log_write(line)
201
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 216 self.logfile.flush()
183 217
184 218 def close_log(self):
185 if hasattr(self, 'logfile'):
186 219 self.logfile.close()
220 self.logfile = None
187 221 self.logfname = ''
@@ -1,7 +1,7 b''
1 1 # -*- coding: utf-8 -*-
2 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 7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
@@ -48,33 +48,8 b' from IPython.PyColorize import Parser'
48 48 from IPython.Struct import Struct
49 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 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 53 def on_off(tag):
79 54 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
80 55 return ['OFF','ON'][tag]
@@ -82,22 +57,15 b' def on_off(tag):'
82 57
83 58 #****************************************************************************
84 59 # Utility classes
85 class Macro:
60 class Macro(list):
86 61 """Simple class to store the value of macros as strings.
87 62
88 63 This allows us to later exec them by checking when something is an
89 64 instance of this class."""
90 65
91 def __init__(self,cmds):
92 """Build a macro from a list of commands."""
93
94 # Since the list may include multi-line entries, first make sure that
95 # they've been all broken up before passing it to magic2python
96 cmdlist = map(magic2python,''.join(cmds).split('\n'))
97 self.value = '\n'.join(cmdlist)
98
99 def __str__(self):
100 return self.value
66 def __init__(self,data):
67 list.__init__(self,data)
68 self.value = ''.join(data)
101 69
102 70 #***************************************************************************
103 71 # Main class implementing Magic functionality
@@ -120,14 +88,11 b' class Magic:'
120 88 # some utility functions
121 89
122 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 92 self.options_table = {}
127 MAGIC_PREFIX = shell.name+'.magic_'
128 MAGIC_ESCAPE = shell.ESC_MAGIC
129 93 if profile is None:
130 94 self.magic_prun = self.profile_missing_notice
95 self.shell = shell
131 96
132 97 def profile_missing_notice(self, *args, **kwargs):
133 98 error("""\
@@ -168,10 +133,6 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
168 133 out.sort()
169 134 return out
170 135
171 def set_shell(self,shell):
172 self.shell = shell
173 self.alias_table = shell.alias_table
174
175 136 def extract_input_slices(self,slices):
176 137 """Return as a string a set of input history slices.
177 138
@@ -496,17 +457,17 b' Currently the magic system has the following functions:\\n"""'
496 457
497 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 461 print 'This feature is only available if numbered prompts are in use.'
501 462 return
502 463 opts,args = self.parse_options(parameter_s,'n',mode='list')
503 464
504 465 default_length = 40
505 466 if len(args) == 0:
506 final = self.outputcache.prompt_count
467 final = self.shell.outputcache.prompt_count
507 468 init = max(1,final-default_length)
508 469 elif len(args) == 1:
509 final = self.outputcache.prompt_count
470 final = self.shell.outputcache.prompt_count
510 471 init = max(1,final-int(args[0]))
511 472 elif len(args) == 2:
512 473 init,final = map(int,args)
@@ -562,11 +523,8 b' Currently the magic system has the following functions:\\n"""'
562 523 if input != 'ipmagic("r")\n' and \
563 524 (input.startswith(start) or input.startswith(start_magic)):
564 525 #print 'match',`input` # dbg
565 if input.startswith(esc_magic):
566 input = magic2python(input)
567 #print 'modified',`input` # dbg
568 526 print 'Executing:',input,
569 exec input in self.shell.user_ns
527 self.shell.runlines(input)
570 528 return
571 529 print 'No previous input matching `%s` found.' % start
572 530
@@ -788,8 +746,8 b' Currently the magic system has the following functions:\\n"""'
788 746 typelist = parameter_s.split()
789 747 for i in self.shell.user_ns.keys():
790 748 if not (i.startswith('_') or i.startswith('_i')) \
791 and not (self.internal_ns.has_key(i) or
792 self.user_config_ns.has_key(i)):
749 and not (self.shell.internal_ns.has_key(i) or
750 self.shell.user_config_ns.has_key(i)):
793 751 if typelist:
794 752 if type(user_ns[i]).__name__ in typelist:
795 753 out.append(i)
@@ -946,9 +904,9 b' Currently the magic system has the following functions:\\n"""'
946 904 def magic_logstart(self,parameter_s=''):
947 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 910 current directory, in 'rotate' mode (see below).
953 911
954 912 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
@@ -956,67 +914,86 b' Currently the magic system has the following functions:\\n"""'
956 914
957 915 %logstart takes a second optional parameter: logging mode. This can be one
958 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 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 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:
966 924
967 valid_modes = qw('over backup append rotate')
968 if self.LOG:
969 print 'Logging is already in place. Logfile:',self.LOG
970 return
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.
971 930
972 par = parameter_s.strip()
973 if not par:
974 logname = self.LOGDEF
975 logmode = 'rotate' # use rotate for the auto-generated logs
976 else:
931 -t: put timestamps before each input line logged (these are put in
932 comments)."""
933
934 opts,par = self.parse_options(parameter_s,'ot')
935 log_output = 'o' in opts
936 timestamp = 't' in opts
937
938 rc = self.shell.rc
939 logger = self.shell.logger
940
941 # if no args are given, the defaults set in the logger constructor by
942 # ipytohn remain valid
943 if par:
977 944 try:
978 logname,logmode = par.split()
945 logfname,logmode = par.split()
979 946 except:
980 try:
981 logname = par
947 logfname = par
982 948 logmode = 'backup'
983 except:
984 warn('Usage: %log [log_name [log_mode]]')
985 return
986 if not logmode in valid_modes:
987 warn('Logging NOT activated.\n'
988 'Usage: %log [log_name [log_mode]]\n'
989 'Valid modes: '+str(valid_modes))
990 return
991
992 # If we made it this far, I think we're ok:
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.
949 else:
950 logfname = logger.logfname
951 logmode = logger.logmode
952 # put logfname into rc struct as if it had been called on the command
953 # line, so it ends up saved in the log header Save it in case we need
954 # to restore it...
955 old_logfile = rc.opts.get('logfile','')
956 if logfname:
957 logfname = os.path.expanduser(logfname)
958 rc.opts.logfile = logfname
959 loghead = self.shell.loghead_tpl % (rc.opts,rc.args)
1003 960 try:
1004 header = str(self.LOGHEAD)
1005 self.create_log(header,logname)
1006 self.logstart(header,logname)
961 started = logger.logstart(logfname,loghead,logmode,
962 log_output,timestamp)
1007 963 except:
1008 self.LOG = '' # we are NOT logging, something went wrong
1009 self.shell.rc.opts.logfile = old_logfile
1010 warn("Couldn't start log: "+str(sys.exc_info()[1]))
1011 else: # log input history up to this point
1012 self.logfile.write(self.shell.user_ns['_ih'][1:])
1013 self.logfile.flush()
964 rc.opts.logfile = old_logfile
965 warn("Couldn't start log: %s" % sys.exc_info()[1])
966 else:
967 # log input history up to this point, optionally interleaving
968 # output if requested
969
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()
1014 991
1015 992 def magic_logoff(self,parameter_s=''):
1016 993 """Temporarily stop logging.
1017 994
1018 995 You must have previously started logging."""
1019 self.switch_log(0)
996 self.shell.logger.switch_log(0)
1020 997
1021 998 def magic_logon(self,parameter_s=''):
1022 999 """Restart logging.
@@ -1026,12 +1003,12 b' Currently the magic system has the following functions:\\n"""'
1026 1003 must use the %logstart function, which allows you to specify an
1027 1004 optional log filename."""
1028 1005
1029 self.switch_log(1)
1006 self.shell.logger.switch_log(1)
1030 1007
1031 1008 def magic_logstate(self,parameter_s=''):
1032 1009 """Print the status of the logging system."""
1033 1010
1034 self.logstate()
1011 self.shell.logger.logstate()
1035 1012
1036 1013 def magic_pdb(self, parameter_s=''):
1037 1014 """Control the calling of the pdb interactive debugger.
@@ -1047,25 +1024,19 b' Currently the magic system has the following functions:\\n"""'
1047 1024
1048 1025 if par:
1049 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 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 1031 return
1054 1032 else:
1055 self.shell.InteractiveTB.call_pdb = pdb
1056 else:
1033 # toggle
1057 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 1035
1036 # set on the shell
1037 self.shell.call_pdb = new_pdb
1065 1038 print 'Automatic pdb calling has been turned',on_off(new_pdb)
1066 1039
1067
1068
1069 1040 def magic_prun(self, parameter_s ='',user_mode=1,
1070 1041 opts=None,arg_lst=None,prog_ns=None):
1071 1042
@@ -1606,12 +1577,12 b' Currently the magic system has the following functions:\\n"""'
1606 1577 args = parameter_s.split()
1607 1578 name,ranges = args[0], args[1:]
1608 1579 #print 'rng',ranges # dbg
1609 cmds = self.extract_input_slices(ranges)
1610 macro = Macro(cmds)
1580 lines = self.extract_input_slices(ranges)
1581 macro = Macro(lines)
1611 1582 self.shell.user_ns.update({name:macro})
1612 1583 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
1613 1584 print 'Macro contents:'
1614 print str(macro).rstrip(),
1585 print macro
1615 1586
1616 1587 def magic_save(self,parameter_s = ''):
1617 1588 """Save a set of lines to a given filename.
@@ -1906,17 +1877,18 b' Currently the magic system has the following functions:\\n"""'
1906 1877 warn('Error changing %s exception modes.\n%s' %
1907 1878 (name,sys.exc_info()[1]))
1908 1879
1880 shell = self.shell
1909 1881 new_mode = parameter_s.strip().capitalize()
1910 1882 try:
1911 self.InteractiveTB.set_mode(mode=new_mode)
1912 print 'Exception reporting mode:',self.InteractiveTB.mode
1883 shell.InteractiveTB.set_mode(mode=new_mode)
1884 print 'Exception reporting mode:',shell.InteractiveTB.mode
1913 1885 except:
1914 1886 xmode_switch_err('user')
1915 1887
1916 1888 # threaded shells use a special handler in sys.excepthook
1917 if self.isthreaded:
1889 if shell.isthreaded:
1918 1890 try:
1919 self.shell.sys_excepthook.set_mode(mode=new_mode)
1891 shell.sys_excepthook.set_mode(mode=new_mode)
1920 1892 except:
1921 1893 xmode_switch_err('threaded')
1922 1894
@@ -1961,37 +1933,39 b' http://starship.python.net/crew/theller/ctypes'
1961 1933 Defaulting color scheme to 'NoColor'"""
1962 1934 new_scheme = 'NoColor'
1963 1935 warn(msg)
1936 # local shortcut
1937 shell = self.shell
1964 1938
1965 1939 # Set prompt colors
1966 1940 try:
1967 self.shell.outputcache.set_colors(new_scheme)
1941 shell.outputcache.set_colors(new_scheme)
1968 1942 except:
1969 1943 color_switch_err('prompt')
1970 1944 else:
1971 self.shell.rc.colors = \
1972 self.shell.outputcache.color_table.active_scheme_name
1945 shell.rc.colors = \
1946 shell.outputcache.color_table.active_scheme_name
1973 1947 # Set exception colors
1974 1948 try:
1975 self.shell.InteractiveTB.set_colors(scheme = new_scheme)
1976 self.shell.SyntaxTB.set_colors(scheme = new_scheme)
1949 shell.InteractiveTB.set_colors(scheme = new_scheme)
1950 shell.SyntaxTB.set_colors(scheme = new_scheme)
1977 1951 except:
1978 1952 color_switch_err('exception')
1979 1953
1980 1954 # threaded shells use a verbose traceback in sys.excepthook
1981 if self.isthreaded:
1955 if shell.isthreaded:
1982 1956 try:
1983 self.shell.sys_excepthook.set_colors(scheme=new_scheme)
1957 shell.sys_excepthook.set_colors(scheme=new_scheme)
1984 1958 except:
1985 1959 color_switch_err('system exception handler')
1986 1960
1987 1961 # Set info (for 'object?') colors
1988 if self.shell.rc.color_info:
1962 if shell.rc.color_info:
1989 1963 try:
1990 self.shell.inspector.set_active_scheme(new_scheme)
1964 shell.inspector.set_active_scheme(new_scheme)
1991 1965 except:
1992 1966 color_switch_err('object inspector')
1993 1967 else:
1994 self.shell.inspector.set_active_scheme('NoColor')
1968 shell.inspector.set_active_scheme('NoColor')
1995 1969
1996 1970 def magic_color_info(self,parameter_s = ''):
1997 1971 """Toggle color_info.
@@ -2284,7 +2258,7 b' Defaulting color scheme to \'NoColor\'"""'
2284 2258 else:
2285 2259 self.shell.user_ns['_dh'].append(os.getcwd())
2286 2260 else:
2287 os.chdir(self.home_dir)
2261 os.chdir(self.shell.home_dir)
2288 2262 self.shell.user_ns['_dh'].append(os.getcwd())
2289 2263 if not 'q' in opts:
2290 2264 print self.shell.user_ns['_dh'][-1]
@@ -2323,7 +2297,6 b' Defaulting color scheme to \'NoColor\'"""'
2323 2297 def magic_env(self, parameter_s=''):
2324 2298 """List environment variables."""
2325 2299
2326 # environ is an instance of UserDict
2327 2300 return os.environ.data
2328 2301
2329 2302 def magic_pushd(self, parameter_s=''):
@@ -2335,11 +2308,12 b' Defaulting color scheme to \'NoColor\'"""'
2335 2308 %pushd with no arguments does a %pushd to your home directory.
2336 2309 """
2337 2310 if parameter_s == '': parameter_s = '~'
2338 if len(self.dir_stack)>0 and os.path.expanduser(parameter_s) != \
2339 os.path.expanduser(self.dir_stack[0]):
2311 dir_s = self.shell.dir_stack
2312 if len(dir_s)>0 and os.path.expanduser(parameter_s) != \
2313 os.path.expanduser(self.shell.dir_stack[0]):
2340 2314 try:
2341 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 2317 self.magic_dirs()
2344 2318 except:
2345 2319 print 'Invalid directory'
@@ -2349,18 +2323,18 b' Defaulting color scheme to \'NoColor\'"""'
2349 2323 def magic_popd(self, parameter_s=''):
2350 2324 """Change to directory popped off the top of the stack.
2351 2325 """
2352 if len (self.dir_stack) > 1:
2353 self.dir_stack.pop(0)
2354 self.magic_cd(self.dir_stack[0])
2355 print self.dir_stack[0]
2326 if len (self.shell.dir_stack) > 1:
2327 self.shell.dir_stack.pop(0)
2328 self.magic_cd(self.shell.dir_stack[0])
2329 print self.shell.dir_stack[0]
2356 2330 else:
2357 2331 print "You can't remove the starting directory from the stack:",\
2358 self.dir_stack
2332 self.shell.dir_stack
2359 2333
2360 2334 def magic_dirs(self, parameter_s=''):
2361 2335 """Return the current directory stack."""
2362 2336
2363 return self.dir_stack[:]
2337 return self.shell.dir_stack[:]
2364 2338
2365 2339 def magic_sc(self, parameter_s=''):
2366 2340 """Shell capture - execute a shell command and capture its output.
@@ -2605,7 +2579,7 b' Defaulting color scheme to \'NoColor\'"""'
2605 2579 bkms[args[0]] = os.getcwd()
2606 2580 elif len(args)==2:
2607 2581 bkms[args[0]] = args[1]
2608 self.persist['bookmarks'] = bkms
2582 self.shell.persist['bookmarks'] = bkms
2609 2583
2610 2584 def magic_pycat(self, parameter_s=''):
2611 2585 """Show a syntax-highlighted file through a pager.
@@ -2,7 +2,7 b''
2 2 """
3 3 Classes for handling input/output prompts.
4 4
5 $Id: Prompts.py 960 2005-12-28 06:51:01Z fperez $"""
5 $Id: Prompts.py 966 2005-12-29 08:34:07Z fperez $"""
6 6
7 7 #*****************************************************************************
8 8 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
@@ -392,10 +392,10 b' class CachedOutput:'
392 392 Initialize with initial and final values for cache counter (this defines
393 393 the maximum size of the cache."""
394 394
395 def __init__(self,cache_size,Pprint,colors='NoColor',input_sep='\n',
396 output_sep='\n',output_sep2='',user_ns={},
397 ps1 = None, ps2 = None,ps_out = None,
398 input_hist = None,pad_left=True):
395 def __init__(self,shell,cache_size,Pprint,
396 colors='NoColor',input_sep='\n',
397 output_sep='\n',output_sep2='',
398 ps1 = None, ps2 = None,ps_out = None,pad_left=True):
399 399
400 400 cache_size_min = 20
401 401 if cache_size <= 0:
@@ -413,9 +413,12 b' class CachedOutput:'
413 413 self.input_sep = input_sep
414 414
415 415 # we need a reference to the user-level namespace
416 self.user_ns = user_ns
416 self.shell = shell
417 self.user_ns = shell.user_ns
417 418 # and to the user's input
418 self.input_hist = input_hist
419 self.input_hist = shell.input_hist
420 # and to the user's logger, for logging output
421 self.logger = shell.logger
419 422
420 423 # Set input prompt strings and colors
421 424 if cache_size == 0:
@@ -509,11 +512,13 b' class CachedOutput:'
509 512 print 'Executing Macro...'
510 513 # in case the macro takes a long time to execute
511 514 Term.cout.flush()
512 exec arg.value in self.user_ns
515 self.shell.runlines(arg.value)
513 516 return None
514 517
515 518 # and now call a possibly user-defined print mechanism
516 519 self.display(arg)
520 if self.logger.log_output:
521 self.logger.log_write(repr(arg),'output')
517 522 cout_write(self.output_sep2)
518 523 Term.cout.flush()
519 524
@@ -6,7 +6,7 b' Requires Python 2.1 or newer.'
6 6
7 7 This file contains all the classes and helper functions specific to IPython.
8 8
9 $Id: iplib.py 965 2005-12-28 23:23:09Z fperez $
9 $Id: iplib.py 966 2005-12-29 08:34:07Z fperez $
10 10 """
11 11
12 12 #*****************************************************************************
@@ -67,7 +67,8 b' from IPython.ColorANSI import ColorScheme,ColorSchemeTable # too long names'
67 67 from IPython.FakeModule import FakeModule
68 68 from IPython.Itpl import Itpl,itpl,printpl,ItplNS,itplns
69 69 from IPython.Logger import Logger
70 from IPython.Magic import Magic,magic2python
70 from IPython.Magic import Magic
71 from IPython.Prompts import CachedOutput
71 72 from IPython.Struct import Struct
72 73 from IPython.background_jobs import BackgroundJobManager
73 74 from IPython.usage import cmd_line_usage,interactive_usage
@@ -229,7 +230,27 b' class SyntaxTB(ultraTB.ListTB):'
229 230
230 231 #****************************************************************************
231 232 # Main IPython class
232 class InteractiveShell(Logger, Magic):
233
234 # FIXME: the Magic class is a mixin for now, and will unfortunately remain so
235 # until a full rewrite is made. I've cleaned all cross-class uses of
236 # attributes and methods, but too much user code out there relies on the
237 # equlity %foo == __IP.magic_foo, so I can't actually remove the mixin usage.
238 #
239 # But at least now, all the pieces have been separated and we could, in
240 # principle, stop using the mixin. This will ease the transition to the
241 # chainsaw branch.
242
243 # For reference, the following is the list of 'self.foo' uses in the Magic
244 # class as of 2005-12-28. These are names we CAN'T use in the main ipython
245 # class, to prevent clashes.
246
247 # ['self.__class__', 'self.__dict__', 'self._inspect', 'self._ofind',
248 # 'self.arg_err', 'self.extract_input', 'self.format_', 'self.lsmagic',
249 # 'self.magic_', 'self.options_table', 'self.parse', 'self.shell',
250 # 'self.value']
251
252
253 class InteractiveShell(Magic):
233 254 """An enhanced console for Python."""
234 255
235 256 # class attribute to indicate whether the class supports threads or not.
@@ -305,7 +326,6 b' class InteractiveShell(Logger, Magic):'
305 326 # Von: Alex Martelli <aleaxit@yahoo.com>
306 327 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
307 328 # Gruppen: comp.lang.python
308 # Referenzen: 1
309 329
310 330 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
311 331 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
@@ -441,13 +461,8 b' class InteractiveShell(Logger, Magic):'
441 461 }
442 462
443 463 # class initializations
444 Logger.__init__(self,log_ns = self.user_ns)
445 464 Magic.__init__(self,self)
446 465
447 # an ugly hack to get a pointer to the shell, so I can start writing
448 # magic code via this pointer instead of the current mixin salad.
449 Magic.set_shell(self,self)
450
451 466 # Python source parser/formatter for syntax highlighting
452 467 pyformat = PyColorize.Parser().format
453 468 self.pycolorize = lambda src: pyformat(src,'str',self.rc['colors'])
@@ -488,6 +503,16 b' class InteractiveShell(Logger, Magic):'
488 503 # Keep track of readline usage (later set by init_readline)
489 504 self.has_readline = False
490 505
506 # template for logfile headers. It gets resolved at runtime by the
507 # logstart method.
508 self.loghead_tpl = \
509 """#log# Automatic Logger file. *** THIS MUST BE THE FIRST LINE ***
510 #log# DO NOT CHANGE THIS LINE OR THE TWO BELOW
511 #log# opts = %s
512 #log# args = %s
513 #log# It is safe to make manual edits below here.
514 #log#-----------------------------------------------------------------------
515 """
491 516 # for pushd/popd management
492 517 try:
493 518 self.home_dir = get_home_dir()
@@ -550,19 +575,6 b' class InteractiveShell(Logger, Magic):'
550 575 # keep track of where we started running (mainly for crash post-mortem)
551 576 self.starting_dir = os.getcwd()
552 577
553 # Attributes for Logger mixin class, make defaults here
554 self._dolog = False
555 self.LOG = ''
556 self.LOGDEF = '.InteractiveShell.log'
557 self.LOGMODE = 'over'
558 self.LOGHEAD = Itpl(
559 """#log# Automatic Logger file. *** THIS MUST BE THE FIRST LINE ***
560 #log# DO NOT CHANGE THIS LINE OR THE TWO BELOW
561 #log# opts = $self.rc.opts
562 #log# args = $self.rc.args
563 #log# It is safe to make manual edits below here.
564 #log#-----------------------------------------------------------------------
565 """)
566 578 # Various switches which can be set
567 579 self.CACHELENGTH = 5000 # this is cheap, it's just text
568 580 self.BANNER = "Python %(version)s on %(platform)s\n" % sys.__dict__
@@ -655,10 +667,42 b' class InteractiveShell(Logger, Magic):'
655 667 if rc.readline:
656 668 self.init_readline()
657 669
670 # log system
671 self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate')
672 # local shortcut, this is used a LOT
673 self.log = self.logger.log
674
675 # Initialize cache, set in/out prompts and printing system
676 self.outputcache = CachedOutput(self,
677 rc.cache_size,
678 rc.pprint,
679 input_sep = rc.separate_in,
680 output_sep = rc.separate_out,
681 output_sep2 = rc.separate_out2,
682 ps1 = rc.prompt_in1,
683 ps2 = rc.prompt_in2,
684 ps_out = rc.prompt_out,
685 pad_left = rc.prompts_pad_left)
686
687 # user may have over-ridden the default print hook:
688 try:
689 self.outputcache.__class__.display = self.hooks.display
690 except AttributeError:
691 pass
692
693 # I don't like assigning globally to sys, because it means when embedding
694 # instances, each embedded instance overrides the previous choice. But
695 # sys.displayhook seems to be called internally by exec, so I don't see a
696 # way around it.
697 sys.displayhook = self.outputcache
698
658 699 # Set user colors (don't do it in the constructor above so that it
659 700 # doesn't crash if colors option is invalid)
660 701 self.magic_colors(rc.colors)
661 702
703 # Set calling of pdb on exceptions
704 self.call_pdb = rc.pdb
705
662 706 # Load user aliases
663 707 for alias in rc.alias:
664 708 self.magic_alias(alias)
@@ -742,6 +786,28 b' class InteractiveShell(Logger, Magic):'
742 786 self.Completer.__class__)
743 787 self.Completer.matchers.insert(pos,newcomp)
744 788
789 def _get_call_pdb(self):
790 return self._call_pdb
791
792 def _set_call_pdb(self,val):
793
794 if val not in (0,1,False,True):
795 raise ValueError,'new call_pdb value must be boolean'
796
797 # store value in instance
798 self._call_pdb = val
799
800 # notify the actual exception handlers
801 self.InteractiveTB.call_pdb = val
802 if self.isthreaded:
803 try:
804 self.sys_excepthook.call_pdb = val
805 except:
806 warn('Failed to activate pdb for threaded exception handler')
807
808 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
809 'Control auto-activation of pdb at exceptions')
810
745 811 def complete(self,text):
746 812 """Return a sorted list of all possible completions on text.
747 813
@@ -1907,10 +1973,10 b' want to merge them back into the new files.""" % locals()'
1907 1973 kw.setdefault('quiet',1)
1908 1974 kw.setdefault('exit_ignore',0)
1909 1975 first = xfile.readline()
1910 _LOGHEAD = str(self.LOGHEAD).split('\n',1)[0].strip()
1976 loghead = str(self.loghead_tpl).split('\n',1)[0].strip()
1911 1977 xfile.close()
1912 1978 # line by line execution
1913 if first.startswith(_LOGHEAD) or kw['islog']:
1979 if first.startswith(loghead) or kw['islog']:
1914 1980 print 'Loading log file <%s> one line at a time...' % fname
1915 1981 if kw['quiet']:
1916 1982 stdout_save = sys.stdout
@@ -1942,9 +2008,6 b' want to merge them back into the new files.""" % locals()'
1942 2008 # don't re-insert logger status info into cache
1943 2009 if line.startswith('#log#'):
1944 2010 continue
1945 elif line.startswith('#%s'% self.ESC_MAGIC):
1946 self.update_cache(line[1:])
1947 line = magic2python(line)
1948 2011 elif line.startswith('#!'):
1949 2012 self.update_cache(line[1:])
1950 2013 else:
@@ -6,7 +6,7 b' Requires Python 2.1 or better.'
6 6
7 7 This file contains the main make_IPython() starter function.
8 8
9 $Id: ipmaker.py 965 2005-12-28 23:23:09Z fperez $"""
9 $Id: ipmaker.py 966 2005-12-29 08:34:07Z fperez $"""
10 10
11 11 #*****************************************************************************
12 12 # Copyright (C) 2001-2004 Fernando Perez. <fperez@colorado.edu>
@@ -51,7 +51,6 b' from IPython.OutputTrap import OutputTrap'
51 51 from IPython.ConfigLoader import ConfigLoader
52 52 from IPython.iplib import InteractiveShell,qw_lol,import_fail_info
53 53 from IPython.usage import cmd_line_usage,interactive_usage
54 from IPython.Prompts import CachedOutput
55 54 from IPython.genutils import *
56 55
57 56 #-----------------------------------------------------------------------------
@@ -322,9 +321,6 b" object? -> Details about 'object'. ?object also works, ?? prints more."
322 321 mutex_opts(opts,[qw('log logfile'),qw('rcfile profile'),
323 322 qw('classic profile'),qw('classic rcfile')])
324 323
325 # default logfilename used when -log is called.
326 IP.LOGDEF = 'ipython.log'
327
328 324 #---------------------------------------------------------------------------
329 325 # Log replay
330 326
@@ -681,36 +677,6 b" object? -> Details about 'object'. ?object also works, ?? prints more."
681 677 # paged:
682 678 num_lines_bot = IP_rc.separate_in.count('\n')+1
683 679 IP_rc.screen_length = IP_rc.screen_length - num_lines_bot
684 # Initialize cache, set in/out prompts and printing system
685 IP.outputcache = CachedOutput(IP_rc.cache_size,
686 IP_rc.pprint,
687 input_sep = IP_rc.separate_in,
688 output_sep = IP_rc.separate_out,
689 output_sep2 = IP_rc.separate_out2,
690 ps1 = IP_rc.prompt_in1,
691 ps2 = IP_rc.prompt_in2,
692 ps_out = IP_rc.prompt_out,
693 user_ns = IP.user_ns,
694 input_hist = IP.input_hist,
695 pad_left = IP_rc.prompts_pad_left)
696
697 # user may have over-ridden the default print hook:
698 try:
699 IP.outputcache.__class__.display = IP.hooks.display
700 except AttributeError:
701 pass
702
703 # Set calling of pdb on exceptions
704 IP.InteractiveTB.call_pdb = IP_rc.pdb
705
706 # I don't like assigning globally to sys, because it means when embedding
707 # instances, each embedded instance overrides the previous choice. But
708 # sys.displayhook seems to be called internally by exec, so I don't see a
709 # way around it.
710 sys.displayhook = IP.outputcache
711
712 # we need to know globally if we're caching i/o or not
713 IP.do_full_cache = IP.outputcache.do_full_cache
714 680
715 681 # configure startup banner
716 682 if IP_rc.c: # regular python doesn't print the banner with -c
@@ -6,7 +6,7 b''
6 6 # the file COPYING, distributed as part of this software.
7 7 #*****************************************************************************
8 8
9 # $Id: usage.py 960 2005-12-28 06:51:01Z fperez $
9 # $Id: usage.py 966 2005-12-29 08:34:07Z fperez $
10 10
11 11 from IPython import Release
12 12 __author__ = '%s <%s>' % Release.authors['Fernando']
@@ -236,14 +236,14 b' REGULAR OPTIONS'
236 236 This can also be specified through the environment variable
237 237 IPYTHONDIR.
238 238
239 -log|l Generate a log file of all input. The file is named ipython.log
240 in your current directory (which prevents logs from multiple
241 IPython sessions from trampling each other). You can use this to
242 later restore a session by loading your logfile as a file to be
243 executed with option -logplay (see below).
239 -log|l Generate a log file of all input. The file is named
240 ipython_log.py in your current directory (which prevents logs
241 from multiple IPython sessions from trampling each other). You
242 can use this to later restore a session by loading your logfile
243 as a file to be executed with option -logplay (see below).
244 244
245 245 -logfile|lf
246 Specifu the name of your logfile.
246 Specify the name of your logfile.
247 247
248 248 -logplay|lp
249 249 Replay a previous log. For restoring a session as close as pos-
@@ -1,3 +1,31 b''
1 2005-12-29 Fernando Perez <Fernando.Perez@colorado.edu>
2
3 * IPython/Magic.py (Macro): simplified Macro class to just
4 subclass list. We've had only 2.2 compatibility for a very long
5 time, yet I was still avoiding subclassing the builtin types. No
6 more (I'm also starting to use properties, though I won't shift to
7 2.3-specific features quite yet).
8
9 * IPython/iplib.py (InteractiveShell.post_config_initialization):
10 changed the default logfile name from 'ipython.log' to
11 'ipython_log.py'. These logs are real python files, and now that
12 we have much better multiline support, people are more likely to
13 want to use them as such. Might as well name them correctly.
14
15 * IPython/Magic.py: substantial cleanup. While we can't stop
16 using magics as mixins, due to the existing customizations 'out
17 there' which rely on the mixin naming conventions, at least I
18 cleaned out all cross-class name usage. So once we are OK with
19 breaking compatibility, the two systems can be separated.
20
21 * IPython/Logger.py: major cleanup. This one is NOT a mixin
22 anymore, and the class is a fair bit less hideous as well. New
23 features were also introduced: timestamping of input, and logging
24 of output results. These are user-visible with the -t and -o
25 options to %logstart. Closes
26 http://www.scipy.net/roundup/ipython/issue11 and a request by
27 William Stein (SAGE developer - http://modular.ucsd.edu/sage).
28
1 29 2005-12-28 Fernando Perez <Fernando.Perez@colorado.edu>
2 30
3 31 * IPython/iplib.py (handle_shell_escape): add Ville's patch to
@@ -205,14 +205,13 b' The name of your IPython configuration directory IPYTHONDIR. This can'
205 205 also be specified through the environment variable IPYTHONDIR.
206 206 .TP
207 207 .B \-log|l
208 Generate a log file of all input. The file is named ipython.log in
209 your current directory (which prevents logs from multiple IPython
210 sessions from trampling each other). You can use this to later restore
211 a session by loading your logfile as a file to be executed with option
212 -logplay (see below).
208 Generate a log file of all input. The file is named ipython_log.py in your
209 current directory (which prevents logs from multiple IPython sessions from
210 trampling each other). You can use this to later restore a session by loading
211 your logfile as a file to be executed with option -logplay (see below).
213 212 .TP
214 213 .B \-logfile|lf
215 Specifu the name of your logfile.
214 Specify the name of your logfile.
216 215 .TP
217 216 .B \-logplay|lp
218 217 Replay a previous log. For restoring a session as close as possible to
@@ -2957,11 +2957,12 b' IPYTHONDIR'
2957 2957 \family default
2958 2958 \series default
2959 2959 : generate a log file of all input.
2960 Defaults to
2960 The file is named
2961 2961 \family typewriter
2962 $IPYTHONDIR/log
2962 ipython_log.py
2963 2963 \family default
2964 .
2964 in your current directory (which prevents logs from multiple IPython sessions
2965 from trampling each other).
2965 2966 You can use this to later restore a session by loading your logfile as
2966 2967 a file to be executed with option
2967 2968 \family typewriter
General Comments 0
You need to be logged in to leave comments. Login now