##// END OF EJS Templates
Remove svn-style $Id marks from docstrings and Release imports....
Fernando Perez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,182 +1,177 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for coloring text in ANSI terminals.
3
4 $Id: ColorANSI.py 2167 2007-03-21 06:57:50Z fperez $"""
3 """
5 4
6 5 #*****************************************************************************
7 6 # Copyright (C) 2002-2006 Fernando Perez. <fperez@colorado.edu>
8 7 #
9 8 # Distributed under the terms of the BSD License. The full license is in
10 9 # the file COPYING, distributed as part of this software.
11 10 #*****************************************************************************
12 11
13 from IPython import Release
14 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __license__ = Release.license
16
17 12 __all__ = ['TermColors','InputTermColors','ColorScheme','ColorSchemeTable']
18 13
19 14 import os
20 15
21 16 from IPython.ipstruct import Struct
22 17
23 18 def make_color_table(in_class):
24 19 """Build a set of color attributes in a class.
25 20
26 21 Helper function for building the *TermColors classes."""
27 22
28 23 color_templates = (
29 24 # Dark colors
30 25 ("Black" , "0;30"),
31 26 ("Red" , "0;31"),
32 27 ("Green" , "0;32"),
33 28 ("Brown" , "0;33"),
34 29 ("Blue" , "0;34"),
35 30 ("Purple" , "0;35"),
36 31 ("Cyan" , "0;36"),
37 32 ("LightGray" , "0;37"),
38 33 # Light colors
39 34 ("DarkGray" , "1;30"),
40 35 ("LightRed" , "1;31"),
41 36 ("LightGreen" , "1;32"),
42 37 ("Yellow" , "1;33"),
43 38 ("LightBlue" , "1;34"),
44 39 ("LightPurple" , "1;35"),
45 40 ("LightCyan" , "1;36"),
46 41 ("White" , "1;37"),
47 42 # Blinking colors. Probably should not be used in anything serious.
48 43 ("BlinkBlack" , "5;30"),
49 44 ("BlinkRed" , "5;31"),
50 45 ("BlinkGreen" , "5;32"),
51 46 ("BlinkYellow" , "5;33"),
52 47 ("BlinkBlue" , "5;34"),
53 48 ("BlinkPurple" , "5;35"),
54 49 ("BlinkCyan" , "5;36"),
55 50 ("BlinkLightGray", "5;37"),
56 51 )
57 52
58 53 for name,value in color_templates:
59 54 setattr(in_class,name,in_class._base % value)
60 55
61 56 class TermColors:
62 57 """Color escape sequences.
63 58
64 59 This class defines the escape sequences for all the standard (ANSI?)
65 60 colors in terminals. Also defines a NoColor escape which is just the null
66 61 string, suitable for defining 'dummy' color schemes in terminals which get
67 62 confused by color escapes.
68 63
69 64 This class should be used as a mixin for building color schemes."""
70 65
71 66 NoColor = '' # for color schemes in color-less terminals.
72 67 Normal = '\033[0m' # Reset normal coloring
73 68 _base = '\033[%sm' # Template for all other colors
74 69
75 70 # Build the actual color table as a set of class attributes:
76 71 make_color_table(TermColors)
77 72
78 73 class InputTermColors:
79 74 """Color escape sequences for input prompts.
80 75
81 76 This class is similar to TermColors, but the escapes are wrapped in \001
82 77 and \002 so that readline can properly know the length of each line and
83 78 can wrap lines accordingly. Use this class for any colored text which
84 79 needs to be used in input prompts, such as in calls to raw_input().
85 80
86 81 This class defines the escape sequences for all the standard (ANSI?)
87 82 colors in terminals. Also defines a NoColor escape which is just the null
88 83 string, suitable for defining 'dummy' color schemes in terminals which get
89 84 confused by color escapes.
90 85
91 86 This class should be used as a mixin for building color schemes."""
92 87
93 88 NoColor = '' # for color schemes in color-less terminals.
94 89
95 90 if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs':
96 91 # (X)emacs on W32 gets confused with \001 and \002 so we remove them
97 92 Normal = '\033[0m' # Reset normal coloring
98 93 _base = '\033[%sm' # Template for all other colors
99 94 else:
100 95 Normal = '\001\033[0m\002' # Reset normal coloring
101 96 _base = '\001\033[%sm\002' # Template for all other colors
102 97
103 98 # Build the actual color table as a set of class attributes:
104 99 make_color_table(InputTermColors)
105 100
106 101 class ColorScheme:
107 102 """Generic color scheme class. Just a name and a Struct."""
108 103 def __init__(self,__scheme_name_,colordict=None,**colormap):
109 104 self.name = __scheme_name_
110 105 if colordict is None:
111 106 self.colors = Struct(**colormap)
112 107 else:
113 108 self.colors = Struct(colordict)
114 109
115 110 def copy(self,name=None):
116 111 """Return a full copy of the object, optionally renaming it."""
117 112 if name is None:
118 113 name = self.name
119 114 return ColorScheme(name,self.colors.__dict__)
120 115
121 116 class ColorSchemeTable(dict):
122 117 """General class to handle tables of color schemes.
123 118
124 119 It's basically a dict of color schemes with a couple of shorthand
125 120 attributes and some convenient methods.
126 121
127 122 active_scheme_name -> obvious
128 123 active_colors -> actual color table of the active scheme"""
129 124
130 125 def __init__(self,scheme_list=None,default_scheme=''):
131 126 """Create a table of color schemes.
132 127
133 128 The table can be created empty and manually filled or it can be
134 129 created with a list of valid color schemes AND the specification for
135 130 the default active scheme.
136 131 """
137 132
138 133 # create object attributes to be set later
139 134 self.active_scheme_name = ''
140 135 self.active_colors = None
141 136
142 137 if scheme_list:
143 138 if default_scheme == '':
144 139 raise ValueError,'you must specify the default color scheme'
145 140 for scheme in scheme_list:
146 141 self.add_scheme(scheme)
147 142 self.set_active_scheme(default_scheme)
148 143
149 144 def copy(self):
150 145 """Return full copy of object"""
151 146 return ColorSchemeTable(self.values(),self.active_scheme_name)
152 147
153 148 def add_scheme(self,new_scheme):
154 149 """Add a new color scheme to the table."""
155 150 if not isinstance(new_scheme,ColorScheme):
156 151 raise ValueError,'ColorSchemeTable only accepts ColorScheme instances'
157 152 self[new_scheme.name] = new_scheme
158 153
159 154 def set_active_scheme(self,scheme,case_sensitive=0):
160 155 """Set the currently active scheme.
161 156
162 157 Names are by default compared in a case-insensitive way, but this can
163 158 be changed by setting the parameter case_sensitive to true."""
164 159
165 160 scheme_names = self.keys()
166 161 if case_sensitive:
167 162 valid_schemes = scheme_names
168 163 scheme_test = scheme
169 164 else:
170 165 valid_schemes = [s.lower() for s in scheme_names]
171 166 scheme_test = scheme.lower()
172 167 try:
173 168 scheme_idx = valid_schemes.index(scheme_test)
174 169 except ValueError:
175 170 raise ValueError,'Unrecognized color scheme: ' + scheme + \
176 171 '\nValid schemes: '+str(scheme_names).replace("'', ",'')
177 172 else:
178 173 active = scheme_names[scheme_idx]
179 174 self.active_scheme_name = active
180 175 self.active_colors = self[active].colors
181 176 # Now allow using '' as an index for the current active scheme
182 177 self[''] = self[active]
@@ -1,116 +1,111 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Configuration loader
3
4 $Id: ConfigLoader.py 1005 2006-01-12 08:39:26Z fperez $"""
3 """
5 4
6 5 #*****************************************************************************
7 6 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
8 7 #
9 8 # Distributed under the terms of the BSD License. The full license is in
10 9 # the file COPYING, distributed as part of this software.
11 10 #*****************************************************************************
12 11
13 from IPython import Release
14 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __license__ = Release.license
16
17 12 import exceptions
18 13 import os
19 14 from pprint import pprint
20 15
21 16 from IPython import ultraTB
22 17 from IPython.ipstruct import Struct
23 18 from IPython.genutils import *
24 19
25 20 class ConfigLoaderError(exceptions.Exception):
26 21 """Exception for ConfigLoader class."""
27 22
28 23 def __init__(self,args=None):
29 24 self.args = args
30 25
31 26 class ConfigLoader:
32 27
33 28 """Configuration file loader capable of handling recursive inclusions and
34 29 with parametrized conflict resolution for multiply found keys."""
35 30
36 31 def __init__(self,conflict=None,field_sep=None,reclimit=15):
37 32
38 33 """The reclimit parameter controls the number of recursive
39 34 configuration file inclusions. This way we can stop early on (before
40 35 python's own recursion limit is hit) if there is a circular
41 36 inclusion.
42 37
43 38 - conflict: dictionary for conflict resolutions (see Struct.merge())
44 39
45 40 """
46 41 self.conflict = conflict
47 42 self.field_sep = field_sep
48 43 self.reset(reclimit)
49 44
50 45 def reset(self,reclimit=15):
51 46 self.reclimit = reclimit
52 47 self.recdepth = 0
53 48 self.included = []
54 49
55 50 def load(self,fname,convert=None,recurse_key='',incpath = '.',**kw):
56 51 """Load a configuration file, return the resulting Struct.
57 52
58 53 Call: load_config(fname,convert=None,conflict=None,recurse_key='')
59 54
60 55 - fname: file to load from.
61 56 - convert: dictionary of type conversions (see read_dict())
62 57 - recurse_key: keyword in dictionary to trigger recursive file
63 58 inclusions.
64 59 """
65 60
66 61 if self.recdepth > self.reclimit:
67 62 raise ConfigLoaderError, 'maximum recursive inclusion of rcfiles '+\
68 63 'exceeded: ' + `self.recdepth` + \
69 64 '.\nMaybe you have a circular chain of inclusions?'
70 65 self.recdepth += 1
71 66 fname = filefind(fname,incpath)
72 67 data = Struct()
73 68 # avoid including the same file more than once
74 69 if fname in self.included:
75 70 return data
76 71 Xinfo = ultraTB.AutoFormattedTB(color_scheme='NoColor')
77 72 if convert==None and recurse_key : convert = {qwflat:recurse_key}
78 73 # for production, change warn to 0:
79 74 data.merge(read_dict(fname,convert,fs=self.field_sep,strip=1,
80 75 warn=0,no_empty=0,**kw))
81 76 # keep track of successfully loaded files
82 77 self.included.append(fname)
83 78 if recurse_key in data:
84 79 for incfilename in data[recurse_key]:
85 80 found=0
86 81 try:
87 82 incfile = filefind(incfilename,incpath)
88 83 except IOError:
89 84 if os.name in ['nt','dos']:
90 85 try:
91 86 # Try again with '.ini' extension
92 87 incfilename += '.ini'
93 88 incfile = filefind(incfilename,incpath)
94 89 except IOError:
95 90 found = 0
96 91 else:
97 92 found = 1
98 93 else:
99 94 found = 0
100 95 else:
101 96 found = 1
102 97 if found:
103 98 try:
104 99 data.merge(self.load(incfile,convert,recurse_key,
105 100 incpath,**kw),
106 101 self.conflict)
107 102 except:
108 103 Xinfo()
109 104 warn('Problem loading included file: '+
110 105 `incfilename` + '. Ignoring it...')
111 106 else:
112 107 warn('File `%s` not found. Included by %s' % (incfilename,fname))
113 108
114 109 return data
115 110
116 111 # end ConfigLoader
@@ -1,228 +1,227 b''
1 1 # -*- coding: utf-8 -*-
2 2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
4 $Id: CrashHandler.py 2908 2007-12-30 21:07:46Z vivainio $"""
3 """
5 4
6 5 #*****************************************************************************
7 6 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
8 7 #
9 8 # Distributed under the terms of the BSD License. The full license is in
10 9 # the file COPYING, distributed as part of this software.
11 10 #*****************************************************************************
12 11
13 12 from IPython import Release
14 13 __author__ = '%s <%s>' % Release.authors['Fernando']
15 14 __license__ = Release.license
16 15 __version__ = Release.version
17 16
18 17 #****************************************************************************
19 18 # Required modules
20 19
21 20 # From the standard library
22 21 import os
23 22 import sys
24 23 from pprint import pprint,pformat
25 24
26 25 # Homebrewed
27 26 from IPython.Itpl import Itpl,itpl,printpl
28 27 from IPython.ColorANSI import ColorScheme,ColorSchemeTable # too long names
29 28 from IPython import ultraTB
30 29 from IPython.genutils import *
31 30
32 31 #****************************************************************************
33 32 class CrashHandler:
34 33 """Customizable crash handlers for IPython-based systems.
35 34
36 35 Instances of this class provide a __call__ method which can be used as a
37 36 sys.excepthook, i.e., the __call__ signature is:
38 37
39 38 def __call__(self,etype, evalue, etb)
40 39
41 40 """
42 41
43 42 def __init__(self,IP,app_name,contact_name,contact_email,
44 43 bug_tracker,crash_report_fname,
45 44 show_crash_traceback=True):
46 45 """New crash handler.
47 46
48 47 Inputs:
49 48
50 49 - IP: a running IPython instance, which will be queried at crash time
51 50 for internal information.
52 51
53 52 - app_name: a string containing the name of your application.
54 53
55 54 - contact_name: a string with the name of the person to contact.
56 55
57 56 - contact_email: a string with the email address of the contact.
58 57
59 58 - bug_tracker: a string with the URL for your project's bug tracker.
60 59
61 60 - crash_report_fname: a string with the filename for the crash report
62 61 to be saved in. These reports are left in the ipython user directory
63 62 as determined by the running IPython instance.
64 63
65 64 Optional inputs:
66 65
67 66 - show_crash_traceback(True): if false, don't print the crash
68 67 traceback on stderr, only generate the on-disk report
69 68
70 69
71 70 Non-argument instance attributes:
72 71
73 72 These instances contain some non-argument attributes which allow for
74 73 further customization of the crash handler's behavior. Please see the
75 74 source for further details.
76 75 """
77 76
78 77 # apply args into instance
79 78 self.IP = IP # IPython instance
80 79 self.app_name = app_name
81 80 self.contact_name = contact_name
82 81 self.contact_email = contact_email
83 82 self.bug_tracker = bug_tracker
84 83 self.crash_report_fname = crash_report_fname
85 84 self.show_crash_traceback = show_crash_traceback
86 85
87 86 # Hardcoded defaults, which can be overridden either by subclasses or
88 87 # at runtime for the instance.
89 88
90 89 # Template for the user message. Subclasses which completely override
91 90 # this, or user apps, can modify it to suit their tastes. It gets
92 91 # expanded using itpl, so calls of the kind $self.foo are valid.
93 92 self.user_message_template = """
94 93 Oops, $self.app_name crashed. We do our best to make it stable, but...
95 94
96 95 A crash report was automatically generated with the following information:
97 96 - A verbatim copy of the crash traceback.
98 97 - A copy of your input history during this session.
99 98 - Data on your current $self.app_name configuration.
100 99
101 100 It was left in the file named:
102 101 \t'$self.crash_report_fname'
103 102 If you can email this file to the developers, the information in it will help
104 103 them in understanding and correcting the problem.
105 104
106 105 You can mail it to: $self.contact_name at $self.contact_email
107 106 with the subject '$self.app_name Crash Report'.
108 107
109 108 If you want to do it now, the following command will work (under Unix):
110 109 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
111 110
112 111 To ensure accurate tracking of this issue, please file a report about it at:
113 112 $self.bug_tracker
114 113 """
115 114
116 115 def __call__(self,etype, evalue, etb):
117 116 """Handle an exception, call for compatible with sys.excepthook"""
118 117
119 118 # Report tracebacks shouldn't use color in general (safer for users)
120 119 color_scheme = 'NoColor'
121 120
122 121 # Use this ONLY for developer debugging (keep commented out for release)
123 122 #color_scheme = 'Linux' # dbg
124 123
125 124 try:
126 125 rptdir = self.IP.rc.ipythondir
127 126 except:
128 127 rptdir = os.getcwd()
129 128 if not os.path.isdir(rptdir):
130 129 rptdir = os.getcwd()
131 130 report_name = os.path.join(rptdir,self.crash_report_fname)
132 131 # write the report filename into the instance dict so it can get
133 132 # properly expanded out in the user message template
134 133 self.crash_report_fname = report_name
135 134 TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,
136 135 long_header=1)
137 136 traceback = TBhandler.text(etype,evalue,etb,context=31)
138 137
139 138 # print traceback to screen
140 139 if self.show_crash_traceback:
141 140 print >> sys.stderr, traceback
142 141
143 142 # and generate a complete report on disk
144 143 try:
145 144 report = open(report_name,'w')
146 145 except:
147 146 print >> sys.stderr, 'Could not create crash report on disk.'
148 147 return
149 148
150 149 # Inform user on stderr of what happened
151 150 msg = itpl('\n'+'*'*70+'\n'+self.user_message_template)
152 151 print >> sys.stderr, msg
153 152
154 153 # Construct report on disk
155 154 report.write(self.make_report(traceback))
156 155 report.close()
157 156 raw_input("Press enter to exit:")
158 157
159 158 def make_report(self,traceback):
160 159 """Return a string containing a crash report."""
161 160
162 161 sec_sep = '\n\n'+'*'*75+'\n\n'
163 162
164 163 report = []
165 164 rpt_add = report.append
166 165
167 166 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
168 167 rpt_add('IPython version: %s \n\n' % Release.version)
169 168 rpt_add('SVN revision : %s \n\n' % Release.revision)
170 169 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
171 170 (os.name,sys.platform) )
172 171 rpt_add(sec_sep+'Current user configuration structure:\n\n')
173 172 rpt_add(pformat(self.IP.rc.dict()))
174 173 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
175 174 try:
176 175 rpt_add(sec_sep+"History of session input:")
177 176 for line in self.IP.user_ns['_ih']:
178 177 rpt_add(line)
179 178 rpt_add('\n*** Last line of input (may not be in above history):\n')
180 179 rpt_add(self.IP._last_input_line+'\n')
181 180 except:
182 181 pass
183 182
184 183 return ''.join(report)
185 184
186 185 class IPythonCrashHandler(CrashHandler):
187 186 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
188 187
189 188 def __init__(self,IP):
190 189
191 190 # Set here which of the IPython authors should be listed as contact
192 191 AUTHOR_CONTACT = 'Ville'
193 192
194 193 # Set argument defaults
195 194 app_name = 'IPython'
196 195 bug_tracker = 'http://projects.scipy.org/ipython/ipython/report'
197 196 contact_name,contact_email = Release.authors[AUTHOR_CONTACT][:2]
198 197 crash_report_fname = 'IPython_crash_report.txt'
199 198 # Call parent constructor
200 199 CrashHandler.__init__(self,IP,app_name,contact_name,contact_email,
201 200 bug_tracker,crash_report_fname)
202 201
203 202 def make_report(self,traceback):
204 203 """Return a string containing a crash report."""
205 204
206 205 sec_sep = '\n\n'+'*'*75+'\n\n'
207 206
208 207 report = []
209 208 rpt_add = report.append
210 209
211 210 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
212 211 rpt_add('IPython version: %s \n\n' % Release.version)
213 212 rpt_add('SVN revision : %s \n\n' % Release.revision)
214 213 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
215 214 (os.name,sys.platform) )
216 215 rpt_add(sec_sep+'Current user configuration structure:\n\n')
217 216 rpt_add(pformat(self.IP.rc.dict()))
218 217 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
219 218 try:
220 219 rpt_add(sec_sep+"History of session input:")
221 220 for line in self.IP.user_ns['_ih']:
222 221 rpt_add(line)
223 222 rpt_add('\n*** Last line of input (may not be in above history):\n')
224 223 rpt_add(self.IP._last_input_line+'\n')
225 224 except:
226 225 pass
227 226
228 227 return ''.join(report)
@@ -1,693 +1,690 b''
1 1 # -*- coding: utf-8 -*-
2 2 """DPyGetOpt -- Demiurge Python GetOptions Module
3 3
4 $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $
5
6 4 This module is modeled after perl's Getopt::Long module-- which
7 5 is, in turn, modeled after GNU's extended getopt() function.
8 6
9 7 Upon instantiation, the option specification should be a sequence
10 8 (list) of option definitions.
11 9
12 10 Options that take no arguments should simply contain the name of
13 11 the option. If a ! is post-pended, the option can be negated by
14 12 prepending 'no'; ie 'debug!' specifies that -debug and -nodebug
15 13 should be accepted.
16 14
17 15 Mandatory arguments to options are specified using a postpended
18 16 '=' + a type specifier. '=s' specifies a mandatory string
19 17 argument, '=i' specifies a mandatory integer argument, and '=f'
20 18 specifies a mandatory real number. In all cases, the '=' can be
21 19 substituted with ':' to specify that the argument is optional.
22 20
23 21 Dashes '-' in option names are allowed.
24 22
25 23 If an option has the character '@' postpended (after the
26 24 argumentation specification), it can appear multiple times within
27 25 each argument list that is processed. The results will be stored
28 26 in a list.
29 27
30 28 The option name can actually be a list of names separated by '|'
31 29 characters; ie-- 'foo|bar|baz=f@' specifies that all -foo, -bar,
32 30 and -baz options that appear on within the parsed argument list
33 31 must have a real number argument and that the accumulated list
34 32 of values will be available under the name 'foo'
35
36 $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $"""
33 """
37 34
38 35 #*****************************************************************************
39 36 #
40 37 # Copyright (c) 2001 Bill Bumgarner <bbum@friday.com>
41 38 #
42 39 #
43 40 # Published under the terms of the MIT license, hereby reproduced:
44 41 #
45 42 # Permission is hereby granted, free of charge, to any person obtaining a copy
46 43 # of this software and associated documentation files (the "Software"), to
47 44 # deal in the Software without restriction, including without limitation the
48 45 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
49 46 # sell copies of the Software, and to permit persons to whom the Software is
50 47 # furnished to do so, subject to the following conditions:
51 48 #
52 49 # The above copyright notice and this permission notice shall be included in
53 50 # all copies or substantial portions of the Software.
54 51 #
55 52 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56 53 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57 54 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58 55 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59 56 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
60 57 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
61 58 # IN THE SOFTWARE.
62 59 #
63 60 #*****************************************************************************
64 61
65 62 __author__ = 'Bill Bumgarner <bbum@friday.com>'
66 63 __license__ = 'MIT'
67 64 __version__ = '1.2'
68 65
69 66 # Modified to use re instead of regex and regsub modules.
70 67 # 2001/5/7, Jonathan Hogg <jonathan@onegoodidea.com>
71 68
72 69 import re
73 70 import string
74 71 import sys
75 72 import types
76 73
77 74 class Error(Exception):
78 75 """Base class for exceptions in the DPyGetOpt module."""
79 76
80 77 class ArgumentError(Error):
81 78 """Exception indicating an error in the arguments passed to
82 79 DPyGetOpt.processArguments."""
83 80
84 81 class SpecificationError(Error):
85 82 """Exception indicating an error with an option specification."""
86 83
87 84 class TerminationError(Error):
88 85 """Exception indicating an error with an option processing terminator."""
89 86
90 87 specificationExpr = re.compile('(?P<required>.)(?P<type>.)(?P<multi>@?)')
91 88
92 89 ArgRequired = 'Requires an Argument'
93 90 ArgOptional = 'Argument Optional'
94 91
95 92 # The types modules is not used for these identifiers because there
96 93 # is no identifier for 'boolean' or 'generic'
97 94 StringArgType = 'String Argument Type'
98 95 IntegerArgType = 'Integer Argument Type'
99 96 RealArgType = 'Real Argument Type'
100 97 BooleanArgType = 'Boolean Argument Type'
101 98 GenericArgType = 'Generic Argument Type'
102 99
103 100 # dictionary of conversion functions-- boolean and generic options
104 101 # do not accept arguments and do not need conversion functions;
105 102 # the identity function is used purely for convenience.
106 103 ConversionFunctions = {
107 104 StringArgType : lambda x: x,
108 105 IntegerArgType : string.atoi,
109 106 RealArgType : string.atof,
110 107 BooleanArgType : lambda x: x,
111 108 GenericArgType : lambda x: x,
112 109 }
113 110
114 111 class DPyGetOpt:
115 112
116 113 def __init__(self, spec = None, terminators = ['--']):
117 114 """
118 115 Declare and intialize instance variables
119 116
120 117 Yes, declaration is not necessary... but one of the things
121 118 I sorely miss from C/Obj-C is the concept of having an
122 119 interface definition that clearly declares all instance
123 120 variables and methods without providing any implementation
124 121 details. it is a useful reference!
125 122
126 123 all instance variables are initialized to 0/Null/None of
127 124 the appropriate type-- not even the default value...
128 125 """
129 126
130 127 # sys.stderr.write(string.join(spec) + "\n")
131 128
132 129 self.allowAbbreviations = 1 # boolean, 1 if abbreviations will
133 130 # be expanded
134 131 self.freeValues = [] # list, contains free values
135 132 self.ignoreCase = 0 # boolean, YES if ignoring case
136 133 self.needsParse = 0 # boolean, YES if need to reparse parameter spec
137 134 self.optionNames = {} # dict, all option names-- value is index of tuple
138 135 self.optionStartExpr = None # regexp defining the start of an option (ie; '-', '--')
139 136 self.optionTuples = [] # list o' tuples containing defn of options AND aliases
140 137 self.optionValues = {} # dict, option names (after alias expansion) -> option value(s)
141 138 self.orderMixed = 0 # boolean, YES if options can be mixed with args
142 139 self.posixCompliance = 0 # boolean, YES indicates posix like behaviour
143 140 self.spec = [] # list, raw specs (in case it must be reparsed)
144 141 self.terminators = terminators # list, strings that terminate argument processing
145 142 self.termValues = [] # list, values after terminator
146 143 self.terminator = None # full name of terminator that ended
147 144 # option processing
148 145
149 146 # set up defaults
150 147 self.setPosixCompliance()
151 148 self.setIgnoreCase()
152 149 self.setAllowAbbreviations()
153 150
154 151 # parse spec-- if present
155 152 if spec:
156 153 self.parseConfiguration(spec)
157 154
158 155 def setPosixCompliance(self, aFlag = 0):
159 156 """
160 157 Enables and disables posix compliance.
161 158
162 159 When enabled, '+' can be used as an option prefix and free
163 160 values can be mixed with options.
164 161 """
165 162 self.posixCompliance = aFlag
166 163 self.needsParse = 1
167 164
168 165 if self.posixCompliance:
169 166 self.optionStartExpr = re.compile('(--|-)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
170 167 self.orderMixed = 0
171 168 else:
172 169 self.optionStartExpr = re.compile('(--|-|\+)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
173 170 self.orderMixed = 1
174 171
175 172 def isPosixCompliant(self):
176 173 """
177 174 Returns the value of the posix compliance flag.
178 175 """
179 176 return self.posixCompliance
180 177
181 178 def setIgnoreCase(self, aFlag = 1):
182 179 """
183 180 Enables and disables ignoring case during option processing.
184 181 """
185 182 self.needsParse = 1
186 183 self.ignoreCase = aFlag
187 184
188 185 def ignoreCase(self):
189 186 """
190 187 Returns 1 if the option processor will ignore case when
191 188 processing options.
192 189 """
193 190 return self.ignoreCase
194 191
195 192 def setAllowAbbreviations(self, aFlag = 1):
196 193 """
197 194 Enables and disables the expansion of abbreviations during
198 195 option processing.
199 196 """
200 197 self.allowAbbreviations = aFlag
201 198
202 199 def willAllowAbbreviations(self):
203 200 """
204 201 Returns 1 if abbreviated options will be automatically
205 202 expanded to the non-abbreviated form (instead of causing an
206 203 unrecognized option error).
207 204 """
208 205 return self.allowAbbreviations
209 206
210 207 def addTerminator(self, newTerm):
211 208 """
212 209 Adds newTerm as terminator of option processing.
213 210
214 211 Whenever the option processor encounters one of the terminators
215 212 during option processing, the processing of options terminates
216 213 immediately, all remaining options are stored in the termValues
217 214 instance variable and the full name of the terminator is stored
218 215 in the terminator instance variable.
219 216 """
220 217 self.terminators = self.terminators + [newTerm]
221 218
222 219 def _addOption(self, oTuple):
223 220 """
224 221 Adds the option described by oTuple (name, (type, mode,
225 222 default), alias) to optionTuples. Adds index keyed under name
226 223 to optionNames. Raises SpecificationError if name already in
227 224 optionNames
228 225 """
229 226 (name, (type, mode, default, multi), realName) = oTuple
230 227
231 228 # verify name and add to option names dictionary
232 229 if self.optionNames.has_key(name):
233 230 if realName:
234 231 raise SpecificationError('Alias \'' + name + '\' for \'' +
235 232 realName +
236 233 '\' already used for another option or alias.')
237 234 else:
238 235 raise SpecificationError('Option named \'' + name +
239 236 '\' specified more than once. Specification: '
240 237 + option)
241 238
242 239 # validated. add to optionNames
243 240 self.optionNames[name] = self.tupleIndex
244 241 self.tupleIndex = self.tupleIndex + 1
245 242
246 243 # add to optionTuples
247 244 self.optionTuples = self.optionTuples + [oTuple]
248 245
249 246 # if type is boolean, add negation
250 247 if type == BooleanArgType:
251 248 alias = 'no' + name
252 249 specTuple = (type, mode, 0, multi)
253 250 oTuple = (alias, specTuple, name)
254 251
255 252 # verify name and add to option names dictionary
256 253 if self.optionNames.has_key(alias):
257 254 if realName:
258 255 raise SpecificationError('Negated alias \'' + name +
259 256 '\' for \'' + realName +
260 257 '\' already used for another option or alias.')
261 258 else:
262 259 raise SpecificationError('Negated option named \'' + name +
263 260 '\' specified more than once. Specification: '
264 261 + option)
265 262
266 263 # validated. add to optionNames
267 264 self.optionNames[alias] = self.tupleIndex
268 265 self.tupleIndex = self.tupleIndex + 1
269 266
270 267 # add to optionTuples
271 268 self.optionTuples = self.optionTuples + [oTuple]
272 269
273 270 def addOptionConfigurationTuple(self, oTuple):
274 271 (name, argSpec, realName) = oTuple
275 272 if self.ignoreCase:
276 273 name = string.lower(name)
277 274 if realName:
278 275 realName = string.lower(realName)
279 276 else:
280 277 realName = name
281 278
282 279 oTuple = (name, argSpec, realName)
283 280
284 281 # add option
285 282 self._addOption(oTuple)
286 283
287 284 def addOptionConfigurationTuples(self, oTuple):
288 285 if type(oTuple) is ListType:
289 286 for t in oTuple:
290 287 self.addOptionConfigurationTuple(t)
291 288 else:
292 289 self.addOptionConfigurationTuple(oTuple)
293 290
294 291 def parseConfiguration(self, spec):
295 292 # destroy previous stored information + store raw spec
296 293 self.spec = spec
297 294 self.optionTuples = []
298 295 self.optionNames = {}
299 296 self.tupleIndex = 0
300 297
301 298 tupleIndex = 0
302 299
303 300 # create some regex's for parsing each spec
304 301 splitExpr = \
305 302 re.compile('(?P<names>\w+[-A-Za-z0-9|]*)?(?P<spec>!|[=:][infs]@?)?')
306 303 for option in spec:
307 304 # push to lower case (does not negatively affect
308 305 # specification)
309 306 if self.ignoreCase:
310 307 option = string.lower(option)
311 308
312 309 # break into names, specification
313 310 match = splitExpr.match(option)
314 311 if match is None:
315 312 raise SpecificationError('Invalid specification {' + option +
316 313 '}')
317 314
318 315 names = match.group('names')
319 316 specification = match.group('spec')
320 317
321 318 # break name into name, aliases
322 319 nlist = string.split(names, '|')
323 320
324 321 # get name
325 322 name = nlist[0]
326 323 aliases = nlist[1:]
327 324
328 325 # specificationExpr = regex.symcomp('\(<required>.\)\(<type>.\)\(<multi>@?\)')
329 326 if not specification:
330 327 #spec tuple is ('type', 'arg mode', 'default value', 'multiple')
331 328 argType = GenericArgType
332 329 argMode = None
333 330 argDefault = 1
334 331 argMultiple = 0
335 332 elif specification == '!':
336 333 argType = BooleanArgType
337 334 argMode = None
338 335 argDefault = 1
339 336 argMultiple = 0
340 337 else:
341 338 # parse
342 339 match = specificationExpr.match(specification)
343 340 if match is None:
344 341 # failed to parse, die
345 342 raise SpecificationError('Invalid configuration for option \''
346 343 + option + '\'')
347 344
348 345 # determine mode
349 346 required = match.group('required')
350 347 if required == '=':
351 348 argMode = ArgRequired
352 349 elif required == ':':
353 350 argMode = ArgOptional
354 351 else:
355 352 raise SpecificationError('Unknown requirement configuration \''
356 353 + required + '\'')
357 354
358 355 # determine type
359 356 type = match.group('type')
360 357 if type == 's':
361 358 argType = StringArgType
362 359 argDefault = ''
363 360 elif type == 'i':
364 361 argType = IntegerArgType
365 362 argDefault = 1
366 363 elif type == 'f' or type == 'n':
367 364 argType = RealArgType
368 365 argDefault = 1
369 366 else:
370 367 raise SpecificationError('Unknown type specifier \'' +
371 368 type + '\'')
372 369
373 370 # determine quantity
374 371 if match.group('multi') == '@':
375 372 argMultiple = 1
376 373 else:
377 374 argMultiple = 0
378 375 ## end else (of not specification)
379 376
380 377 # construct specification tuple
381 378 specTuple = (argType, argMode, argDefault, argMultiple)
382 379
383 380 # add the option-- option tuple is (name, specTuple, real name)
384 381 oTuple = (name, specTuple, name)
385 382 self._addOption(oTuple)
386 383
387 384 for alias in aliases:
388 385 # drop to all lower (if configured to do so)
389 386 if self.ignoreCase:
390 387 alias = string.lower(alias)
391 388 # create configuration tuple
392 389 oTuple = (alias, specTuple, name)
393 390 # add
394 391 self._addOption(oTuple)
395 392
396 393 # successfully parsed....
397 394 self.needsParse = 0
398 395
399 396 def _getArgTuple(self, argName):
400 397 """
401 398 Returns a list containing all the specification tuples that
402 399 match argName. If none match, None is returned. If one
403 400 matches, a list with one tuple is returned. If more than one
404 401 match, a list containing all the tuples that matched is
405 402 returned.
406 403
407 404 In other words, this function does not pass judgement upon the
408 405 validity of multiple matches.
409 406 """
410 407 # is it in the optionNames dict?
411 408
412 409 try:
413 410 # sys.stderr.write(argName + string.join(self.optionNames.keys()) + "\n")
414 411
415 412 # yes, get index
416 413 tupleIndex = self.optionNames[argName]
417 414 # and return tuple as element of list
418 415 return [self.optionTuples[tupleIndex]]
419 416 except KeyError:
420 417 # are abbreviations allowed?
421 418 if not self.allowAbbreviations:
422 419 # No! terefore, this cannot be valid argument-- nothing found
423 420 return None
424 421
425 422 # argName might be an abbreviation (and, abbreviations must
426 423 # be allowed... or this would not have been reached!)
427 424
428 425 # create regex for argName
429 426 argExpr = re.compile('^' + argName)
430 427
431 428 tuples = filter(lambda x, argExpr=argExpr: argExpr.search(x[0]) is not None,
432 429 self.optionTuples)
433 430
434 431 if not len(tuples):
435 432 return None
436 433 else:
437 434 return tuples
438 435
439 436 def _isTerminator(self, optionName):
440 437 """
441 438 Returns the full name of the terminator if optionName is a valid
442 439 terminator. If it is, sets self.terminator to the full name of
443 440 the terminator.
444 441
445 442 If more than one terminator matched, raises a TerminationError with a
446 443 string describing the ambiguity.
447 444 """
448 445
449 446 # sys.stderr.write(optionName + "\n")
450 447 # sys.stderr.write(repr(self.terminators))
451 448
452 449 if optionName in self.terminators:
453 450 self.terminator = optionName
454 451 elif not self.allowAbbreviations:
455 452 return None
456 453
457 454 # regex thing in bogus
458 455 # termExpr = regex.compile('^' + optionName)
459 456
460 457 terms = filter(lambda x, on=optionName: string.find(x,on) == 0, self.terminators)
461 458
462 459 if not len(terms):
463 460 return None
464 461 elif len(terms) > 1:
465 462 raise TerminationError('Ambiguous terminator \'' + optionName +
466 463 '\' matches ' + repr(terms))
467 464
468 465 self.terminator = terms[0]
469 466 return self.terminator
470 467
471 468 def processArguments(self, args = None):
472 469 """
473 470 Processes args, a list of arguments (including options).
474 471
475 472 If args is the same as sys.argv, automatically trims the first
476 473 argument (the executable name/path).
477 474
478 475 If an exception is not raised, the argument list was parsed
479 476 correctly.
480 477
481 478 Upon successful completion, the freeValues instance variable
482 479 will contain all the arguments that were not associated with an
483 480 option in the order they were encountered. optionValues is a
484 481 dictionary containing the value of each option-- the method
485 482 valueForOption() can be used to query this dictionary.
486 483 terminator will contain the argument encountered that terminated
487 484 option processing (or None, if a terminator was never
488 485 encountered) and termValues will contain all of the options that
489 486 appeared after the Terminator (or an empty list).
490 487 """
491 488
492 489 if hasattr(sys, "argv") and args == sys.argv:
493 490 args = sys.argv[1:]
494 491
495 492 max = len(args) # maximum index + 1
496 493 self.freeValues = [] # array to hold return values
497 494 self.optionValues= {}
498 495 index = 0 # initial index
499 496 self.terminator = None
500 497 self.termValues = []
501 498
502 499 while index < max:
503 500 # obtain argument
504 501 arg = args[index]
505 502 # increment index -- REMEMBER; it is NOW incremented
506 503 index = index + 1
507 504
508 505 # terminate immediately if option terminator encountered
509 506 if self._isTerminator(arg):
510 507 self.freeValues = self.freeValues + args[index:]
511 508 self.termValues = args[index:]
512 509 return
513 510
514 511 # is this possibly an option?
515 512 match = self.optionStartExpr.match(arg)
516 513 if match is None:
517 514 # not an option-- add to freeValues
518 515 self.freeValues = self.freeValues + [arg]
519 516 if not self.orderMixed:
520 517 # mixing not allowed; add rest of args as freeValues
521 518 self.freeValues = self.freeValues + args[index:]
522 519 # return to caller
523 520 return
524 521 else:
525 522 continue
526 523
527 524 # grab name
528 525 optName = match.group('option')
529 526
530 527 # obtain next argument-- index has already been incremented
531 528 nextArg = match.group('arg')
532 529 if nextArg:
533 530 nextArg = nextArg[1:]
534 531 index = index - 1 # put it back
535 532 else:
536 533 try:
537 534 nextArg = args[index]
538 535 except:
539 536 nextArg = None
540 537
541 538 # transpose to lower case, if necessary
542 539 if self.ignoreCase:
543 540 optName = string.lower(optName)
544 541
545 542 # obtain defining tuple
546 543 tuples = self._getArgTuple(optName)
547 544
548 545 if tuples == None:
549 546 raise ArgumentError('Illegal option \'' + arg + '\'')
550 547 elif len(tuples) > 1:
551 548 raise ArgumentError('Ambiguous option \'' + arg +
552 549 '\'; matches ' +
553 550 repr(map(lambda x: x[0], tuples)))
554 551 else:
555 552 config = tuples[0]
556 553
557 554 # config is now set to the configuration tuple for the
558 555 # argument
559 556 (fullName, spec, realName) = config
560 557 (optType, optMode, optDefault, optMultiple) = spec
561 558
562 559 # if opt mode required, but nextArg is none, raise an error
563 560 if (optMode == ArgRequired):
564 561 if (not nextArg) or self._isTerminator(nextArg):
565 562 # print nextArg
566 563 raise ArgumentError('Option \'' + arg +
567 564 '\' requires an argument of type ' +
568 565 optType)
569 566
570 567 if (not optMode == None) and nextArg and (not self._isTerminator(nextArg)):
571 568 # nextArg defined, option configured to possibly consume arg
572 569 try:
573 570 # grab conversion function-- the try is more for internal diagnostics
574 571 func = ConversionFunctions[optType]
575 572 try:
576 573 optionValue = func(nextArg)
577 574 index = index + 1
578 575 except:
579 576 # only raise conversion error if REQUIRED to consume argument
580 577 if optMode == ArgRequired:
581 578 raise ArgumentError('Invalid argument to option \''
582 579 + arg + '\'; should be \'' +
583 580 optType + '\'')
584 581 else:
585 582 optionValue = optDefault
586 583 except ArgumentError:
587 584 raise
588 585 except:
589 586 raise ArgumentError('(' + arg +
590 587 ') Conversion function for \'' +
591 588 optType + '\' not found.')
592 589 else:
593 590 optionValue = optDefault
594 591
595 592 # add value to options dictionary
596 593 if optMultiple:
597 594 # can be multiple values
598 595 try:
599 596 # try to append element
600 597 self.optionValues[realName] = self.optionValues[realName] + [optionValue]
601 598 except:
602 599 # failed-- must not exist; add it
603 600 self.optionValues[realName] = [optionValue]
604 601 else:
605 602 # only one value per
606 603 if self.isPosixCompliant and self.optionValues.has_key(realName):
607 604 raise ArgumentError('Argument \'' + arg +
608 605 '\' occurs multiple times.')
609 606
610 607 self.optionValues[realName] = optionValue
611 608
612 609 def valueForOption(self, optionName, defaultValue = None):
613 610 """
614 611 Return the value associated with optionName. If optionName was
615 612 not encountered during parsing of the arguments, returns the
616 613 defaultValue (which defaults to None).
617 614 """
618 615 try:
619 616 optionValue = self.optionValues[optionName]
620 617 except:
621 618 optionValue = defaultValue
622 619
623 620 return optionValue
624 621
625 622 ##
626 623 ## test/example section
627 624 ##
628 625 test_error = 'Test Run Amok!'
629 626 def _test():
630 627 """
631 628 A relatively complete test suite.
632 629 """
633 630 try:
634 631 DPyGetOpt(['foo', 'bar=s', 'foo'])
635 632 except Error, exc:
636 633 print 'EXCEPTION (should be \'foo\' already used..): %s' % exc
637 634
638 635 try:
639 636 DPyGetOpt(['foo|bar|apple=s@', 'baz|apple!'])
640 637 except Error, exc:
641 638 print 'EXCEPTION (should be duplicate alias/name error): %s' % exc
642 639
643 640 x = DPyGetOpt(['apple|atlas=i@', 'application|executable=f@'])
644 641 try:
645 642 x.processArguments(['-app', '29.3'])
646 643 except Error, exc:
647 644 print 'EXCEPTION (should be ambiguous argument): %s' % exc
648 645
649 646 x = DPyGetOpt(['foo'], ['antigravity', 'antithesis'])
650 647 try:
651 648 x.processArguments(['-foo', 'anti'])
652 649 except Error, exc:
653 650 print 'EXCEPTION (should be ambiguous terminator): %s' % exc
654 651
655 652 profile = ['plain-option',
656 653 'boolean-option!',
657 654 'list-of-integers=i@',
658 655 'list-real-option|list-real-alias|list-real-pseudonym=f@',
659 656 'optional-string-option:s',
660 657 'abbreviated-string-list=s@']
661 658
662 659 terminators = ['terminator']
663 660
664 661 args = ['-plain-option',
665 662 '+noboolean-option',
666 663 '--list-of-integers', '1',
667 664 '+list-of-integers', '2',
668 665 '-list-of-integers', '3',
669 666 'freeargone',
670 667 '-list-real-option', '1.1',
671 668 '+list-real-alias', '1.2',
672 669 '--list-real-pseudonym', '1.3',
673 670 'freeargtwo',
674 671 '-abbreviated-string-list', 'String1',
675 672 '--abbreviated-s', 'String2',
676 673 '-abbrev', 'String3',
677 674 '-a', 'String4',
678 675 '-optional-string-option',
679 676 'term',
680 677 'next option should look like an invalid arg',
681 678 '-a']
682 679
683 680
684 681 print 'Using profile: ' + repr(profile)
685 682 print 'With terminator: ' + repr(terminators)
686 683 print 'Processing arguments: ' + repr(args)
687 684
688 685 go = DPyGetOpt(profile, terminators)
689 686 go.processArguments(args)
690 687
691 688 print 'Options (and values): ' + repr(go.optionValues)
692 689 print 'free args: ' + repr(go.freeValues)
693 690 print 'term args: ' + repr(go.termValues)
@@ -1,528 +1,522 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 http://www.python.org/2.2.3/license.html
17
18 $Id: Debugger.py 2913 2007-12-31 12:42:14Z vivainio $"""
16 http://www.python.org/2.2.3/license.html"""
19 17
20 18 #*****************************************************************************
21 19 #
22 20 # This file is licensed under the PSF license.
23 21 #
24 22 # Copyright (C) 2001 Python Software Foundation, www.python.org
25 23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
26 24 #
27 25 #
28 26 #*****************************************************************************
29 27
30 from IPython import Release
31 __author__ = '%s <%s>' % Release.authors['Fernando']
32 __license__ = 'Python'
33
34 28 import bdb
35 29 import cmd
36 30 import linecache
37 31 import os
38 32 import sys
39 33
40 34 from IPython import PyColorize, ColorANSI, ipapi
41 35 from IPython.genutils import Term
42 36 from IPython.excolors import exception_colors
43 37
44 38 # See if we can use pydb.
45 39 has_pydb = False
46 40 prompt = 'ipdb> '
47 41 #We have to check this directly from sys.argv, config struct not yet available
48 42 if '-pydb' in sys.argv:
49 43 try:
50 44 import pydb
51 45 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
52 46 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
53 47 # better protect against it.
54 48 has_pydb = True
55 49 except ImportError:
56 50 print "Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available"
57 51
58 52 if has_pydb:
59 53 from pydb import Pdb as OldPdb
60 54 #print "Using pydb for %run -d and post-mortem" #dbg
61 55 prompt = 'ipydb> '
62 56 else:
63 57 from pdb import Pdb as OldPdb
64 58
65 59 # Allow the set_trace code to operate outside of an ipython instance, even if
66 60 # it does so with some limitations. The rest of this support is implemented in
67 61 # the Tracer constructor.
68 62 def BdbQuit_excepthook(et,ev,tb):
69 63 if et==bdb.BdbQuit:
70 64 print 'Exiting Debugger.'
71 65 else:
72 66 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
73 67
74 68 def BdbQuit_IPython_excepthook(self,et,ev,tb):
75 69 print 'Exiting Debugger.'
76 70
77 71 class Tracer(object):
78 72 """Class for local debugging, similar to pdb.set_trace.
79 73
80 74 Instances of this class, when called, behave like pdb.set_trace, but
81 75 providing IPython's enhanced capabilities.
82 76
83 77 This is implemented as a class which must be initialized in your own code
84 78 and not as a standalone function because we need to detect at runtime
85 79 whether IPython is already active or not. That detection is done in the
86 80 constructor, ensuring that this code plays nicely with a running IPython,
87 81 while functioning acceptably (though with limitations) if outside of it.
88 82 """
89 83
90 84 def __init__(self,colors=None):
91 85 """Create a local debugger instance.
92 86
93 87 :Parameters:
94 88
95 89 - `colors` (None): a string containing the name of the color scheme to
96 90 use, it must be one of IPython's valid color schemes. If not given, the
97 91 function will default to the current IPython scheme when running inside
98 92 IPython, and to 'NoColor' otherwise.
99 93
100 94 Usage example:
101 95
102 96 from IPython.Debugger import Tracer; debug_here = Tracer()
103 97
104 98 ... later in your code
105 99 debug_here() # -> will open up the debugger at that point.
106 100
107 101 Once the debugger activates, you can use all of its regular commands to
108 102 step through code, set breakpoints, etc. See the pdb documentation
109 103 from the Python standard library for usage details.
110 104 """
111 105
112 106 global __IPYTHON__
113 107 try:
114 108 __IPYTHON__
115 109 except NameError:
116 110 # Outside of ipython, we set our own exception hook manually
117 111 __IPYTHON__ = ipapi.get(True,False)
118 112 BdbQuit_excepthook.excepthook_ori = sys.excepthook
119 113 sys.excepthook = BdbQuit_excepthook
120 114 def_colors = 'NoColor'
121 115 try:
122 116 # Limited tab completion support
123 117 import rlcompleter,readline
124 118 readline.parse_and_bind('tab: complete')
125 119 except ImportError:
126 120 pass
127 121 else:
128 122 # In ipython, we use its custom exception handler mechanism
129 123 ip = ipapi.get()
130 124 def_colors = ip.options.colors
131 125 ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook)
132 126
133 127 if colors is None:
134 128 colors = def_colors
135 129 self.debugger = Pdb(colors)
136 130
137 131 def __call__(self):
138 132 """Starts an interactive debugger at the point where called.
139 133
140 134 This is similar to the pdb.set_trace() function from the std lib, but
141 135 using IPython's enhanced debugger."""
142 136
143 137 self.debugger.set_trace(sys._getframe().f_back)
144 138
145 139 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
146 140 """Make new_fn have old_fn's doc string. This is particularly useful
147 141 for the do_... commands that hook into the help system.
148 142 Adapted from from a comp.lang.python posting
149 143 by Duncan Booth."""
150 144 def wrapper(*args, **kw):
151 145 return new_fn(*args, **kw)
152 146 if old_fn.__doc__:
153 147 wrapper.__doc__ = old_fn.__doc__ + additional_text
154 148 return wrapper
155 149
156 150 def _file_lines(fname):
157 151 """Return the contents of a named file as a list of lines.
158 152
159 153 This function never raises an IOError exception: if the file can't be
160 154 read, it simply returns an empty list."""
161 155
162 156 try:
163 157 outfile = open(fname)
164 158 except IOError:
165 159 return []
166 160 else:
167 161 out = outfile.readlines()
168 162 outfile.close()
169 163 return out
170 164
171 165 class Pdb(OldPdb):
172 166 """Modified Pdb class, does not load readline."""
173 167
174 168 if sys.version[:3] >= '2.5' or has_pydb:
175 169 def __init__(self,color_scheme='NoColor',completekey=None,
176 170 stdin=None, stdout=None):
177 171
178 172 # Parent constructor:
179 173 if has_pydb and completekey is None:
180 174 OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)
181 175 else:
182 176 OldPdb.__init__(self,completekey,stdin,stdout)
183 177
184 178 self.prompt = prompt # The default prompt is '(Pdb)'
185 179
186 180 # IPython changes...
187 181 self.is_pydb = has_pydb
188 182
189 183 if self.is_pydb:
190 184
191 185 # iplib.py's ipalias seems to want pdb's checkline
192 186 # which located in pydb.fn
193 187 import pydb.fns
194 188 self.checkline = lambda filename, lineno: \
195 189 pydb.fns.checkline(self, filename, lineno)
196 190
197 191 self.curframe = None
198 192 self.do_restart = self.new_do_restart
199 193
200 194 self.old_all_completions = __IPYTHON__.Completer.all_completions
201 195 __IPYTHON__.Completer.all_completions=self.all_completions
202 196
203 197 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
204 198 OldPdb.do_list)
205 199 self.do_l = self.do_list
206 200 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
207 201 OldPdb.do_frame)
208 202
209 203 self.aliases = {}
210 204
211 205 # Create color table: we copy the default one from the traceback
212 206 # module and add a few attributes needed for debugging
213 207 self.color_scheme_table = exception_colors()
214 208
215 209 # shorthands
216 210 C = ColorANSI.TermColors
217 211 cst = self.color_scheme_table
218 212
219 213 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
220 214 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
221 215
222 216 cst['Linux'].colors.breakpoint_enabled = C.LightRed
223 217 cst['Linux'].colors.breakpoint_disabled = C.Red
224 218
225 219 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
226 220 cst['LightBG'].colors.breakpoint_disabled = C.Red
227 221
228 222 self.set_colors(color_scheme)
229 223
230 224 # Add a python parser so we can syntax highlight source while
231 225 # debugging.
232 226 self.parser = PyColorize.Parser()
233 227
234 228
235 229 else:
236 230 # Ugly hack: for Python 2.3-2.4, we can't call the parent constructor,
237 231 # because it binds readline and breaks tab-completion. This means we
238 232 # have to COPY the constructor here.
239 233 def __init__(self,color_scheme='NoColor'):
240 234 bdb.Bdb.__init__(self)
241 235 cmd.Cmd.__init__(self,completekey=None) # don't load readline
242 236 self.prompt = 'ipdb> ' # The default prompt is '(Pdb)'
243 237 self.aliases = {}
244 238
245 239 # These two lines are part of the py2.4 constructor, let's put them
246 240 # unconditionally here as they won't cause any problems in 2.3.
247 241 self.mainpyfile = ''
248 242 self._wait_for_mainpyfile = 0
249 243
250 244 # Read $HOME/.pdbrc and ./.pdbrc
251 245 try:
252 246 self.rcLines = _file_lines(os.path.join(os.environ['HOME'],
253 247 ".pdbrc"))
254 248 except KeyError:
255 249 self.rcLines = []
256 250 self.rcLines.extend(_file_lines(".pdbrc"))
257 251
258 252 # Create color table: we copy the default one from the traceback
259 253 # module and add a few attributes needed for debugging
260 254 self.color_scheme_table = exception_colors()
261 255
262 256 # shorthands
263 257 C = ColorANSI.TermColors
264 258 cst = self.color_scheme_table
265 259
266 260 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
267 261 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
268 262
269 263 cst['Linux'].colors.breakpoint_enabled = C.LightRed
270 264 cst['Linux'].colors.breakpoint_disabled = C.Red
271 265
272 266 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
273 267 cst['LightBG'].colors.breakpoint_disabled = C.Red
274 268
275 269 self.set_colors(color_scheme)
276 270
277 271 # Add a python parser so we can syntax highlight source while
278 272 # debugging.
279 273 self.parser = PyColorize.Parser()
280 274
281 275 def set_colors(self, scheme):
282 276 """Shorthand access to the color table scheme selector method."""
283 277 self.color_scheme_table.set_active_scheme(scheme)
284 278
285 279 def interaction(self, frame, traceback):
286 280 __IPYTHON__.set_completer_frame(frame)
287 281 OldPdb.interaction(self, frame, traceback)
288 282
289 283 def new_do_up(self, arg):
290 284 OldPdb.do_up(self, arg)
291 285 __IPYTHON__.set_completer_frame(self.curframe)
292 286 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
293 287
294 288 def new_do_down(self, arg):
295 289 OldPdb.do_down(self, arg)
296 290 __IPYTHON__.set_completer_frame(self.curframe)
297 291
298 292 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
299 293
300 294 def new_do_frame(self, arg):
301 295 OldPdb.do_frame(self, arg)
302 296 __IPYTHON__.set_completer_frame(self.curframe)
303 297
304 298 def new_do_quit(self, arg):
305 299
306 300 if hasattr(self, 'old_all_completions'):
307 301 __IPYTHON__.Completer.all_completions=self.old_all_completions
308 302
309 303
310 304 return OldPdb.do_quit(self, arg)
311 305
312 306 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
313 307
314 308 def new_do_restart(self, arg):
315 309 """Restart command. In the context of ipython this is exactly the same
316 310 thing as 'quit'."""
317 311 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
318 312 return self.do_quit(arg)
319 313
320 314 def postloop(self):
321 315 __IPYTHON__.set_completer_frame(None)
322 316
323 317 def print_stack_trace(self):
324 318 try:
325 319 for frame_lineno in self.stack:
326 320 self.print_stack_entry(frame_lineno, context = 5)
327 321 except KeyboardInterrupt:
328 322 pass
329 323
330 324 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
331 325 context = 3):
332 326 #frame, lineno = frame_lineno
333 327 print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
334 328
335 329 # vds: >>
336 330 frame, lineno = frame_lineno
337 331 filename = frame.f_code.co_filename
338 332 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
339 333 # vds: <<
340 334
341 335 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
342 336 import linecache, repr
343 337
344 338 ret = []
345 339
346 340 Colors = self.color_scheme_table.active_colors
347 341 ColorsNormal = Colors.Normal
348 342 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
349 343 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
350 344 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
351 345 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
352 346 ColorsNormal)
353 347
354 348 frame, lineno = frame_lineno
355 349
356 350 return_value = ''
357 351 if '__return__' in frame.f_locals:
358 352 rv = frame.f_locals['__return__']
359 353 #return_value += '->'
360 354 return_value += repr.repr(rv) + '\n'
361 355 ret.append(return_value)
362 356
363 357 #s = filename + '(' + `lineno` + ')'
364 358 filename = self.canonic(frame.f_code.co_filename)
365 359 link = tpl_link % filename
366 360
367 361 if frame.f_code.co_name:
368 362 func = frame.f_code.co_name
369 363 else:
370 364 func = "<lambda>"
371 365
372 366 call = ''
373 367 if func != '?':
374 368 if '__args__' in frame.f_locals:
375 369 args = repr.repr(frame.f_locals['__args__'])
376 370 else:
377 371 args = '()'
378 372 call = tpl_call % (func, args)
379 373
380 374 # The level info should be generated in the same format pdb uses, to
381 375 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
382 376 if frame is self.curframe:
383 377 ret.append('> ')
384 378 else:
385 379 ret.append(' ')
386 380 ret.append('%s(%s)%s\n' % (link,lineno,call))
387 381
388 382 start = lineno - 1 - context//2
389 383 lines = linecache.getlines(filename)
390 384 start = max(start, 0)
391 385 start = min(start, len(lines) - context)
392 386 lines = lines[start : start + context]
393 387
394 388 for i,line in enumerate(lines):
395 389 show_arrow = (start + 1 + i == lineno)
396 390 linetpl = (frame is self.curframe or show_arrow) \
397 391 and tpl_line_em \
398 392 or tpl_line
399 393 ret.append(self.__format_line(linetpl, filename,
400 394 start + 1 + i, line,
401 395 arrow = show_arrow) )
402 396
403 397 return ''.join(ret)
404 398
405 399 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
406 400 bp_mark = ""
407 401 bp_mark_color = ""
408 402
409 403 scheme = self.color_scheme_table.active_scheme_name
410 404 new_line, err = self.parser.format2(line, 'str', scheme)
411 405 if not err: line = new_line
412 406
413 407 bp = None
414 408 if lineno in self.get_file_breaks(filename):
415 409 bps = self.get_breaks(filename, lineno)
416 410 bp = bps[-1]
417 411
418 412 if bp:
419 413 Colors = self.color_scheme_table.active_colors
420 414 bp_mark = str(bp.number)
421 415 bp_mark_color = Colors.breakpoint_enabled
422 416 if not bp.enabled:
423 417 bp_mark_color = Colors.breakpoint_disabled
424 418
425 419 numbers_width = 7
426 420 if arrow:
427 421 # This is the line with the error
428 422 pad = numbers_width - len(str(lineno)) - len(bp_mark)
429 423 if pad >= 3:
430 424 marker = '-'*(pad-3) + '-> '
431 425 elif pad == 2:
432 426 marker = '> '
433 427 elif pad == 1:
434 428 marker = '>'
435 429 else:
436 430 marker = ''
437 431 num = '%s%s' % (marker, str(lineno))
438 432 line = tpl_line % (bp_mark_color + bp_mark, num, line)
439 433 else:
440 434 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
441 435 line = tpl_line % (bp_mark_color + bp_mark, num, line)
442 436
443 437 return line
444 438
445 439 def list_command_pydb(self, arg):
446 440 """List command to use if we have a newer pydb installed"""
447 441 filename, first, last = OldPdb.parse_list_cmd(self, arg)
448 442 if filename is not None:
449 443 self.print_list_lines(filename, first, last)
450 444
451 445 def print_list_lines(self, filename, first, last):
452 446 """The printing (as opposed to the parsing part of a 'list'
453 447 command."""
454 448 try:
455 449 Colors = self.color_scheme_table.active_colors
456 450 ColorsNormal = Colors.Normal
457 451 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
458 452 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
459 453 src = []
460 454 for lineno in range(first, last+1):
461 455 line = linecache.getline(filename, lineno)
462 456 if not line:
463 457 break
464 458
465 459 if lineno == self.curframe.f_lineno:
466 460 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
467 461 else:
468 462 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
469 463
470 464 src.append(line)
471 465 self.lineno = lineno
472 466
473 467 print >>Term.cout, ''.join(src)
474 468
475 469 except KeyboardInterrupt:
476 470 pass
477 471
478 472 def do_list(self, arg):
479 473 self.lastcmd = 'list'
480 474 last = None
481 475 if arg:
482 476 try:
483 477 x = eval(arg, {}, {})
484 478 if type(x) == type(()):
485 479 first, last = x
486 480 first = int(first)
487 481 last = int(last)
488 482 if last < first:
489 483 # Assume it's a count
490 484 last = first + last
491 485 else:
492 486 first = max(1, int(x) - 5)
493 487 except:
494 488 print '*** Error in argument:', `arg`
495 489 return
496 490 elif self.lineno is None:
497 491 first = max(1, self.curframe.f_lineno - 5)
498 492 else:
499 493 first = self.lineno + 1
500 494 if last is None:
501 495 last = first + 10
502 496 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
503 497
504 498 # vds: >>
505 499 lineno = first
506 500 filename = self.curframe.f_code.co_filename
507 501 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
508 502 # vds: <<
509 503
510 504 do_l = do_list
511 505
512 506 def do_pdef(self, arg):
513 507 """The debugger interface to magic_pdef"""
514 508 namespaces = [('Locals', self.curframe.f_locals),
515 509 ('Globals', self.curframe.f_globals)]
516 510 __IPYTHON__.magic_pdef(arg, namespaces=namespaces)
517 511
518 512 def do_pdoc(self, arg):
519 513 """The debugger interface to magic_pdoc"""
520 514 namespaces = [('Locals', self.curframe.f_locals),
521 515 ('Globals', self.curframe.f_globals)]
522 516 __IPYTHON__.magic_pdoc(arg, namespaces=namespaces)
523 517
524 518 def do_pinfo(self, arg):
525 519 """The debugger equivalant of ?obj"""
526 520 namespaces = [('Locals', self.curframe.f_locals),
527 521 ('Globals', self.curframe.f_globals)]
528 522 __IPYTHON__.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
@@ -1,259 +1,253 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Modified input prompt for executing files.
3 3
4 4 We define a special input line filter to allow typing lines which begin with
5 5 '~', '/' or '.'. If one of those strings is encountered, it is automatically
6 6 executed.
7
8 $Id: InterpreterExec.py 2724 2007-09-07 08:05:38Z fperez $"""
7 """
9 8
10 9 #*****************************************************************************
11 10 # Copyright (C) 2004 W.J. van der Laan <gnufnork@hetdigitalegat.nl>
12 11 # Copyright (C) 2004-2006 Fernando Perez <fperez@colorado.edu>
13 12 #
14 13 # Distributed under the terms of the BSD License. The full license is in
15 14 # the file COPYING, distributed as part of this software.
16 15 #*****************************************************************************
17 16
18 from IPython import Release
19 __author__ = 'W.J. van der Laan <gnufnork@hetdigitalegat.nl>, '\
20 '%s <%s>' % Release.authors['Fernando']
21 __license__ = Release.license
22
23 17 # TODO: deprecated
24 18 def prefilter_shell(self,line,continuation):
25 19 """Alternate prefilter, modified for shell-like functionality.
26 20
27 21 - Execute all lines beginning with '~', '/' or '.'
28 22 - $var=cmd <=> %sc var=cmd
29 23 - $$var=cmd <=> %sc -l var=cmd
30 24 """
31 25
32 26 if line:
33 27 l0 = line[0]
34 28 if l0 in '~/.':
35 29 return self._prefilter("!%s"%line,continuation)
36 30 elif l0=='$':
37 31 lrest = line[1:]
38 32 if lrest.startswith('$'):
39 33 # $$var=cmd <=> %sc -l var=cmd
40 34 return self._prefilter("%ssc -l %s" % (self.ESC_MAGIC,lrest[1:]),
41 35 continuation)
42 36 else:
43 37 # $var=cmd <=> %sc var=cmd
44 38 return self._prefilter("%ssc %s" % (self.ESC_MAGIC,lrest),
45 39 continuation)
46 40 else:
47 41 return self._prefilter(line,continuation)
48 42 else:
49 43 return self._prefilter(line,continuation)
50 44
51 45 # Rebind this to be the new IPython prefilter:
52 46 from IPython.iplib import InteractiveShell
53 47 InteractiveShell.prefilter = prefilter_shell
54 48 # Clean up the namespace.
55 49 del InteractiveShell,prefilter_shell
56 50
57 51 # Provide pysh and further shell-oriented services
58 52 import os,sys,shutil
59 53 from IPython.genutils import system,shell,getoutput,getoutputerror
60 54
61 55 # Short aliases for getting shell output as a string and a list
62 56 sout = getoutput
63 57 lout = lambda cmd: getoutput(cmd,split=1)
64 58
65 59 # Empty function, meant as a docstring holder so help(pysh) works.
66 60 def pysh():
67 61 """Pysh is a set of modules and extensions to IPython which make shell-like
68 62 usage with Python syntax more convenient. Keep in mind that pysh is NOT a
69 63 full-blown shell, so don't try to make it your /etc/passwd entry!
70 64
71 65 In particular, it has no job control, so if you type Ctrl-Z (under Unix),
72 66 you'll suspend pysh itself, not the process you just started.
73 67
74 68 Since pysh is really nothing but a customized IPython, you should
75 69 familiarize yourself with IPython's features. This brief help mainly
76 70 documents areas in which pysh differs from the normal IPython.
77 71
78 72 ALIASES
79 73 -------
80 74 All of your $PATH has been loaded as IPython aliases, so you should be
81 75 able to type any normal system command and have it executed. See %alias?
82 76 and %unalias? for details on the alias facilities.
83 77
84 78 SPECIAL SYNTAX
85 79 --------------
86 80 Any lines which begin with '~', '/' and '.' will be executed as shell
87 81 commands instead of as Python code. The special escapes below are also
88 82 recognized. !cmd is valid in single or multi-line input, all others are
89 83 only valid in single-line input:
90 84
91 85 !cmd - pass 'cmd' directly to the shell
92 86 !!cmd - execute 'cmd' and return output as a list (split on '\\n')
93 87 $var=cmd - capture output of cmd into var, as a string
94 88 $$var=cmd - capture output of cmd into var, as a list (split on '\\n')
95 89
96 90 The $/$$ syntaxes make Python variables from system output, which you can
97 91 later use for further scripting. The converse is also possible: when
98 92 executing an alias or calling to the system via !/!!, you can expand any
99 93 python variable or expression by prepending it with $. Full details of
100 94 the allowed syntax can be found in Python's PEP 215.
101 95
102 96 A few brief examples will illustrate these:
103 97
104 98 fperez[~/test]|3> !ls *s.py
105 99 scopes.py strings.py
106 100
107 101 ls is an internal alias, so there's no need to use !:
108 102 fperez[~/test]|4> ls *s.py
109 103 scopes.py* strings.py
110 104
111 105 !!ls will return the output into a Python variable:
112 106 fperez[~/test]|5> !!ls *s.py
113 107 <5> ['scopes.py', 'strings.py']
114 108 fperez[~/test]|6> print _5
115 109 ['scopes.py', 'strings.py']
116 110
117 111 $ and $$ allow direct capture to named variables:
118 112 fperez[~/test]|7> $astr = ls *s.py
119 113 fperez[~/test]|8> astr
120 114 <8> 'scopes.py\\nstrings.py'
121 115
122 116 fperez[~/test]|9> $$alist = ls *s.py
123 117 fperez[~/test]|10> alist
124 118 <10> ['scopes.py', 'strings.py']
125 119
126 120 alist is now a normal python list you can loop over. Using $ will expand
127 121 back the python values when alias calls are made:
128 122 fperez[~/test]|11> for f in alist:
129 123 |..> print 'file',f,
130 124 |..> wc -l $f
131 125 |..>
132 126 file scopes.py 13 scopes.py
133 127 file strings.py 4 strings.py
134 128
135 129 Note that you may need to protect your variables with braces if you want
136 130 to append strings to their names. To copy all files in alist to .bak
137 131 extensions, you must use:
138 132 fperez[~/test]|12> for f in alist:
139 133 |..> cp $f ${f}.bak
140 134
141 135 If you try using $f.bak, you'll get an AttributeError exception saying
142 136 that your string object doesn't have a .bak attribute. This is because
143 137 the $ expansion mechanism allows you to expand full Python expressions:
144 138 fperez[~/test]|13> echo "sys.platform is: $sys.platform"
145 139 sys.platform is: linux2
146 140
147 141 IPython's input history handling is still active, which allows you to
148 142 rerun a single block of multi-line input by simply using exec:
149 143 fperez[~/test]|14> $$alist = ls *.eps
150 144 fperez[~/test]|15> exec _i11
151 145 file image2.eps 921 image2.eps
152 146 file image.eps 921 image.eps
153 147
154 148 While these are new special-case syntaxes, they are designed to allow very
155 149 efficient use of the shell with minimal typing. At an interactive shell
156 150 prompt, conciseness of expression wins over readability.
157 151
158 152 USEFUL FUNCTIONS AND MODULES
159 153 ----------------------------
160 154 The os, sys and shutil modules from the Python standard library are
161 155 automatically loaded. Some additional functions, useful for shell usage,
162 156 are listed below. You can request more help about them with '?'.
163 157
164 158 shell - execute a command in the underlying system shell
165 159 system - like shell(), but return the exit status of the command
166 160 sout - capture the output of a command as a string
167 161 lout - capture the output of a command as a list (split on '\\n')
168 162 getoutputerror - capture (output,error) of a shell command
169 163
170 164 sout/lout are the functional equivalents of $/$$. They are provided to
171 165 allow you to capture system output in the middle of true python code,
172 166 function definitions, etc (where $ and $$ are invalid).
173 167
174 168 DIRECTORY MANAGEMENT
175 169 --------------------
176 170 Since each command passed by pysh to the underlying system is executed in
177 171 a subshell which exits immediately, you can NOT use !cd to navigate the
178 172 filesystem.
179 173
180 174 Pysh provides its own builtin '%cd' magic command to move in the
181 175 filesystem (the % is not required with automagic on). It also maintains a
182 176 list of visited directories (use %dhist to see it) and allows direct
183 177 switching to any of them. Type 'cd?' for more details.
184 178
185 179 %pushd, %popd and %dirs are provided for directory stack handling.
186 180
187 181 PROMPT CUSTOMIZATION
188 182 --------------------
189 183
190 184 The supplied ipythonrc-pysh profile comes with an example of a very
191 185 colored and detailed prompt, mainly to serve as an illustration. The
192 186 valid escape sequences, besides color names, are:
193 187
194 188 \\# - Prompt number.
195 189 \\D - Dots, as many as there are digits in \\# (so they align).
196 190 \\w - Current working directory (cwd).
197 191 \\W - Basename of current working directory.
198 192 \\XN - Where N=0..5. N terms of the cwd, with $HOME written as ~.
199 193 \\YN - Where N=0..5. Like XN, but if ~ is term N+1 it's also shown.
200 194 \\u - Username.
201 195 \\H - Full hostname.
202 196 \\h - Hostname up to first '.'
203 197 \\$ - Root symbol ($ or #).
204 198 \\t - Current time, in H:M:S format.
205 199 \\v - IPython release version.
206 200 \\n - Newline.
207 201 \\r - Carriage return.
208 202 \\\\ - An explicitly escaped '\\'.
209 203
210 204 You can configure your prompt colors using any ANSI color escape. Each
211 205 color escape sets the color for any subsequent text, until another escape
212 206 comes in and changes things. The valid color escapes are:
213 207
214 208 \\C_Black
215 209 \\C_Blue
216 210 \\C_Brown
217 211 \\C_Cyan
218 212 \\C_DarkGray
219 213 \\C_Green
220 214 \\C_LightBlue
221 215 \\C_LightCyan
222 216 \\C_LightGray
223 217 \\C_LightGreen
224 218 \\C_LightPurple
225 219 \\C_LightRed
226 220 \\C_Purple
227 221 \\C_Red
228 222 \\C_White
229 223 \\C_Yellow
230 224 \\C_Normal - Stop coloring, defaults to your terminal settings.
231 225 """
232 226 pass
233 227
234 228 # Configure a few things. Much of this is fairly hackish, since IPython
235 229 # doesn't really expose a clean API for it. Be careful if you start making
236 230 # many modifications here.
237 231
238 232
239 233 # Set the 'cd' command to quiet mode, a more shell-like behavior
240 234 __IPYTHON__.default_option('cd','-q')
241 235
242 236 # This is redundant, ipy_user_conf.py will determine this
243 237 # Load all of $PATH as aliases
244 238 __IPYTHON__.magic_rehashx()
245 239
246 240 # Remove %sc,%sx if present as aliases
247 241 __IPYTHON__.magic_unalias('sc')
248 242 __IPYTHON__.magic_unalias('sx')
249 243
250 244 # We need different criteria for line-splitting, so that aliases such as
251 245 # 'gnome-terminal' are interpreted as a single alias instead of variable
252 246 # 'gnome' minus variable 'terminal'.
253 247 import re
254 248 __IPYTHON__.line_split = re.compile(r'^([\s*,;/])'
255 249 r'([\?\w\.\-\+]+\w*\s*)'
256 250 r'(\(?.*$)')
257 251
258 252 # Namespace cleanup
259 253 del re
@@ -1,66 +1,63 b''
1 1 # -*- coding: utf-8 -*-
2 2 """ IPython extension: new prefilters for output grabbing
3 3
4 4 Provides
5 5
6 6 var = %magic blah blah
7 7
8 8 var = !ls
9
10 $Id: genutils.py 1077 2006-01-24 18:15:27Z vivainio $
11
12 9 """
13 10
14 11 import IPython.ipapi
15 12 from IPython.genutils import *
16 13
17 14 ip = IPython.ipapi.get()
18 15
19 16 import re
20 17
21 18 def hnd_magic(line,mo):
22 19 """ Handle a = %mymagic blah blah """
23 20 #cmd = genutils.make_quoted_expr(mo.group('syscmd'))
24 21 #mag = 'ipmagic
25 22 #return "%s = %s"
26 23 var = mo.group('varname')
27 24 cmd = mo.group('cmd')
28 25 expr = make_quoted_expr(cmd)
29 26 return itpl('$var = _ip.magic($expr)')
30 27
31 28 def hnd_syscmd(line,mo):
32 29 """ Handle a = !ls """
33 30 #cmd = genutils.make_quoted_expr(mo.group('syscmd'))
34 31 #mag = 'ipmagic
35 32 #return "%s = %s"
36 33 var = mo.group('varname')
37 34 cmd = mo.group('cmd')
38 35 expr = make_quoted_expr(itpl("sc -l =$cmd"))
39 36 return itpl('$var = _ip.magic($expr)')
40 37
41 38 def install_re_handler(pat, hnd):
42 39 ip.meta.re_prefilters.append((re.compile(pat), hnd))
43 40
44 41 def init_handlers():
45 42
46 43 ip.meta.re_prefilters = []
47 44
48 45 install_re_handler('(?P<varname>[\w\.]+)\s*=\s*%(?P<cmd>.*)',
49 46 hnd_magic
50 47 )
51 48
52 49 install_re_handler('(?P<varname>[\w\.]+)\s*=\s*!(?P<cmd>.*)',
53 50 hnd_syscmd
54 51 )
55 52
56 53 init_handlers()
57 54
58 55 def regex_prefilter_f(self,line):
59 56 for pat, handler in ip.meta.re_prefilters:
60 57 mo = pat.match(line)
61 58 if mo:
62 59 return handler(line,mo)
63 60
64 61 raise IPython.ipapi.TryNext
65 62
66 63 ip.set_hook('input_prefilter', regex_prefilter_f)
@@ -1,184 +1,182 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 %store magic for lightweight persistence.
4 4
5 5 Stores variables, aliases etc. in PickleShare database.
6
7 $Id: iplib.py 1107 2006-01-30 19:02:20Z vivainio $
8 6 """
9 7
10 8 import IPython.ipapi
11 9 from IPython.ipapi import UsageError
12 10 ip = IPython.ipapi.get()
13 11
14 12 import pickleshare
15 13
16 14 import inspect,pickle,os,sys,textwrap
17 15 from IPython.FakeModule import FakeModule
18 16
19 17 def restore_aliases(self):
20 18 ip = self.getapi()
21 19 staliases = ip.db.get('stored_aliases', {})
22 20 for k,v in staliases.items():
23 21 #print "restore alias",k,v # dbg
24 22 #self.alias_table[k] = v
25 23 ip.defalias(k,v)
26 24
27 25
28 26 def refresh_variables(ip):
29 27 db = ip.db
30 28 for key in db.keys('autorestore/*'):
31 29 # strip autorestore
32 30 justkey = os.path.basename(key)
33 31 try:
34 32 obj = db[key]
35 33 except KeyError:
36 34 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
37 35 print "The error was:",sys.exc_info()[0]
38 36 else:
39 37 #print "restored",justkey,"=",obj #dbg
40 38 ip.user_ns[justkey] = obj
41 39
42 40
43 41 def restore_dhist(ip):
44 42 db = ip.db
45 43 ip.user_ns['_dh'] = db.get('dhist',[])
46 44
47 45 def restore_data(self):
48 46 ip = self.getapi()
49 47 refresh_variables(ip)
50 48 restore_aliases(self)
51 49 restore_dhist(self)
52 50 raise IPython.ipapi.TryNext
53 51
54 52 ip.set_hook('late_startup_hook', restore_data)
55 53
56 54 def magic_store(self, parameter_s=''):
57 55 """Lightweight persistence for python variables.
58 56
59 57 Example:
60 58
61 59 ville@badger[~]|1> A = ['hello',10,'world']\\
62 60 ville@badger[~]|2> %store A\\
63 61 ville@badger[~]|3> Exit
64 62
65 63 (IPython session is closed and started again...)
66 64
67 65 ville@badger:~$ ipython -p pysh\\
68 66 ville@badger[~]|1> print A
69 67
70 68 ['hello', 10, 'world']
71 69
72 70 Usage:
73 71
74 72 %store - Show list of all variables and their current values\\
75 73 %store <var> - Store the *current* value of the variable to disk\\
76 74 %store -d <var> - Remove the variable and its value from storage\\
77 75 %store -z - Remove all variables from storage\\
78 76 %store -r - Refresh all variables from store (delete current vals)\\
79 77 %store foo >a.txt - Store value of foo to new file a.txt\\
80 78 %store foo >>a.txt - Append value of foo to file a.txt\\
81 79
82 80 It should be noted that if you change the value of a variable, you
83 81 need to %store it again if you want to persist the new value.
84 82
85 83 Note also that the variables will need to be pickleable; most basic
86 84 python types can be safely %stored.
87 85
88 86 Also aliases can be %store'd across sessions.
89 87 """
90 88
91 89 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
92 90 args = argsl.split(None,1)
93 91 ip = self.getapi()
94 92 db = ip.db
95 93 # delete
96 94 if opts.has_key('d'):
97 95 try:
98 96 todel = args[0]
99 97 except IndexError:
100 98 raise UsageError('You must provide the variable to forget')
101 99 else:
102 100 try:
103 101 del db['autorestore/' + todel]
104 102 except:
105 103 raise UsageError("Can't delete variable '%s'" % todel)
106 104 # reset
107 105 elif opts.has_key('z'):
108 106 for k in db.keys('autorestore/*'):
109 107 del db[k]
110 108
111 109 elif opts.has_key('r'):
112 110 refresh_variables(ip)
113 111
114 112
115 113 # run without arguments -> list variables & values
116 114 elif not args:
117 115 vars = self.db.keys('autorestore/*')
118 116 vars.sort()
119 117 if vars:
120 118 size = max(map(len,vars))
121 119 else:
122 120 size = 0
123 121
124 122 print 'Stored variables and their in-db values:'
125 123 fmt = '%-'+str(size)+'s -> %s'
126 124 get = db.get
127 125 for var in vars:
128 126 justkey = os.path.basename(var)
129 127 # print 30 first characters from every var
130 128 print fmt % (justkey,repr(get(var,'<unavailable>'))[:50])
131 129
132 130 # default action - store the variable
133 131 else:
134 132 # %store foo >file.txt or >>file.txt
135 133 if len(args) > 1 and args[1].startswith('>'):
136 134 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
137 135 if args[1].startswith('>>'):
138 136 fil = open(fnam,'a')
139 137 else:
140 138 fil = open(fnam,'w')
141 139 obj = ip.ev(args[0])
142 140 print "Writing '%s' (%s) to file '%s'." % (args[0],
143 141 obj.__class__.__name__, fnam)
144 142
145 143
146 144 if not isinstance (obj,basestring):
147 145 from pprint import pprint
148 146 pprint(obj,fil)
149 147 else:
150 148 fil.write(obj)
151 149 if not obj.endswith('\n'):
152 150 fil.write('\n')
153 151
154 152 fil.close()
155 153 return
156 154
157 155 # %store foo
158 156 try:
159 157 obj = ip.user_ns[args[0]]
160 158 except KeyError:
161 159 # it might be an alias
162 160 if args[0] in self.alias_table:
163 161 staliases = db.get('stored_aliases',{})
164 162 staliases[ args[0] ] = self.alias_table[ args[0] ]
165 163 db['stored_aliases'] = staliases
166 164 print "Alias stored:", args[0], self.alias_table[ args[0] ]
167 165 return
168 166 else:
169 167 raise UsageError("Unknown variable '%s'" % args[0])
170 168
171 169 else:
172 170 if isinstance(inspect.getmodule(obj), FakeModule):
173 171 print textwrap.dedent("""\
174 172 Warning:%s is %s
175 173 Proper storage of interactively declared classes (or instances
176 174 of those classes) is not possible! Only instances
177 175 of classes in real modules on file system can be %%store'd.
178 176 """ % (args[0], obj) )
179 177 return
180 178 #pickled = pickle.dumps(obj)
181 179 self.db[ 'autorestore/' + args[0] ] = obj
182 180 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
183 181
184 182 ip.expose_magic('store',magic_store)
@@ -1,43 +1,42 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Class which mimics a module.
4 4
5 5 Needed to allow pickle to correctly resolve namespaces during IPython
6 6 sessions.
7
8 $Id: FakeModule.py 2754 2007-09-09 10:16:59Z fperez $"""
7 """
9 8
10 9 #*****************************************************************************
11 10 # Copyright (C) 2002-2004 Fernando Perez. <fperez@colorado.edu>
12 11 #
13 12 # Distributed under the terms of the BSD License. The full license is in
14 13 # the file COPYING, distributed as part of this software.
15 14 #*****************************************************************************
16 15
17 16 import types
18 17
19 18 class FakeModule(types.ModuleType):
20 19 """Simple class with attribute access to fake a module.
21 20
22 21 This is not meant to replace a module, but to allow inserting a fake
23 22 module in sys.modules so that systems which rely on run-time module
24 23 importing (like shelve and pickle) work correctly in interactive IPython
25 24 sessions.
26 25
27 26 Do NOT use this code for anything other than this IPython private hack."""
28 27
29 28 def __init__(self,adict=None):
30 29
31 30 # tmp to force __dict__ instance creation, else self.__dict__ fails
32 31 self.__iptmp = None
33 32
34 33 # It seems pydoc (and perhaps others) needs any module instance to
35 34 # implement a __nonzero__ method, so we add it if missing:
36 35 self.__dict__.setdefault('__nonzero__',lambda : True)
37 36 self.__dict__.setdefault('__file__',__file__)
38 37
39 38 # cleanup our temp trick
40 39 del self.__iptmp
41 40
42 41 if adict is not None:
43 42 self.__dict__.update(adict)
@@ -1,666 +1,665 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Improved replacement for the Gnuplot.Gnuplot class.
3 3
4 4 This module imports Gnuplot and replaces some of its functionality with
5 5 improved versions. They add better handling of arrays for plotting and more
6 6 convenient PostScript generation, plus some fixes for hardcopy().
7 7
8 8 It also adds a convenient plot2 method for plotting dictionaries and
9 9 lists/tuples of arrays.
10 10
11 11 This module is meant to be used as a drop-in replacement to the original
12 12 Gnuplot, so it should be safe to do:
13 13
14 14 import IPython.Gnuplot2 as Gnuplot
15
16 $Id: Gnuplot2.py 1210 2006-03-13 01:19:31Z fperez $"""
15 """
17 16
18 17 import cStringIO
19 18 import os
20 19 import string
21 20 import sys
22 21 import tempfile
23 22 import time
24 23 import types
25 24
26 25 import Gnuplot as Gnuplot_ori
27 26 import Numeric
28 27
29 28 from IPython.genutils import popkey,xsys
30 29
31 30 # needed by hardcopy():
32 31 gp = Gnuplot_ori.gp
33 32
34 33 # Patch for Gnuplot.py 1.6 compatibility.
35 34 # Thanks to Hayden Callow <h.callow@elec.canterbury.ac.nz>
36 35 try:
37 36 OptionException = Gnuplot_ori.PlotItems.OptionException
38 37 except AttributeError:
39 38 OptionException = Gnuplot_ori.Errors.OptionError
40 39
41 40 # exhibit a similar interface to Gnuplot so it can be somewhat drop-in
42 41 Data = Gnuplot_ori.Data
43 42 Func = Gnuplot_ori.Func
44 43 GridData = Gnuplot_ori.GridData
45 44 PlotItem = Gnuplot_ori.PlotItem
46 45 PlotItems = Gnuplot_ori.PlotItems
47 46
48 47 # Modify some of Gnuplot's functions with improved versions (or bugfixed, in
49 48 # hardcopy's case). In order to preserve the docstrings at runtime, I've
50 49 # copied them from the original code.
51 50
52 51 # After some significant changes in v 1.7 of Gnuplot.py, we need to do a bit
53 52 # of version checking.
54 53
55 54 if Gnuplot_ori.__version__ <= '1.6':
56 55 _BaseFileItem = PlotItems.File
57 56 _BaseTempFileItem = PlotItems.TempFile
58 57
59 58 # Fix the File class to add the 'index' option for Gnuplot versions < 1.7
60 59 class File(_BaseFileItem):
61 60
62 61 _option_list = _BaseFileItem._option_list.copy()
63 62 _option_list.update({
64 63 'index' : lambda self, index: self.set_option_index(index),
65 64 })
66 65
67 66 # A new initializer is needed b/c we want to add a modified
68 67 # _option_sequence list which includes 'index' in the right place.
69 68 def __init__(self,*args,**kw):
70 69 self._option_sequence = ['binary', 'index', 'using', 'smooth', 'axes',
71 70 'title', 'with']
72 71
73 72 _BaseFileItem.__init__(self,*args,**kw)
74 73
75 74 # Let's fix the constructor docstring
76 75 __newdoc = \
77 76 """Additional Keyword arguments added by IPython:
78 77
79 78 'index=<int>' -- similar to the `index` keyword in Gnuplot.
80 79 This allows only some of the datasets in a file to be
81 80 plotted. Datasets within a file are assumed to be separated
82 81 by _pairs_ of blank lines, and the first one is numbered as
83 82 0 (similar to C/Python usage)."""
84 83 __init__.__doc__ = PlotItems.File.__init__.__doc__ + __newdoc
85 84
86 85 def set_option_index(self, index):
87 86 if index is None:
88 87 self.clear_option('index')
89 88 elif type(index) in [type(''), type(1)]:
90 89 self._options['index'] = (index, 'index %s' % index)
91 90 elif type(index) is type(()):
92 91 self._options['index'] = (index,'index %s' %
93 92 string.join(map(repr, index), ':'))
94 93 else:
95 94 raise OptionException('index=%s' % (index,))
96 95
97 96 # We need a FileClass with a different name from 'File', which is a
98 97 # factory function in 1.7, so that our String class can subclass FileClass
99 98 # in any version.
100 99 _FileClass = File
101 100
102 101 elif Gnuplot_ori.__version__ =='1.7':
103 102 _FileClass = _BaseFileItem = PlotItems._FileItem
104 103 _BaseTempFileItem = PlotItems._TempFileItem
105 104 File = PlotItems.File
106 105
107 106 else: # changes in the newer version (svn as of March'06)
108 107 _FileClass = _BaseFileItem = PlotItems._FileItem
109 108 _BaseTempFileItem = PlotItems._NewFileItem
110 109 File = PlotItems.File
111 110
112 111
113 112 # Now, we can add our generic code which is version independent
114 113
115 114 # First some useful utilities
116 115 def eps_fix_bbox(fname):
117 116 """Fix the bounding box of an eps file by running ps2eps on it.
118 117
119 118 If its name ends in .eps, the original file is removed.
120 119
121 120 This is particularly useful for plots made by Gnuplot with square aspect
122 121 ratio: there is a bug in Gnuplot which makes it generate a bounding box
123 122 which is far wider than the actual plot.
124 123
125 124 This function assumes that ps2eps is installed in your system."""
126 125
127 126 # note: ps2ps and eps2eps do NOT work, ONLY ps2eps works correctly. The
128 127 # others make output with bitmapped fonts, which looks horrible.
129 128 print 'Fixing eps file: <%s>' % fname
130 129 xsys('ps2eps -f -q -l %s' % fname)
131 130 if fname.endswith('.eps'):
132 131 os.rename(fname+'.eps',fname)
133 132
134 133 def is_list1d(x,containers = [types.ListType,types.TupleType]):
135 134 """Returns true if x appears to be a 1d list/tuple/array.
136 135
137 136 The heuristics are: identify Numeric arrays, or lists/tuples whose first
138 137 element is not itself a list/tuple. This way zipped lists should work like
139 138 the original Gnuplot. There's no inexpensive way to know if a list doesn't
140 139 have a composite object after its first element, so that kind of input
141 140 will produce an error. But it should work well in most cases.
142 141 """
143 142 x_type = type(x)
144 143
145 144 return x_type == Numeric.ArrayType and len(x.shape)==1 or \
146 145 (x_type in containers and
147 146 type(x[0]) not in containers + [Numeric.ArrayType])
148 147
149 148 def zip_items(items,titles=None):
150 149 """zip together neighboring 1-d arrays, and zip standalone ones
151 150 with their index. Leave other plot items alone."""
152 151
153 152 class StandaloneItem(Exception): pass
154 153
155 154 def get_titles(titles):
156 155 """Return the next title and the input titles array.
157 156
158 157 The input array may be changed to None when no titles are left to
159 158 prevent extra unnecessary calls to this function."""
160 159
161 160 try:
162 161 title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope
163 162 except IndexError:
164 163 titles = None # so we don't enter again
165 164 title = None
166 165 else:
167 166 tit_ct[0] += 1
168 167 return title,titles
169 168
170 169 new_items = []
171 170
172 171 if titles:
173 172 # Initialize counter. It was put in a list as a hack to allow the
174 173 # nested get_titles to modify it without raising a NameError.
175 174 tit_ct = [0]
176 175
177 176 n = 0 # this loop needs to be done by hand
178 177 while n < len(items):
179 178 item = items[n]
180 179 try:
181 180 if is_list1d(item):
182 181 if n==len(items)-1: # last in list
183 182 raise StandaloneItem
184 183 else: # check the next item and zip together if needed
185 184 next_item = items[n+1]
186 185 if next_item is None:
187 186 n += 1
188 187 raise StandaloneItem
189 188 elif is_list1d(next_item):
190 189 # this would be best done with an iterator
191 190 if titles:
192 191 title,titles = get_titles(titles)
193 192 else:
194 193 title = None
195 194 new_items.append(Data(zip(item,next_item),
196 195 title=title))
197 196 n += 1 # avoid double-inclusion of next item
198 197 else: # can't zip with next, zip with own index list
199 198 raise StandaloneItem
200 199 else: # not 1-d array
201 200 new_items.append(item)
202 201 except StandaloneItem:
203 202 if titles:
204 203 title,titles = get_titles(titles)
205 204 else:
206 205 title = None
207 206 new_items.append(Data(zip(range(len(item)),item),title=title))
208 207 except AttributeError:
209 208 new_items.append(item)
210 209 n+=1
211 210
212 211 return new_items
213 212
214 213 # And some classes with enhanced functionality.
215 214 class String(_FileClass):
216 215 """Make a PlotItem from data in a string with the same format as a File.
217 216
218 217 This allows writing data directly inside python scripts using the exact
219 218 same format and manipulation options which would be used for external
220 219 files."""
221 220
222 221 def __init__(self, data_str, **keyw):
223 222 """Construct a String object.
224 223
225 224 <data_str> is a string formatted exactly like a valid Gnuplot data
226 225 file would be. All options from the File constructor are valid here.
227 226
228 227 Warning: when used for interactive plotting in scripts which exit
229 228 immediately, you may get an error because the temporary file used to
230 229 hold the string data was deleted before Gnuplot had a chance to see
231 230 it. You can work around this problem by putting a raw_input() call at
232 231 the end of the script.
233 232
234 233 This problem does not appear when generating PostScript output, only
235 234 with Gnuplot windows."""
236 235
237 236 self.tmpfile = _BaseTempFileItem()
238 237 tmpfile = file(self.tmpfile.filename,'w')
239 238 tmpfile.write(data_str)
240 239 _BaseFileItem.__init__(self,self.tmpfile,**keyw)
241 240
242 241
243 242 class Gnuplot(Gnuplot_ori.Gnuplot):
244 243 """Improved Gnuplot class.
245 244
246 245 Enhancements: better plot,replot and hardcopy methods. New methods for
247 246 quick range setting.
248 247 """
249 248
250 249 def xrange(self,min='*',max='*'):
251 250 """Set xrange. If min/max is omitted, it is set to '*' (auto).
252 251
253 252 Note that this is different from the regular Gnuplot behavior, where
254 253 an unspecified limit means no change. Here any unspecified limit is
255 254 set to autoscaling, allowing these functions to be used for full
256 255 autoscaling when called with no arguments.
257 256
258 257 To preserve one limit's current value while changing the other, an
259 258 explicit '' argument must be given as the limit to be kept.
260 259
261 260 Similar functions exist for [y{2}z{2}rtuv]range."""
262 261
263 262 self('set xrange [%s:%s]' % (min,max))
264 263
265 264 def yrange(self,min='*',max='*'):
266 265 self('set yrange [%s:%s]' % (min,max))
267 266
268 267 def zrange(self,min='*',max='*'):
269 268 self('set zrange [%s:%s]' % (min,max))
270 269
271 270 def x2range(self,min='*',max='*'):
272 271 self('set xrange [%s:%s]' % (min,max))
273 272
274 273 def y2range(self,min='*',max='*'):
275 274 self('set yrange [%s:%s]' % (min,max))
276 275
277 276 def z2range(self,min='*',max='*'):
278 277 self('set zrange [%s:%s]' % (min,max))
279 278
280 279 def rrange(self,min='*',max='*'):
281 280 self('set rrange [%s:%s]' % (min,max))
282 281
283 282 def trange(self,min='*',max='*'):
284 283 self('set trange [%s:%s]' % (min,max))
285 284
286 285 def urange(self,min='*',max='*'):
287 286 self('set urange [%s:%s]' % (min,max))
288 287
289 288 def vrange(self,min='*',max='*'):
290 289 self('set vrange [%s:%s]' % (min,max))
291 290
292 291 def set_ps(self,option):
293 292 """Set an option for the PostScript terminal and reset default term."""
294 293
295 294 self('set terminal postscript %s ' % option)
296 295 self('set terminal %s' % gp.GnuplotOpts.default_term)
297 296
298 297 def __plot_ps(self, plot_method,*items, **keyw):
299 298 """Wrapper for plot/splot/replot, with processing of hardcopy options.
300 299
301 300 For internal use only."""
302 301
303 302 # Filter out PostScript options which will crash the normal plot/replot
304 303 psargs = {'filename':None,
305 304 'mode':None,
306 305 'eps':None,
307 306 'enhanced':None,
308 307 'color':None,
309 308 'solid':None,
310 309 'duplexing':None,
311 310 'fontname':None,
312 311 'fontsize':None,
313 312 'debug':0 }
314 313
315 314 for k in psargs.keys():
316 315 if keyw.has_key(k):
317 316 psargs[k] = keyw[k]
318 317 del keyw[k]
319 318
320 319 # Filter out other options the original plot doesn't know
321 320 hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None)
322 321 titles = popkey(keyw,'titles',0)
323 322
324 323 # the filename keyword should control hardcopy generation, this is an
325 324 # override switch only which needs to be explicitly set to zero
326 325 if hardcopy:
327 326 if psargs['filename'] is None:
328 327 raise ValueError, \
329 328 'If you request hardcopy, you must give a filename.'
330 329
331 330 # set null output so nothing goes to screen. hardcopy() restores output
332 331 self('set term dumb')
333 332 # I don't know how to prevent screen output in Windows
334 333 if os.name == 'posix':
335 334 self('set output "/dev/null"')
336 335
337 336 new_items = zip_items(items,titles)
338 337 # plot_method is either plot or replot from the original Gnuplot class:
339 338 plot_method(self,*new_items,**keyw)
340 339
341 340 # Do hardcopy if requested
342 341 if hardcopy:
343 342 if psargs['filename'].endswith('.eps'):
344 343 psargs['eps'] = 1
345 344 self.hardcopy(**psargs)
346 345
347 346 def plot(self, *items, **keyw):
348 347 """Draw a new plot.
349 348
350 349 Clear the current plot and create a new 2-d plot containing
351 350 the specified items. Each arguments should be of the
352 351 following types:
353 352
354 353 'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most
355 354 flexible way to call plot because the PlotItems can
356 355 contain suboptions. Moreover, PlotItems can be saved to
357 356 variables so that their lifetime is longer than one plot
358 357 command; thus they can be replotted with minimal overhead.
359 358
360 359 'string' (e.g., 'sin(x)') -- The string is interpreted as
361 360 'Func(string)' (a function that is computed by gnuplot).
362 361
363 362 Anything else -- The object, which should be convertible to an
364 363 array, is passed to the 'Data' constructor, and thus
365 364 plotted as data. If the conversion fails, an exception is
366 365 raised.
367 366
368 367
369 368 This is a modified version of plot(). Compared to the original in
370 369 Gnuplot.py, this version has several enhancements, listed below.
371 370
372 371
373 372 Modifications to the input arguments
374 373 ------------------------------------
375 374
376 375 (1-d array means Numeric array, list or tuple):
377 376
378 377 (i) Any 1-d array which is NOT followed by another 1-d array, is
379 378 automatically zipped with range(len(array_1d)). Typing g.plot(y) will
380 379 plot y against its indices.
381 380
382 381 (ii) If two 1-d arrays are contiguous in the argument list, they are
383 382 automatically zipped together. So g.plot(x,y) plots y vs. x, and
384 383 g.plot(x1,y1,x2,y2) plots y1 vs. x1 and y2 vs. x2.
385 384
386 385 (iii) Any 1-d array which is followed by None is automatically zipped
387 386 with range(len(array_1d)). In this form, typing g.plot(y1,None,y2)
388 387 will plot both y1 and y2 against their respective indices (and NOT
389 388 versus one another). The None prevents zipping y1 and y2 together, and
390 389 since y2 is unpaired it is automatically zipped to its indices by (i)
391 390
392 391 (iv) Any other arguments which don't match these cases are left alone and
393 392 passed to the code below.
394 393
395 394 For lists or tuples, the heuristics used to determine whether they are
396 395 in fact 1-d is fairly simplistic: their first element is checked, and
397 396 if it is not a list or tuple itself, it is assumed that the whole
398 397 object is one-dimensional.
399 398
400 399 An additional optional keyword 'titles' has been added: it must be a
401 400 list of strings to be used as labels for the individual plots which
402 401 are NOT PlotItem objects (since those objects carry their own labels
403 402 within).
404 403
405 404
406 405 PostScript generation
407 406 ---------------------
408 407
409 408 This version of plot() also handles automatically the production of
410 409 PostScript output. The main options are (given as keyword arguments):
411 410
412 411 - filename: a string, typically ending in .eps. If given, the plot is
413 412 sent to this file in PostScript format.
414 413
415 414 - hardcopy: this can be set to 0 to override 'filename'. It does not
416 415 need to be given to produce PostScript, its purpose is to allow
417 416 switching PostScript output off globally in scripts without having to
418 417 manually change 'filename' values in multiple calls.
419 418
420 419 All other keywords accepted by Gnuplot.hardcopy() are transparently
421 420 passed, and safely ignored if output is sent to the screen instead of
422 421 PostScript.
423 422
424 423 For example:
425 424
426 425 In [1]: x=frange(0,2*pi,npts=100)
427 426
428 427 Generate a plot in file 'sin.eps':
429 428
430 429 In [2]: plot(x,sin(x),filename = 'sin.eps')
431 430
432 431 Plot to screen instead, without having to change the filename:
433 432
434 433 In [3]: plot(x,sin(x),filename = 'sin.eps',hardcopy=0)
435 434
436 435 Pass the 'color=0' option to hardcopy for monochrome output:
437 436
438 437 In [4]: plot(x,sin(x),filename = 'sin.eps',color=0)
439 438
440 439 PostScript generation through plot() is useful mainly for scripting
441 440 uses where you are not interested in interactive plotting. For
442 441 interactive use, the hardcopy() function is typically more convenient:
443 442
444 443 In [5]: plot(x,sin(x))
445 444
446 445 In [6]: hardcopy('sin.eps') """
447 446
448 447 self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw)
449 448
450 449 def plot2(self,arg,**kw):
451 450 """Plot the entries of a dictionary or a list/tuple of arrays.
452 451
453 452 This simple utility calls plot() with a list of Gnuplot.Data objects
454 453 constructed either from the values of the input dictionary, or the entries
455 454 in it if it is a tuple or list. Each item gets labeled with the key/index
456 455 in the Gnuplot legend.
457 456
458 457 Each item is plotted by zipping it with a list of its indices.
459 458
460 459 Any keywords are passed directly to plot()."""
461 460
462 461 if hasattr(arg,'keys'):
463 462 keys = arg.keys()
464 463 keys.sort()
465 464 else:
466 465 keys = range(len(arg))
467 466
468 467 pitems = [Data(zip(range(len(arg[k])),arg[k]),title=`k`) for k in keys]
469 468 self.plot(*pitems,**kw)
470 469
471 470 def splot(self, *items, **keyw):
472 471 """Draw a new three-dimensional plot.
473 472
474 473 Clear the current plot and create a new 3-d plot containing
475 474 the specified items. Arguments can be of the following types:
476 475
477 476 'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This
478 477 is the most flexible way to call plot because the
479 478 PlotItems can contain suboptions. Moreover, PlotItems can
480 479 be saved to variables so that their lifetime is longer
481 480 than one plot command--thus they can be replotted with
482 481 minimal overhead.
483 482
484 483 'string' (e.g., 'sin(x*y)') -- The string is interpreted as a
485 484 'Func()' (a function that is computed by gnuplot).
486 485
487 486 Anything else -- The object is converted to a Data() item, and
488 487 thus plotted as data. Note that each data point should
489 488 normally have at least three values associated with it
490 489 (i.e., x, y, and z). If the conversion fails, an
491 490 exception is raised.
492 491
493 492 This is a modified version of splot(). Compared to the original in
494 493 Gnuplot.py, this version has several enhancements, listed in the
495 494 plot() documentation.
496 495 """
497 496
498 497 self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw)
499 498
500 499 def replot(self, *items, **keyw):
501 500 """Replot the data, possibly adding new 'PlotItem's.
502 501
503 502 Replot the existing graph, using the items in the current
504 503 itemlist. If arguments are specified, they are interpreted as
505 504 additional items to be plotted alongside the existing items on
506 505 the same graph. See 'plot' for details.
507 506
508 507 If you want to replot to a postscript file, you MUST give the
509 508 'filename' keyword argument in each call to replot. The Gnuplot python
510 509 interface has no way of knowing that your previous call to
511 510 Gnuplot.plot() was meant for PostScript output."""
512 511
513 512 self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw)
514 513
515 514 # The original hardcopy has a bug. See fix at the end. The rest of the code
516 515 # was lifted verbatim from the original, so that people using IPython get the
517 516 # benefits without having to manually patch Gnuplot.py
518 517 def hardcopy(self, filename=None,
519 518 mode=None,
520 519 eps=None,
521 520 enhanced=None,
522 521 color=None,
523 522 solid=None,
524 523 duplexing=None,
525 524 fontname=None,
526 525 fontsize=None,
527 526 debug = 0,
528 527 ):
529 528 """Create a hardcopy of the current plot.
530 529
531 530 Create a postscript hardcopy of the current plot to the
532 531 default printer (if configured) or to the specified filename.
533 532
534 533 Note that gnuplot remembers the postscript suboptions across
535 534 terminal changes. Therefore if you set, for example, color=1
536 535 for one hardcopy then the next hardcopy will also be color
537 536 unless you explicitly choose color=0. Alternately you can
538 537 force all of the options to their defaults by setting
539 538 mode='default'. I consider this to be a bug in gnuplot.
540 539
541 540 Keyword arguments:
542 541
543 542 'filename=<string>' -- if a filename is specified, save the
544 543 output in that file; otherwise print it immediately
545 544 using the 'default_lpr' configuration option. If the
546 545 filename ends in '.eps', EPS mode is automatically
547 546 selected (like manually specifying eps=1 or mode='eps').
548 547
549 548 'mode=<string>' -- set the postscript submode ('landscape',
550 549 'portrait', 'eps', or 'default'). The default is
551 550 to leave this option unspecified.
552 551
553 552 'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to
554 553 generate encapsulated postscript.
555 554
556 555 'enhanced=<bool>' -- if set (the default), then generate
557 556 enhanced postscript, which allows extra features like
558 557 font-switching, superscripts, and subscripts in axis
559 558 labels. (Some old gnuplot versions do not support
560 559 enhanced postscript; if this is the case set
561 560 gp.GnuplotOpts.prefer_enhanced_postscript=None.)
562 561
563 562 'color=<bool>' -- if set, create a plot with color. Default
564 563 is to leave this option unchanged.
565 564
566 565 'solid=<bool>' -- if set, force lines to be solid (i.e., not
567 566 dashed).
568 567
569 568 'duplexing=<string>' -- set duplexing option ('defaultplex',
570 569 'simplex', or 'duplex'). Only request double-sided
571 570 printing if your printer can handle it. Actually this
572 571 option is probably meaningless since hardcopy() can only
573 572 print a single plot at a time.
574 573
575 574 'fontname=<string>' -- set the default font to <string>,
576 575 which must be a valid postscript font. The default is
577 576 to leave this option unspecified.
578 577
579 578 'fontsize=<double>' -- set the default font size, in
580 579 postscript points.
581 580
582 581 'debug=<bool>' -- print extra debugging information (useful if
583 582 your PostScript files are misteriously not being created).
584 583 """
585 584
586 585 if filename is None:
587 586 assert gp.GnuplotOpts.default_lpr is not None, \
588 587 OptionException('default_lpr is not set, so you can only '
589 588 'print to a file.')
590 589 filename = gp.GnuplotOpts.default_lpr
591 590 lpr_output = 1
592 591 else:
593 592 if filename.endswith('.eps'):
594 593 eps = 1
595 594 lpr_output = 0
596 595
597 596 # Be careful processing the options. If the user didn't
598 597 # request an option explicitly, do not specify it on the 'set
599 598 # terminal' line (don't even specify the default value for the
600 599 # option). This is to avoid confusing older versions of
601 600 # gnuplot that do not support all of these options. The
602 601 # exception is 'enhanced', which is just too useful to have to
603 602 # specify each time!
604 603
605 604 setterm = ['set', 'terminal', 'postscript']
606 605 if eps:
607 606 assert mode is None or mode=='eps', \
608 607 OptionException('eps option and mode are incompatible')
609 608 setterm.append('eps')
610 609 else:
611 610 if mode is not None:
612 611 assert mode in ['landscape', 'portrait', 'eps', 'default'], \
613 612 OptionException('illegal mode "%s"' % mode)
614 613 setterm.append(mode)
615 614 if enhanced is None:
616 615 enhanced = gp.GnuplotOpts.prefer_enhanced_postscript
617 616 if enhanced is not None:
618 617 if enhanced: setterm.append('enhanced')
619 618 else: setterm.append('noenhanced')
620 619 if color is not None:
621 620 if color: setterm.append('color')
622 621 else: setterm.append('monochrome')
623 622 if solid is not None:
624 623 if solid: setterm.append('solid')
625 624 else: setterm.append('dashed')
626 625 if duplexing is not None:
627 626 assert duplexing in ['defaultplex', 'simplex', 'duplex'], \
628 627 OptionException('illegal duplexing mode "%s"' % duplexing)
629 628 setterm.append(duplexing)
630 629 if fontname is not None:
631 630 setterm.append('"%s"' % fontname)
632 631 if fontsize is not None:
633 632 setterm.append('%s' % fontsize)
634 633
635 634 self(string.join(setterm))
636 635 self.set_string('output', filename)
637 636 # replot the current figure (to the printer):
638 637 self.refresh()
639 638
640 639 # fperez. Ugly kludge: often for some reason the file is NOT created
641 640 # and we must reissue the creation commands. I have no idea why!
642 641 if not lpr_output:
643 642 #print 'Hardcopy <%s>' % filename # dbg
644 643 maxtries = 20
645 644 delay = 0.1 # delay (in seconds) between print attempts
646 645 for i in range(maxtries):
647 646 time.sleep(0.05) # safety, very small delay
648 647 if os.path.isfile(filename):
649 648 if debug:
650 649 print 'Hardcopy to file <%s> success at attempt #%s.' \
651 650 % (filename,i+1)
652 651 break
653 652 time.sleep(delay)
654 653 # try again, issue all commands just in case
655 654 self(string.join(setterm))
656 655 self.set_string('output', filename)
657 656 self.refresh()
658 657 if not os.path.isfile(filename):
659 658 print >> sys.stderr,'ERROR: Tried %s times and failed to '\
660 659 'create hardcopy file `%s`' % (maxtries,filename)
661 660
662 661 # reset the terminal to its `default' setting:
663 662 self('set terminal %s' % gp.GnuplotOpts.default_term)
664 663 self.set_string('output')
665 664
666 665 #********************** End of file <Gnuplot2.py> ************************
@@ -1,148 +1,147 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Interactive functions and magic functions for Gnuplot usage.
3 3
4 4 This requires the Gnuplot.py module for interfacing python with Gnuplot, which
5 5 can be downloaded from:
6 6
7 7 http://gnuplot-py.sourceforge.net/
8 8
9 9 See gphelp() below for details on the services offered by this module.
10 10
11 11 Inspired by a suggestion/request from Arnd Baecker.
12
13 $Id: GnuplotInteractive.py 389 2004-10-09 07:59:30Z fperez $"""
12 """
14 13
15 14 __all__ = ['Gnuplot','gp','gp_new','plot','plot2','splot','replot',
16 15 'hardcopy','gpdata','gpfile','gpstring','gpfunc','gpgrid',
17 16 'gphelp']
18 17
19 18 import IPython.GnuplotRuntime as GRun
20 19 from IPython.genutils import page,warn
21 20
22 21 # Set global names for interactive use
23 22 Gnuplot = GRun.Gnuplot
24 23 gp_new = GRun.gp_new
25 24 gp = GRun.gp
26 25 plot = gp.plot
27 26 plot2 = gp.plot2
28 27 splot = gp.splot
29 28 replot = gp.replot
30 29 hardcopy = gp.hardcopy
31 30
32 31 # Accessors for the main plot object constructors:
33 32 gpdata = Gnuplot.Data
34 33 gpfile = Gnuplot.File
35 34 gpstring = Gnuplot.String
36 35 gpfunc = Gnuplot.Func
37 36 gpgrid = Gnuplot.GridData
38 37
39 38 def gphelp():
40 39 """Print information about the Gnuplot facilities in IPython."""
41 40
42 41 page("""
43 42 IPython provides an interface to access the Gnuplot scientific plotting
44 43 system, in an environment similar to that of Mathematica or Matlab.
45 44
46 45 New top-level global objects
47 46 ----------------------------
48 47
49 48 Please see their respective docstrings for further details.
50 49
51 50 - gp: a running Gnuplot instance. You can access its methods as
52 51 gp.<method>. gp(`a string`) will execute the given string as if it had been
53 52 typed in an interactive gnuplot window.
54 53
55 54 - plot, splot, replot and hardcopy: aliases to the methods of the same name in
56 55 the global running Gnuplot instance gp. These allow you to simply type:
57 56
58 57 In [1]: plot(x,sin(x),title='Sin(x)') # assuming x is a Numeric array
59 58
60 59 and obtain a plot of sin(x) vs x with the title 'Sin(x)'.
61 60
62 61 - gp_new: a function which returns a new Gnuplot instance. This can be used to
63 62 have multiple Gnuplot instances running in your session to compare different
64 63 plots, each in a separate window.
65 64
66 65 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
67 66 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
68 67 functions with improved versions (Gnuplot2 comes with IPython).
69 68
70 69 - gpdata, gpfile, gpstring, gpfunc, gpgrid: aliases to Gnuplot.Data,
71 70 Gnuplot.File, Gnuplot.String, Gnuplot.Func and Gnuplot.GridData
72 71 respectively. These functions create objects which can then be passed to the
73 72 plotting commands. See the Gnuplot.py documentation for details.
74 73
75 74 Keep in mind that all commands passed to a Gnuplot instance are executed in
76 75 the Gnuplot namespace, where no Python variables exist. For example, for
77 76 plotting sin(x) vs x as above, typing
78 77
79 78 In [2]: gp('plot x,sin(x)')
80 79
81 80 would not work. Instead, you would get the plot of BOTH the functions 'x' and
82 81 'sin(x)', since Gnuplot doesn't know about the 'x' Python array. The plot()
83 82 method lives in python and does know about these variables.
84 83
85 84
86 85 New magic functions
87 86 -------------------
88 87
89 88 %gpc: pass one command to Gnuplot and execute it or open a Gnuplot shell where
90 89 each line of input is executed.
91 90
92 91 %gp_set_default: reset the value of IPython's global Gnuplot instance.""")
93 92
94 93 # Code below is all for IPython use
95 94 # Define the magic functions for communicating with the above gnuplot instance.
96 95 def magic_gpc(self,parameter_s=''):
97 96 """Execute a gnuplot command or open a gnuplot shell.
98 97
99 98 Usage (omit the % if automagic is on). There are two ways to use it:
100 99
101 100 1) %gpc 'command' -> passes 'command' directly to the gnuplot instance.
102 101
103 102 2) %gpc -> will open up a prompt (gnuplot>>>) which takes input like the
104 103 standard gnuplot interactive prompt. If you need to type a multi-line
105 104 command, use \\ at the end of each intermediate line.
106 105
107 106 Upon exiting of the gnuplot sub-shell, you return to your IPython
108 107 session (the gnuplot sub-shell can be invoked as many times as needed).
109 108 """
110 109
111 110 if parameter_s.strip():
112 111 self.shell.gnuplot(parameter_s)
113 112 else:
114 113 self.shell.gnuplot.interact()
115 114
116 115 def magic_gp_set_default(self,parameter_s=''):
117 116 """Set the default gnuplot instance accessed by the %gp magic function.
118 117
119 118 %gp_set_default name
120 119
121 120 Call with the name of the new instance at the command line. If you want to
122 121 set this instance in your own code (using an embedded IPython, for
123 122 example), simply set the variable __IPYTHON__.gnuplot to your own gnuplot
124 123 instance object."""
125 124
126 125 gname = parameter_s.strip()
127 126 G = eval(gname,self.shell.user_ns)
128 127 self.shell.gnuplot = G
129 128 self.shell.user_ns.update({'plot':G.plot,'splot':G.splot,'plot2':G.plot2,
130 129 'replot':G.replot,'hardcopy':G.hardcopy})
131 130
132 131 try:
133 132 __IPYTHON__
134 133 except NameError:
135 134 pass
136 135 else:
137 136 # make the global Gnuplot instance known to IPython
138 137 __IPYTHON__.gnuplot = GRun.gp
139 138 __IPYTHON__.gnuplot.shell_first_time = 1
140 139
141 140 print """*** Type `gphelp` for help on the Gnuplot integration features."""
142 141
143 142 # Add the new magic functions to the class dict
144 143 from IPython.iplib import InteractiveShell
145 144 InteractiveShell.magic_gpc = magic_gpc
146 145 InteractiveShell.magic_gp_set_default = magic_gp_set_default
147 146
148 147 #********************** End of file <GnuplotInteractive.py> *******************
@@ -1,147 +1,146 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Basic Gnuplot functionality for inclusion in other code.
3 3
4 4 This module creates a running Gnuplot instance called 'gp' and builds other
5 5 convenient globals for quick use in running scripts. It is intended to allow
6 6 you to script plotting tasks in Python with a minimum of effort. A typical
7 7 usage would be:
8 8
9 9 import IPython.GnuplotRuntime as GP # or some other short name
10 10 GP.gp.plot(GP.File('your_data.dat'))
11 11
12 12
13 13 This module exposes the following objects:
14 14
15 15 - gp: a running Gnuplot instance. You can access its methods as
16 16 gp.<method>. gp(`a string`) will execute the given string as if it had been
17 17 typed in an interactive gnuplot window.
18 18
19 19 - gp_new: a function which returns a new Gnuplot instance. This can be used to
20 20 have multiple Gnuplot instances running in your session to compare different
21 21 plots.
22 22
23 23 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
24 24 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
25 25 functions with improved versions (Gnuplot2 comes with IPython).
26 26
27 27 - Data: alias to Gnuplot.Data, makes a PlotItem from array data.
28 28
29 29 - File: alias to Gnuplot.File, makes a PlotItem from a file.
30 30
31 31 - String: alias to Gnuplot.String, makes a PlotItem from a string formatted
32 32 exactly like a file for Gnuplot.File would be.
33 33
34 34 - Func: alias to Gnuplot.Func, makes a PlotItem from a function string.
35 35
36 36 - GridData: alias to Gnuplot.GridData, makes a PlotItem from grid data.
37 37
38 38 - pm3d_config: a string with Gnuplot commands to set up the pm3d mode for
39 39 surface plotting. You can activate it simply by calling gp(pm3d_config).
40 40
41 41 - eps_fix_bbox: A Unix-only function to fix eps files with bad bounding boxes
42 42 (which Gnuplot generates when the plot size is set to square).
43 43
44 44 This requires the Gnuplot.py module for interfacing Python with Gnuplot, which
45 45 can be downloaded from:
46 46
47 47 http://gnuplot-py.sourceforge.net/
48 48
49 49 Inspired by a suggestion/request from Arnd Baecker.
50
51 $Id: GnuplotRuntime.py 389 2004-10-09 07:59:30Z fperez $"""
50 """
52 51
53 52 __all__ = ['Gnuplot','gp','gp_new','Data','File','Func','GridData',
54 53 'pm3d_config','eps_fix_bbox']
55 54
56 55 import os,tempfile,sys
57 56 from IPython.genutils import getoutput
58 57
59 58 #---------------------------------------------------------------------------
60 59 # Notes on mouse support for Gnuplot.py
61 60
62 61 # If you do not have a mouse-enabled gnuplot, set gnuplot_mouse to 0. If you
63 62 # use gnuplot, you should really grab a recent, mouse enabled copy. It is an
64 63 # extremely useful feature. Mouse support is official as of gnuplot 4.0,
65 64 # released in April 2004.
66 65
67 66 # For the mouse features to work correctly, you MUST set your Gnuplot.py
68 67 # module to use temporary files instead of 'inline data' for data
69 68 # communication. Note that this is the default, so unless you've manually
70 69 # fiddled with it you should be ok. If you need to make changes, in the
71 70 # Gnuplot module directory, loook for the gp_unix.py file and make sure the
72 71 # prefer_inline_data variable is set to 0. If you set it to 1 Gnuplot.py will
73 72 # try to pass the data to gnuplot via standard input, which completely
74 73 # confuses the mouse control system (even though it may be a bit faster than
75 74 # using temp files).
76 75
77 76 # As of Gnuplot.py v1.7, a new option was added to use FIFOs (pipes). This
78 77 # mechanism, while fast, also breaks the mouse system. You must therefore set
79 78 # the variable prefer_fifo_data to 0 in gp_unix.py.
80 79
81 80 tmpname = tempfile.mktemp()
82 81 open(tmpname,'w').write('set mouse')
83 82 gnu_out = getoutput('gnuplot '+ tmpname)
84 83 os.unlink(tmpname)
85 84 if gnu_out: # Gnuplot won't print anything if it has mouse support
86 85 print "*** Your version of Gnuplot appears not to have mouse support."
87 86 gnuplot_mouse = 0
88 87 else:
89 88 gnuplot_mouse = 1
90 89 del tmpname,gnu_out
91 90
92 91 # Default state for persistence of new gnuplot instances
93 92 if os.name in ['nt','dos'] or sys.platform == 'cygwin':
94 93 gnuplot_persist = 0
95 94 else:
96 95 gnuplot_persist = 1
97 96
98 97 import IPython.Gnuplot2 as Gnuplot
99 98
100 99 class NotGiven: pass
101 100
102 101 def gp_new(mouse=NotGiven,persist=NotGiven):
103 102 """Return a new Gnuplot instance.
104 103
105 104 The instance returned uses the improved methods defined in Gnuplot2.
106 105
107 106 Options (boolean):
108 107
109 108 - mouse: if unspecified, the module global gnuplot_mouse is used.
110 109
111 110 - persist: if unspecified, the module global gnuplot_persist is used."""
112 111
113 112 if mouse is NotGiven:
114 113 mouse = gnuplot_mouse
115 114 if persist is NotGiven:
116 115 persist = gnuplot_persist
117 116 g = Gnuplot.Gnuplot(persist=persist)
118 117 if mouse:
119 118 g('set mouse')
120 119 return g
121 120
122 121 # Global-level names.
123 122
124 123 # A global Gnuplot instance for interactive use:
125 124 gp = gp_new()
126 125
127 126 # Accessors for the main plot object constructors:
128 127 Data = Gnuplot.Data
129 128 File = Gnuplot.File
130 129 Func = Gnuplot.Func
131 130 String = Gnuplot.String
132 131 GridData = Gnuplot.GridData
133 132
134 133 # A Unix-only function to fix eps files with bad bounding boxes (which Gnuplot
135 134 # generates when the plot size is set to square):
136 135 eps_fix_bbox = Gnuplot.eps_fix_bbox
137 136
138 137 # String for configuring pm3d. Simply call g(pm3d_config) to execute it. pm3d
139 138 # is a very nice mode for plotting colormaps on surfaces. Modify the defaults
140 139 # below to suit your taste.
141 140 pm3d_config = """
142 141 set pm3d solid
143 142 set hidden3d
144 143 unset surface
145 144 set isosamples 50
146 145 """
147 146 #******************** End of file <GnuplotRuntime.py> ******************
@@ -1,292 +1,290 b''
1 1 # -*- coding: utf-8 -*-
2 2 """String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
3 3
4 4 This module lets you quickly and conveniently interpolate values into
5 5 strings (in the flavour of Perl or Tcl, but with less extraneous
6 6 punctuation). You get a bit more power than in the other languages,
7 7 because this module allows subscripting, slicing, function calls,
8 8 attribute lookup, or arbitrary expressions. Variables and expressions
9 9 are evaluated in the namespace of the caller.
10 10
11 11 The itpl() function returns the result of interpolating a string, and
12 12 printpl() prints out an interpolated string. Here are some examples:
13 13
14 14 from Itpl import printpl
15 15 printpl("Here is a $string.")
16 16 printpl("Here is a $module.member.")
17 17 printpl("Here is an $object.member.")
18 18 printpl("Here is a $functioncall(with, arguments).")
19 19 printpl("Here is an ${arbitrary + expression}.")
20 20 printpl("Here is an $array[3] member.")
21 21 printpl("Here is a $dictionary['member'].")
22 22
23 23 The filter() function filters a file object so that output through it
24 24 is interpolated. This lets you produce the illusion that Python knows
25 25 how to do interpolation:
26 26
27 27 import Itpl
28 28 sys.stdout = Itpl.filter()
29 29 f = "fancy"
30 print "Isn't this $f?"
30 print "Is this not $f?"
31 31 print "Standard output has been replaced with a $sys.stdout object."
32 32 sys.stdout = Itpl.unfilter()
33 33 print "Okay, back $to $normal."
34 34
35 35 Under the hood, the Itpl class represents a string that knows how to
36 36 interpolate values. An instance of the class parses the string once
37 37 upon initialization; the evaluation and substitution can then be done
38 38 each time the instance is evaluated with str(instance). For example:
39 39
40 40 from Itpl import Itpl
41 41 s = Itpl("Here is $foo.")
42 42 foo = 5
43 43 print str(s)
44 44 foo = "bar"
45 45 print str(s)
46
47 $Id: Itpl.py 2918 2007-12-31 14:34:47Z vivainio $
48 """ # ' -> close an open quote for stupid emacs
46 """
49 47
50 48 #*****************************************************************************
51 49 #
52 50 # Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
53 51 #
54 52 #
55 53 # Published under the terms of the MIT license, hereby reproduced:
56 54 #
57 55 # Permission is hereby granted, free of charge, to any person obtaining a copy
58 56 # of this software and associated documentation files (the "Software"), to
59 57 # deal in the Software without restriction, including without limitation the
60 58 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
61 59 # sell copies of the Software, and to permit persons to whom the Software is
62 60 # furnished to do so, subject to the following conditions:
63 61 #
64 62 # The above copyright notice and this permission notice shall be included in
65 63 # all copies or substantial portions of the Software.
66 64 #
67 65 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68 66 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69 67 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70 68 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71 69 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
72 70 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
73 71 # IN THE SOFTWARE.
74 72 #
75 73 #*****************************************************************************
76 74
77 75 __author__ = 'Ka-Ping Yee <ping@lfw.org>'
78 76 __license__ = 'MIT'
79 77
80 78 import string
81 79 import sys
82 80 from tokenize import tokenprog
83 81 from types import StringType
84 82
85 83 class ItplError(ValueError):
86 84 def __init__(self, text, pos):
87 85 self.text = text
88 86 self.pos = pos
89 87 def __str__(self):
90 88 return "unfinished expression in %s at char %d" % (
91 89 repr(self.text), self.pos)
92 90
93 91 def matchorfail(text, pos):
94 92 match = tokenprog.match(text, pos)
95 93 if match is None:
96 94 raise ItplError(text, pos)
97 95
98 96 return match, match.end()
99 97
100 98 try:
101 99 itpl_encoding = sys.stdin.encoding or 'ascii'
102 100 except AttributeError:
103 101 itpl_encoding = 'ascii'
104 102
105 103
106 104
107 105 class Itpl:
108 106 """Class representing a string with interpolation abilities.
109 107
110 108 Upon creation, an instance works out what parts of the format
111 109 string are literal and what parts need to be evaluated. The
112 110 evaluation and substitution happens in the namespace of the
113 111 caller when str(instance) is called."""
114 112
115 113 def __init__(self, format,codec=itpl_encoding,encoding_errors='backslashreplace'):
116 114 """The single mandatory argument to this constructor is a format
117 115 string.
118 116
119 117 The format string is parsed according to the following rules:
120 118
121 119 1. A dollar sign and a name, possibly followed by any of:
122 120 - an open-paren, and anything up to the matching paren
123 121 - an open-bracket, and anything up to the matching bracket
124 122 - a period and a name
125 123 any number of times, is evaluated as a Python expression.
126 124
127 125 2. A dollar sign immediately followed by an open-brace, and
128 126 anything up to the matching close-brace, is evaluated as
129 127 a Python expression.
130 128
131 129 3. Outside of the expressions described in the above two rules,
132 130 two dollar signs in a row give you one literal dollar sign.
133 131
134 132 Optional arguments:
135 133
136 134 - codec('utf_8'): a string containing the name of a valid Python
137 135 codec.
138 136
139 137 - encoding_errors('backslashreplace'): a string with a valid error handling
140 138 policy. See the codecs module documentation for details.
141 139
142 140 These are used to encode the format string if a call to str() fails on
143 141 the expanded result."""
144 142
145 143 if not isinstance(format,basestring):
146 144 raise TypeError, "needs string initializer"
147 145 self.format = format
148 146 self.codec = codec
149 147 self.encoding_errors = encoding_errors
150 148
151 149 namechars = "abcdefghijklmnopqrstuvwxyz" \
152 150 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
153 151 chunks = []
154 152 pos = 0
155 153
156 154 while 1:
157 155 dollar = string.find(format, "$", pos)
158 156 if dollar < 0: break
159 157 nextchar = format[dollar+1]
160 158
161 159 if nextchar == "{":
162 160 chunks.append((0, format[pos:dollar]))
163 161 pos, level = dollar+2, 1
164 162 while level:
165 163 match, pos = matchorfail(format, pos)
166 164 tstart, tend = match.regs[3]
167 165 token = format[tstart:tend]
168 166 if token == "{": level = level+1
169 167 elif token == "}": level = level-1
170 168 chunks.append((1, format[dollar+2:pos-1]))
171 169
172 170 elif nextchar in namechars:
173 171 chunks.append((0, format[pos:dollar]))
174 172 match, pos = matchorfail(format, dollar+1)
175 173 while pos < len(format):
176 174 if format[pos] == "." and \
177 175 pos+1 < len(format) and format[pos+1] in namechars:
178 176 match, pos = matchorfail(format, pos+1)
179 177 elif format[pos] in "([":
180 178 pos, level = pos+1, 1
181 179 while level:
182 180 match, pos = matchorfail(format, pos)
183 181 tstart, tend = match.regs[3]
184 182 token = format[tstart:tend]
185 183 if token[0] in "([": level = level+1
186 184 elif token[0] in ")]": level = level-1
187 185 else: break
188 186 chunks.append((1, format[dollar+1:pos]))
189 187
190 188 else:
191 189 chunks.append((0, format[pos:dollar+1]))
192 190 pos = dollar + 1 + (nextchar == "$")
193 191
194 192 if pos < len(format): chunks.append((0, format[pos:]))
195 193 self.chunks = chunks
196 194
197 195 def __repr__(self):
198 196 return "<Itpl %s >" % repr(self.format)
199 197
200 198 def _str(self,glob,loc):
201 199 """Evaluate to a string in the given globals/locals.
202 200
203 201 The final output is built by calling str(), but if this fails, the
204 202 result is encoded with the instance's codec and error handling policy,
205 203 via a call to out.encode(self.codec,self.encoding_errors)"""
206 204 result = []
207 205 app = result.append
208 206 for live, chunk in self.chunks:
209 207 if live:
210 208 val = eval(chunk,glob,loc)
211 209 try:
212 210 app(str(val))
213 211 except UnicodeEncodeError:
214 212 app(unicode(val))
215 213
216 214 else: app(chunk)
217 215 out = ''.join(result)
218 216 try:
219 217 return str(out)
220 218 except UnicodeError:
221 219 return out.encode(self.codec,self.encoding_errors)
222 220
223 221 def __str__(self):
224 222 """Evaluate and substitute the appropriate parts of the string."""
225 223
226 224 # We need to skip enough frames to get to the actual caller outside of
227 225 # Itpl.
228 226 frame = sys._getframe(1)
229 227 while frame.f_globals["__name__"] == __name__: frame = frame.f_back
230 228 loc, glob = frame.f_locals, frame.f_globals
231 229
232 230 return self._str(glob,loc)
233 231
234 232 class ItplNS(Itpl):
235 233 """Class representing a string with interpolation abilities.
236 234
237 235 This inherits from Itpl, but at creation time a namespace is provided
238 236 where the evaluation will occur. The interpolation becomes a bit more
239 237 efficient, as no traceback needs to be extracte. It also allows the
240 238 caller to supply a different namespace for the interpolation to occur than
241 239 its own."""
242 240
243 241 def __init__(self, format,globals,locals=None,
244 242 codec='utf_8',encoding_errors='backslashreplace'):
245 243 """ItplNS(format,globals[,locals]) -> interpolating string instance.
246 244
247 245 This constructor, besides a format string, takes a globals dictionary
248 246 and optionally a locals (which defaults to globals if not provided).
249 247
250 248 For further details, see the Itpl constructor."""
251 249
252 250 if locals is None:
253 251 locals = globals
254 252 self.globals = globals
255 253 self.locals = locals
256 254 Itpl.__init__(self,format,codec,encoding_errors)
257 255
258 256 def __str__(self):
259 257 """Evaluate and substitute the appropriate parts of the string."""
260 258 return self._str(self.globals,self.locals)
261 259
262 260 def __repr__(self):
263 261 return "<ItplNS %s >" % repr(self.format)
264 262
265 263 # utilities for fast printing
266 264 def itpl(text): return str(Itpl(text))
267 265 def printpl(text): print itpl(text)
268 266 # versions with namespace
269 267 def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
270 268 def printplns(text,globals,locals=None): print itplns(text,globals,locals)
271 269
272 270 class ItplFile:
273 271 """A file object that filters each write() through an interpolator."""
274 272 def __init__(self, file): self.file = file
275 273 def __repr__(self): return "<interpolated " + repr(self.file) + ">"
276 274 def __getattr__(self, attr): return getattr(self.file, attr)
277 275 def write(self, text): self.file.write(str(Itpl(text)))
278 276
279 277 def filter(file=sys.stdout):
280 278 """Return an ItplFile that filters writes to the given file object.
281 279
282 280 'file = filter(file)' replaces 'file' with a filtered object that
283 281 has a write() method. When called with no argument, this creates
284 282 a filter to sys.stdout."""
285 283 return ItplFile(file)
286 284
287 285 def unfilter(ifile=None):
288 286 """Return the original file that corresponds to the given ItplFile.
289 287
290 288 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
291 289 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
292 290 return ifile and ifile.file or sys.stdout.file
@@ -1,270 +1,263 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Logger class for IPython's logging facilities.
4
5 $Id: Logger.py 2875 2007-11-26 08:37:39Z fperez $
6 4 """
7 5
8 6 #*****************************************************************************
9 7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
10 8 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
11 9 #
12 10 # Distributed under the terms of the BSD License. The full license is in
13 11 # the file COPYING, distributed as part of this software.
14 12 #*****************************************************************************
15 13
16 14 #****************************************************************************
17 15 # Modules and globals
18 16
19 from IPython import Release
20 __author__ = '%s <%s>\n%s <%s>' % \
21 ( Release.authors['Janko'] + Release.authors['Fernando'] )
22 __license__ = Release.license
23
24 17 # Python standard modules
25 18 import glob
26 19 import os
27 20 import time
28 21
29 22 #****************************************************************************
30 23 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
31 24 # ipython and does input cache management. Finish cleanup later...
32 25
33 26 class Logger(object):
34 27 """A Logfile class with different policies for file creation"""
35 28
36 29 def __init__(self,shell,logfname='Logger.log',loghead='',logmode='over'):
37 30
38 31 self._i00,self._i,self._ii,self._iii = '','','',''
39 32
40 33 # this is the full ipython instance, we need some attributes from it
41 34 # which won't exist until later. What a mess, clean up later...
42 35 self.shell = shell
43 36
44 37 self.logfname = logfname
45 38 self.loghead = loghead
46 39 self.logmode = logmode
47 40 self.logfile = None
48 41
49 42 # Whether to log raw or processed input
50 43 self.log_raw_input = False
51 44
52 45 # whether to also log output
53 46 self.log_output = False
54 47
55 48 # whether to put timestamps before each log entry
56 49 self.timestamp = False
57 50
58 51 # activity control flags
59 52 self.log_active = False
60 53
61 54 # logmode is a validated property
62 55 def _set_mode(self,mode):
63 56 if mode not in ['append','backup','global','over','rotate']:
64 57 raise ValueError,'invalid log mode %s given' % mode
65 58 self._logmode = mode
66 59
67 60 def _get_mode(self):
68 61 return self._logmode
69 62
70 63 logmode = property(_get_mode,_set_mode)
71 64
72 65 def logstart(self,logfname=None,loghead=None,logmode=None,
73 66 log_output=False,timestamp=False,log_raw_input=False):
74 67 """Generate a new log-file with a default header.
75 68
76 69 Raises RuntimeError if the log has already been started"""
77 70
78 71 if self.logfile is not None:
79 72 raise RuntimeError('Log file is already active: %s' %
80 73 self.logfname)
81 74
82 75 self.log_active = True
83 76
84 77 # The parameters can override constructor defaults
85 78 if logfname is not None: self.logfname = logfname
86 79 if loghead is not None: self.loghead = loghead
87 80 if logmode is not None: self.logmode = logmode
88 81
89 82 # Parameters not part of the constructor
90 83 self.timestamp = timestamp
91 84 self.log_output = log_output
92 85 self.log_raw_input = log_raw_input
93 86
94 87 # init depending on the log mode requested
95 88 isfile = os.path.isfile
96 89 logmode = self.logmode
97 90
98 91 if logmode == 'append':
99 92 self.logfile = open(self.logfname,'a')
100 93
101 94 elif logmode == 'backup':
102 95 if isfile(self.logfname):
103 96 backup_logname = self.logfname+'~'
104 97 # Manually remove any old backup, since os.rename may fail
105 98 # under Windows.
106 99 if isfile(backup_logname):
107 100 os.remove(backup_logname)
108 101 os.rename(self.logfname,backup_logname)
109 102 self.logfile = open(self.logfname,'w')
110 103
111 104 elif logmode == 'global':
112 105 self.logfname = os.path.join(self.shell.home_dir,self.logfname)
113 106 self.logfile = open(self.logfname, 'a')
114 107
115 108 elif logmode == 'over':
116 109 if isfile(self.logfname):
117 110 os.remove(self.logfname)
118 111 self.logfile = open(self.logfname,'w')
119 112
120 113 elif logmode == 'rotate':
121 114 if isfile(self.logfname):
122 115 if isfile(self.logfname+'.001~'):
123 116 old = glob.glob(self.logfname+'.*~')
124 117 old.sort()
125 118 old.reverse()
126 119 for f in old:
127 120 root, ext = os.path.splitext(f)
128 121 num = int(ext[1:-1])+1
129 122 os.rename(f, root+'.'+`num`.zfill(3)+'~')
130 123 os.rename(self.logfname, self.logfname+'.001~')
131 124 self.logfile = open(self.logfname,'w')
132 125
133 126 if logmode != 'append':
134 127 self.logfile.write(self.loghead)
135 128
136 129 self.logfile.flush()
137 130
138 131 def switch_log(self,val):
139 132 """Switch logging on/off. val should be ONLY a boolean."""
140 133
141 134 if val not in [False,True,0,1]:
142 135 raise ValueError, \
143 136 'Call switch_log ONLY with a boolean argument, not with:',val
144 137
145 138 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
146 139
147 140 if self.logfile is None:
148 141 print """
149 142 Logging hasn't been started yet (use logstart for that).
150 143
151 144 %logon/%logoff are for temporarily starting and stopping logging for a logfile
152 145 which already exists. But you must first start the logging process with
153 146 %logstart (optionally giving a logfile name)."""
154 147
155 148 else:
156 149 if self.log_active == val:
157 150 print 'Logging is already',label[val]
158 151 else:
159 152 print 'Switching logging',label[val]
160 153 self.log_active = not self.log_active
161 154 self.log_active_out = self.log_active
162 155
163 156 def logstate(self):
164 157 """Print a status message about the logger."""
165 158 if self.logfile is None:
166 159 print 'Logging has not been activated.'
167 160 else:
168 161 state = self.log_active and 'active' or 'temporarily suspended'
169 162 print 'Filename :',self.logfname
170 163 print 'Mode :',self.logmode
171 164 print 'Output logging :',self.log_output
172 165 print 'Raw input log :',self.log_raw_input
173 166 print 'Timestamping :',self.timestamp
174 167 print 'State :',state
175 168
176 169 def log(self,line_ori,line_mod,continuation=None):
177 170 """Write the line to a log and create input cache variables _i*.
178 171
179 172 Inputs:
180 173
181 174 - line_ori: unmodified input line from the user. This is not
182 175 necessarily valid Python.
183 176
184 177 - line_mod: possibly modified input, such as the transformations made
185 178 by input prefilters or input handlers of various kinds. This should
186 179 always be valid Python.
187 180
188 181 - continuation: if True, indicates this is part of multi-line input."""
189 182
190 183 # update the auto _i tables
191 184 #print '***logging line',line_mod # dbg
192 185 #print '***cache_count', self.shell.outputcache.prompt_count # dbg
193 186 try:
194 187 input_hist = self.shell.user_ns['_ih']
195 188 except:
196 189 #print 'userns:',self.shell.user_ns.keys() # dbg
197 190 return
198 191
199 192 out_cache = self.shell.outputcache
200 193
201 194 # add blank lines if the input cache fell out of sync.
202 195 if out_cache.do_full_cache and \
203 196 out_cache.prompt_count +1 > len(input_hist):
204 197 input_hist.extend(['\n'] * (out_cache.prompt_count - len(input_hist)))
205 198
206 199 if not continuation and line_mod:
207 200 self._iii = self._ii
208 201 self._ii = self._i
209 202 self._i = self._i00
210 203 # put back the final \n of every input line
211 204 self._i00 = line_mod+'\n'
212 205 #print 'Logging input:<%s>' % line_mod # dbg
213 206 input_hist.append(self._i00)
214 207 #print '---[%s]' % (len(input_hist)-1,) # dbg
215 208
216 209 # hackish access to top-level namespace to create _i1,_i2... dynamically
217 210 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
218 211 if self.shell.outputcache.do_full_cache:
219 212 in_num = self.shell.outputcache.prompt_count
220 213
221 214 # but if the opposite is true (a macro can produce multiple inputs
222 215 # with no output display called), then bring the output counter in
223 216 # sync:
224 217 last_num = len(input_hist)-1
225 218 if in_num != last_num:
226 219 in_num = self.shell.outputcache.prompt_count = last_num
227 220 new_i = '_i%s' % in_num
228 221 if continuation:
229 222 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
230 223 input_hist[in_num] = self._i00
231 224 to_main[new_i] = self._i00
232 225 self.shell.user_ns.update(to_main)
233 226
234 227 # Write the log line, but decide which one according to the
235 228 # log_raw_input flag, set when the log is started.
236 229 if self.log_raw_input:
237 230 self.log_write(line_ori)
238 231 else:
239 232 self.log_write(line_mod)
240 233
241 234 def log_write(self,data,kind='input'):
242 235 """Write data to the log file, if active"""
243 236
244 237 #print 'data: %r' % data # dbg
245 238 if self.log_active and data:
246 239 write = self.logfile.write
247 240 if kind=='input':
248 241 if self.timestamp:
249 242 write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
250 243 time.localtime()))
251 244 write('%s\n' % data)
252 245 elif kind=='output' and self.log_output:
253 246 odata = '\n'.join(['#[Out]# %s' % s
254 247 for s in data.split('\n')])
255 248 write('%s\n' % odata)
256 249 self.logfile.flush()
257 250
258 251 def logstop(self):
259 252 """Fully stop logging and close log file.
260 253
261 254 In order to start logging again, a new logstart() call needs to be
262 255 made, possibly (though not necessarily) with a new filename, mode and
263 256 other options."""
264 257
265 258 self.logfile.close()
266 259 self.logfile = None
267 260 self.log_active = False
268 261
269 262 # For backwards compatibility, in case anyone was using this.
270 263 close_log = logstop
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,613 +1,607 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for inspecting Python objects.
3 3
4 4 Uses syntax highlighting for presenting the various information elements.
5 5
6 6 Similar in spirit to the inspect module, but all calls take a name argument to
7 7 reference the name under which an object is being read.
8
9 $Id: OInspect.py 2843 2007-10-15 21:22:32Z fperez $
10 8 """
11 9
12 10 #*****************************************************************************
13 11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
14 12 #
15 13 # Distributed under the terms of the BSD License. The full license is in
16 14 # the file COPYING, distributed as part of this software.
17 15 #*****************************************************************************
18 16
19 from IPython import Release
20 __author__ = '%s <%s>' % Release.authors['Fernando']
21 __license__ = Release.license
22
23 17 __all__ = ['Inspector','InspectColors']
24 18
25 19 # stdlib modules
26 20 import __builtin__
27 21 import StringIO
28 22 import inspect
29 23 import linecache
30 24 import os
31 25 import string
32 26 import sys
33 27 import types
34 28
35 29 # IPython's own
36 30 from IPython import PyColorize
37 31 from IPython.genutils import page,indent,Term
38 32 from IPython.Itpl import itpl
39 33 from IPython.wildcard import list_namespace
40 34 from IPython.ColorANSI import *
41 35
42 36 #****************************************************************************
43 37 # HACK!!! This is a crude fix for bugs in python 2.3's inspect module. We
44 38 # simply monkeypatch inspect with code copied from python 2.4.
45 39 if sys.version_info[:2] == (2,3):
46 40 from inspect import ismodule, getabsfile, modulesbyfile
47 41 def getmodule(object):
48 42 """Return the module an object was defined in, or None if not found."""
49 43 if ismodule(object):
50 44 return object
51 45 if hasattr(object, '__module__'):
52 46 return sys.modules.get(object.__module__)
53 47 try:
54 48 file = getabsfile(object)
55 49 except TypeError:
56 50 return None
57 51 if file in modulesbyfile:
58 52 return sys.modules.get(modulesbyfile[file])
59 53 for module in sys.modules.values():
60 54 if hasattr(module, '__file__'):
61 55 modulesbyfile[
62 56 os.path.realpath(
63 57 getabsfile(module))] = module.__name__
64 58 if file in modulesbyfile:
65 59 return sys.modules.get(modulesbyfile[file])
66 60 main = sys.modules['__main__']
67 61 if not hasattr(object, '__name__'):
68 62 return None
69 63 if hasattr(main, object.__name__):
70 64 mainobject = getattr(main, object.__name__)
71 65 if mainobject is object:
72 66 return main
73 67 builtin = sys.modules['__builtin__']
74 68 if hasattr(builtin, object.__name__):
75 69 builtinobject = getattr(builtin, object.__name__)
76 70 if builtinobject is object:
77 71 return builtin
78 72
79 73 inspect.getmodule = getmodule
80 74
81 75 #****************************************************************************
82 76 # Builtin color schemes
83 77
84 78 Colors = TermColors # just a shorthand
85 79
86 80 # Build a few color schemes
87 81 NoColor = ColorScheme(
88 82 'NoColor',{
89 83 'header' : Colors.NoColor,
90 84 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
91 85 } )
92 86
93 87 LinuxColors = ColorScheme(
94 88 'Linux',{
95 89 'header' : Colors.LightRed,
96 90 'normal' : Colors.Normal # color off (usu. Colors.Normal)
97 91 } )
98 92
99 93 LightBGColors = ColorScheme(
100 94 'LightBG',{
101 95 'header' : Colors.Red,
102 96 'normal' : Colors.Normal # color off (usu. Colors.Normal)
103 97 } )
104 98
105 99 # Build table of color schemes (needed by the parser)
106 100 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
107 101 'Linux')
108 102
109 103 #****************************************************************************
110 104 # Auxiliary functions
111 105 def getdoc(obj):
112 106 """Stable wrapper around inspect.getdoc.
113 107
114 108 This can't crash because of attribute problems.
115 109
116 110 It also attempts to call a getdoc() method on the given object. This
117 111 allows objects which provide their docstrings via non-standard mechanisms
118 112 (like Pyro proxies) to still be inspected by ipython's ? system."""
119 113
120 114 ds = None # default return value
121 115 try:
122 116 ds = inspect.getdoc(obj)
123 117 except:
124 118 # Harden against an inspect failure, which can occur with
125 119 # SWIG-wrapped extensions.
126 120 pass
127 121 # Allow objects to offer customized documentation via a getdoc method:
128 122 try:
129 123 ds2 = obj.getdoc()
130 124 except:
131 125 pass
132 126 else:
133 127 # if we get extra info, we add it to the normal docstring.
134 128 if ds is None:
135 129 ds = ds2
136 130 else:
137 131 ds = '%s\n%s' % (ds,ds2)
138 132 return ds
139 133
140 134
141 135 def getsource(obj,is_binary=False):
142 136 """Wrapper around inspect.getsource.
143 137
144 138 This can be modified by other projects to provide customized source
145 139 extraction.
146 140
147 141 Inputs:
148 142
149 143 - obj: an object whose source code we will attempt to extract.
150 144
151 145 Optional inputs:
152 146
153 147 - is_binary: whether the object is known to come from a binary source.
154 148 This implementation will skip returning any output for binary objects, but
155 149 custom extractors may know how to meaningfully process them."""
156 150
157 151 if is_binary:
158 152 return None
159 153 else:
160 154 try:
161 155 src = inspect.getsource(obj)
162 156 except TypeError:
163 157 if hasattr(obj,'__class__'):
164 158 src = inspect.getsource(obj.__class__)
165 159 return src
166 160
167 161 def getargspec(obj):
168 162 """Get the names and default values of a function's arguments.
169 163
170 164 A tuple of four things is returned: (args, varargs, varkw, defaults).
171 165 'args' is a list of the argument names (it may contain nested lists).
172 166 'varargs' and 'varkw' are the names of the * and ** arguments or None.
173 167 'defaults' is an n-tuple of the default values of the last n arguments.
174 168
175 169 Modified version of inspect.getargspec from the Python Standard
176 170 Library."""
177 171
178 172 if inspect.isfunction(obj):
179 173 func_obj = obj
180 174 elif inspect.ismethod(obj):
181 175 func_obj = obj.im_func
182 176 else:
183 177 raise TypeError, 'arg is not a Python function'
184 178 args, varargs, varkw = inspect.getargs(func_obj.func_code)
185 179 return args, varargs, varkw, func_obj.func_defaults
186 180
187 181 #****************************************************************************
188 182 # Class definitions
189 183
190 184 class myStringIO(StringIO.StringIO):
191 185 """Adds a writeln method to normal StringIO."""
192 186 def writeln(self,*arg,**kw):
193 187 """Does a write() and then a write('\n')"""
194 188 self.write(*arg,**kw)
195 189 self.write('\n')
196 190
197 191
198 192 class Inspector:
199 193 def __init__(self,color_table,code_color_table,scheme,
200 194 str_detail_level=0):
201 195 self.color_table = color_table
202 196 self.parser = PyColorize.Parser(code_color_table,out='str')
203 197 self.format = self.parser.format
204 198 self.str_detail_level = str_detail_level
205 199 self.set_active_scheme(scheme)
206 200
207 201 def __getdef(self,obj,oname=''):
208 202 """Return the definition header for any callable object.
209 203
210 204 If any exception is generated, None is returned instead and the
211 205 exception is suppressed."""
212 206
213 207 try:
214 208 return oname + inspect.formatargspec(*getargspec(obj))
215 209 except:
216 210 return None
217 211
218 212 def __head(self,h):
219 213 """Return a header string with proper colors."""
220 214 return '%s%s%s' % (self.color_table.active_colors.header,h,
221 215 self.color_table.active_colors.normal)
222 216
223 217 def set_active_scheme(self,scheme):
224 218 self.color_table.set_active_scheme(scheme)
225 219 self.parser.color_table.set_active_scheme(scheme)
226 220
227 221 def noinfo(self,msg,oname):
228 222 """Generic message when no information is found."""
229 223 print 'No %s found' % msg,
230 224 if oname:
231 225 print 'for %s' % oname
232 226 else:
233 227 print
234 228
235 229 def pdef(self,obj,oname=''):
236 230 """Print the definition header for any callable object.
237 231
238 232 If the object is a class, print the constructor information."""
239 233
240 234 if not callable(obj):
241 235 print 'Object is not callable.'
242 236 return
243 237
244 238 header = ''
245 239
246 240 if inspect.isclass(obj):
247 241 header = self.__head('Class constructor information:\n')
248 242 obj = obj.__init__
249 243 elif type(obj) is types.InstanceType:
250 244 obj = obj.__call__
251 245
252 246 output = self.__getdef(obj,oname)
253 247 if output is None:
254 248 self.noinfo('definition header',oname)
255 249 else:
256 250 print >>Term.cout, header,self.format(output),
257 251
258 252 def pdoc(self,obj,oname='',formatter = None):
259 253 """Print the docstring for any object.
260 254
261 255 Optional:
262 256 -formatter: a function to run the docstring through for specially
263 257 formatted docstrings."""
264 258
265 259 head = self.__head # so that itpl can find it even if private
266 260 ds = getdoc(obj)
267 261 if formatter:
268 262 ds = formatter(ds)
269 263 if inspect.isclass(obj):
270 264 init_ds = getdoc(obj.__init__)
271 265 output = itpl('$head("Class Docstring:")\n'
272 266 '$indent(ds)\n'
273 267 '$head("Constructor Docstring"):\n'
274 268 '$indent(init_ds)')
275 269 elif (type(obj) is types.InstanceType or isinstance(obj,object)) \
276 270 and hasattr(obj,'__call__'):
277 271 call_ds = getdoc(obj.__call__)
278 272 if call_ds:
279 273 output = itpl('$head("Class Docstring:")\n$indent(ds)\n'
280 274 '$head("Calling Docstring:")\n$indent(call_ds)')
281 275 else:
282 276 output = ds
283 277 else:
284 278 output = ds
285 279 if output is None:
286 280 self.noinfo('documentation',oname)
287 281 return
288 282 page(output)
289 283
290 284 def psource(self,obj,oname=''):
291 285 """Print the source code for an object."""
292 286
293 287 # Flush the source cache because inspect can return out-of-date source
294 288 linecache.checkcache()
295 289 try:
296 290 src = getsource(obj)
297 291 except:
298 292 self.noinfo('source',oname)
299 293 else:
300 294 page(self.format(src))
301 295
302 296 def pfile(self,obj,oname=''):
303 297 """Show the whole file where an object was defined."""
304 298
305 299 try:
306 300 try:
307 301 lineno = inspect.getsourcelines(obj)[1]
308 302 except TypeError:
309 303 # For instances, try the class object like getsource() does
310 304 if hasattr(obj,'__class__'):
311 305 lineno = inspect.getsourcelines(obj.__class__)[1]
312 306 # Adjust the inspected object so getabsfile() below works
313 307 obj = obj.__class__
314 308 except:
315 309 self.noinfo('file',oname)
316 310 return
317 311
318 312 # We only reach this point if object was successfully queried
319 313
320 314 # run contents of file through pager starting at line
321 315 # where the object is defined
322 316 ofile = inspect.getabsfile(obj)
323 317
324 318 if (ofile.endswith('.so') or ofile.endswith('.dll')):
325 319 print 'File %r is binary, not printing.' % ofile
326 320 elif not os.path.isfile(ofile):
327 321 print 'File %r does not exist, not printing.' % ofile
328 322 else:
329 323 # Print only text files, not extension binaries. Note that
330 324 # getsourcelines returns lineno with 1-offset and page() uses
331 325 # 0-offset, so we must adjust.
332 326 page(self.format(open(ofile).read()),lineno-1)
333 327
334 328 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
335 329 """Show detailed information about an object.
336 330
337 331 Optional arguments:
338 332
339 333 - oname: name of the variable pointing to the object.
340 334
341 335 - formatter: special formatter for docstrings (see pdoc)
342 336
343 337 - info: a structure with some information fields which may have been
344 338 precomputed already.
345 339
346 340 - detail_level: if set to 1, more information is given.
347 341 """
348 342
349 343 obj_type = type(obj)
350 344
351 345 header = self.__head
352 346 if info is None:
353 347 ismagic = 0
354 348 isalias = 0
355 349 ospace = ''
356 350 else:
357 351 ismagic = info.ismagic
358 352 isalias = info.isalias
359 353 ospace = info.namespace
360 354 # Get docstring, special-casing aliases:
361 355 if isalias:
362 356 if not callable(obj):
363 357 try:
364 358 ds = "Alias to the system command:\n %s" % obj[1]
365 359 except:
366 360 ds = "Alias: " + str(obj)
367 361 else:
368 362 ds = "Alias to " + str(obj)
369 363 if obj.__doc__:
370 364 ds += "\nDocstring:\n" + obj.__doc__
371 365 else:
372 366 ds = getdoc(obj)
373 367 if ds is None:
374 368 ds = '<no docstring>'
375 369 if formatter is not None:
376 370 ds = formatter(ds)
377 371
378 372 # store output in a list which gets joined with \n at the end.
379 373 out = myStringIO()
380 374
381 375 string_max = 200 # max size of strings to show (snipped if longer)
382 376 shalf = int((string_max -5)/2)
383 377
384 378 if ismagic:
385 379 obj_type_name = 'Magic function'
386 380 elif isalias:
387 381 obj_type_name = 'System alias'
388 382 else:
389 383 obj_type_name = obj_type.__name__
390 384 out.writeln(header('Type:\t\t')+obj_type_name)
391 385
392 386 try:
393 387 bclass = obj.__class__
394 388 out.writeln(header('Base Class:\t')+str(bclass))
395 389 except: pass
396 390
397 391 # String form, but snip if too long in ? form (full in ??)
398 392 if detail_level >= self.str_detail_level:
399 393 try:
400 394 ostr = str(obj)
401 395 str_head = 'String Form:'
402 396 if not detail_level and len(ostr)>string_max:
403 397 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
404 398 ostr = ("\n" + " " * len(str_head.expandtabs())).\
405 399 join(map(string.strip,ostr.split("\n")))
406 400 if ostr.find('\n') > -1:
407 401 # Print multi-line strings starting at the next line.
408 402 str_sep = '\n'
409 403 else:
410 404 str_sep = '\t'
411 405 out.writeln("%s%s%s" % (header(str_head),str_sep,ostr))
412 406 except:
413 407 pass
414 408
415 409 if ospace:
416 410 out.writeln(header('Namespace:\t')+ospace)
417 411
418 412 # Length (for strings and lists)
419 413 try:
420 414 length = str(len(obj))
421 415 out.writeln(header('Length:\t\t')+length)
422 416 except: pass
423 417
424 418 # Filename where object was defined
425 419 binary_file = False
426 420 try:
427 421 try:
428 422 fname = inspect.getabsfile(obj)
429 423 except TypeError:
430 424 # For an instance, the file that matters is where its class was
431 425 # declared.
432 426 if hasattr(obj,'__class__'):
433 427 fname = inspect.getabsfile(obj.__class__)
434 428 if fname.endswith('<string>'):
435 429 fname = 'Dynamically generated function. No source code available.'
436 430 if (fname.endswith('.so') or fname.endswith('.dll')):
437 431 binary_file = True
438 432 out.writeln(header('File:\t\t')+fname)
439 433 except:
440 434 # if anything goes wrong, we don't want to show source, so it's as
441 435 # if the file was binary
442 436 binary_file = True
443 437
444 438 # reconstruct the function definition and print it:
445 439 defln = self.__getdef(obj,oname)
446 440 if defln:
447 441 out.write(header('Definition:\t')+self.format(defln))
448 442
449 443 # Docstrings only in detail 0 mode, since source contains them (we
450 444 # avoid repetitions). If source fails, we add them back, see below.
451 445 if ds and detail_level == 0:
452 446 out.writeln(header('Docstring:\n') + indent(ds))
453 447
454 448 # Original source code for any callable
455 449 if detail_level:
456 450 # Flush the source cache because inspect can return out-of-date
457 451 # source
458 452 linecache.checkcache()
459 453 source_success = False
460 454 try:
461 455 try:
462 456 src = getsource(obj,binary_file)
463 457 except TypeError:
464 458 if hasattr(obj,'__class__'):
465 459 src = getsource(obj.__class__,binary_file)
466 460 if src is not None:
467 461 source = self.format(src)
468 462 out.write(header('Source:\n')+source.rstrip())
469 463 source_success = True
470 464 except Exception, msg:
471 465 pass
472 466
473 467 if ds and not source_success:
474 468 out.writeln(header('Docstring [source file open failed]:\n')
475 469 + indent(ds))
476 470
477 471 # Constructor docstring for classes
478 472 if inspect.isclass(obj):
479 473 # reconstruct the function definition and print it:
480 474 try:
481 475 obj_init = obj.__init__
482 476 except AttributeError:
483 477 init_def = init_ds = None
484 478 else:
485 479 init_def = self.__getdef(obj_init,oname)
486 480 init_ds = getdoc(obj_init)
487 481 # Skip Python's auto-generated docstrings
488 482 if init_ds and \
489 483 init_ds.startswith('x.__init__(...) initializes'):
490 484 init_ds = None
491 485
492 486 if init_def or init_ds:
493 487 out.writeln(header('\nConstructor information:'))
494 488 if init_def:
495 489 out.write(header('Definition:\t')+ self.format(init_def))
496 490 if init_ds:
497 491 out.writeln(header('Docstring:\n') + indent(init_ds))
498 492 # and class docstring for instances:
499 493 elif obj_type is types.InstanceType or \
500 494 isinstance(obj,object):
501 495
502 496 # First, check whether the instance docstring is identical to the
503 497 # class one, and print it separately if they don't coincide. In
504 498 # most cases they will, but it's nice to print all the info for
505 499 # objects which use instance-customized docstrings.
506 500 if ds:
507 501 try:
508 502 cls = getattr(obj,'__class__')
509 503 except:
510 504 class_ds = None
511 505 else:
512 506 class_ds = getdoc(cls)
513 507 # Skip Python's auto-generated docstrings
514 508 if class_ds and \
515 509 (class_ds.startswith('function(code, globals[,') or \
516 510 class_ds.startswith('instancemethod(function, instance,') or \
517 511 class_ds.startswith('module(name[,') ):
518 512 class_ds = None
519 513 if class_ds and ds != class_ds:
520 514 out.writeln(header('Class Docstring:\n') +
521 515 indent(class_ds))
522 516
523 517 # Next, try to show constructor docstrings
524 518 try:
525 519 init_ds = getdoc(obj.__init__)
526 520 # Skip Python's auto-generated docstrings
527 521 if init_ds and \
528 522 init_ds.startswith('x.__init__(...) initializes'):
529 523 init_ds = None
530 524 except AttributeError:
531 525 init_ds = None
532 526 if init_ds:
533 527 out.writeln(header('Constructor Docstring:\n') +
534 528 indent(init_ds))
535 529
536 530 # Call form docstring for callable instances
537 531 if hasattr(obj,'__call__'):
538 532 #out.writeln(header('Callable:\t')+'Yes')
539 533 call_def = self.__getdef(obj.__call__,oname)
540 534 #if call_def is None:
541 535 # out.writeln(header('Call def:\t')+
542 536 # 'Calling definition not available.')
543 537 if call_def is not None:
544 538 out.writeln(header('Call def:\t')+self.format(call_def))
545 539 call_ds = getdoc(obj.__call__)
546 540 # Skip Python's auto-generated docstrings
547 541 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
548 542 call_ds = None
549 543 if call_ds:
550 544 out.writeln(header('Call docstring:\n') + indent(call_ds))
551 545
552 546 # Finally send to printer/pager
553 547 output = out.getvalue()
554 548 if output:
555 549 page(output)
556 550 # end pinfo
557 551
558 552 def psearch(self,pattern,ns_table,ns_search=[],
559 553 ignore_case=False,show_all=False):
560 554 """Search namespaces with wildcards for objects.
561 555
562 556 Arguments:
563 557
564 558 - pattern: string containing shell-like wildcards to use in namespace
565 559 searches and optionally a type specification to narrow the search to
566 560 objects of that type.
567 561
568 562 - ns_table: dict of name->namespaces for search.
569 563
570 564 Optional arguments:
571 565
572 566 - ns_search: list of namespace names to include in search.
573 567
574 568 - ignore_case(False): make the search case-insensitive.
575 569
576 570 - show_all(False): show all names, including those starting with
577 571 underscores.
578 572 """
579 573 #print 'ps pattern:<%r>' % pattern # dbg
580 574
581 575 # defaults
582 576 type_pattern = 'all'
583 577 filter = ''
584 578
585 579 cmds = pattern.split()
586 580 len_cmds = len(cmds)
587 581 if len_cmds == 1:
588 582 # Only filter pattern given
589 583 filter = cmds[0]
590 584 elif len_cmds == 2:
591 585 # Both filter and type specified
592 586 filter,type_pattern = cmds
593 587 else:
594 588 raise ValueError('invalid argument string for psearch: <%s>' %
595 589 pattern)
596 590
597 591 # filter search namespaces
598 592 for name in ns_search:
599 593 if name not in ns_table:
600 594 raise ValueError('invalid namespace <%s>. Valid names: %s' %
601 595 (name,ns_table.keys()))
602 596
603 597 #print 'type_pattern:',type_pattern # dbg
604 598 search_result = []
605 599 for ns_name in ns_search:
606 600 ns = ns_table[ns_name]
607 601 tmp_res = list(list_namespace(ns,type_pattern,filter,
608 602 ignore_case=ignore_case,
609 603 show_all=show_all))
610 604 search_result.extend(tmp_res)
611 605 search_result.sort()
612 606
613 607 page('\n'.join(search_result))
@@ -1,263 +1,258 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Class to trap stdout and stderr and log them separately.
3
4 $Id: OutputTrap.py 958 2005-12-27 23:17:51Z fperez $"""
3 """
5 4
6 5 #*****************************************************************************
7 6 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
8 7 #
9 8 # Distributed under the terms of the BSD License. The full license is in
10 9 # the file COPYING, distributed as part of this software.
11 10 #*****************************************************************************
12 11
13 from IPython import Release
14 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __license__ = Release.license
16
17 12 import exceptions
18 13 import sys
19 14 from cStringIO import StringIO
20 15
21 16 class OutputTrapError(exceptions.Exception):
22 17 """Exception for OutputTrap class."""
23 18
24 19 def __init__(self,args=None):
25 20 exceptions.Exception.__init__(self)
26 21 self.args = args
27 22
28 23 class OutputTrap:
29 24
30 25 """Class to trap standard output and standard error. They get logged in
31 26 StringIO objects which are available as <instance>.out and
32 27 <instance>.err. The class also offers summary methods which format this
33 28 data a bit.
34 29
35 30 A word of caution: because it blocks messages, using this class can make
36 31 debugging very tricky. If you are having bizarre problems silently, try
37 32 turning your output traps off for a while. You can call the constructor
38 33 with the parameter debug=1 for these cases. This turns actual trapping
39 34 off, but you can keep the rest of your code unchanged (this has already
40 35 been a life saver).
41 36
42 37 Example:
43 38
44 39 # config: trapper with a line of dots as log separator (final '\\n' needed)
45 40 config = OutputTrap('Config','Out ','Err ','.'*80+'\\n')
46 41
47 42 # start trapping output
48 43 config.trap_all()
49 44
50 45 # now all output is logged ...
51 46 # do stuff...
52 47
53 48 # output back to normal:
54 49 config.release_all()
55 50
56 51 # print all that got logged:
57 52 print config.summary()
58 53
59 54 # print individual raw data:
60 55 print config.out.getvalue()
61 56 print config.err.getvalue()
62 57 """
63 58
64 59 def __init__(self,name='Generic Output Trap',
65 60 out_head='Standard Output. ',err_head='Standard Error. ',
66 61 sum_sep='\n',debug=0,trap_out=0,trap_err=0,
67 62 quiet_out=0,quiet_err=0):
68 63 self.name = name
69 64 self.out_head = out_head
70 65 self.err_head = err_head
71 66 self.sum_sep = sum_sep
72 67 self.out = StringIO()
73 68 self.err = StringIO()
74 69 self.out_save = None
75 70 self.err_save = None
76 71 self.debug = debug
77 72 self.quiet_out = quiet_out
78 73 self.quiet_err = quiet_err
79 74 if trap_out:
80 75 self.trap_out()
81 76 if trap_err:
82 77 self.trap_err()
83 78
84 79 def trap_out(self):
85 80 """Trap and log stdout."""
86 81 if sys.stdout is self.out:
87 82 raise OutputTrapError,'You are already trapping stdout.'
88 83 if not self.debug:
89 84 self._out_save = sys.stdout
90 85 sys.stdout = self.out
91 86
92 87 def release_out(self):
93 88 """Release stdout."""
94 89 if not self.debug:
95 90 if not sys.stdout is self.out:
96 91 raise OutputTrapError,'You are not trapping stdout.'
97 92 sys.stdout = self._out_save
98 93 self.out_save = None
99 94
100 95 def summary_out(self):
101 96 """Return as a string the log from stdout."""
102 97 out = self.out.getvalue()
103 98 if out:
104 99 if self.quiet_out:
105 100 return out
106 101 else:
107 102 return self.out_head + 'Log by '+ self.name + ':\n' + out
108 103 else:
109 104 return ''
110 105
111 106 def flush_out(self):
112 107 """Flush the stdout log. All data held in the log is lost."""
113 108
114 109 self.out.close()
115 110 self.out = StringIO()
116 111
117 112 def trap_err(self):
118 113 """Trap and log stderr."""
119 114 if sys.stderr is self.err:
120 115 raise OutputTrapError,'You are already trapping stderr.'
121 116 if not self.debug:
122 117 self._err_save = sys.stderr
123 118 sys.stderr = self.err
124 119
125 120 def release_err(self):
126 121 """Release stderr."""
127 122 if not self.debug:
128 123 if not sys.stderr is self.err:
129 124 raise OutputTrapError,'You are not trapping stderr.'
130 125 sys.stderr = self._err_save
131 126 self.err_save = None
132 127
133 128 def summary_err(self):
134 129 """Return as a string the log from stderr."""
135 130 err = self.err.getvalue()
136 131 if err:
137 132 if self.quiet_err:
138 133 return err
139 134 else:
140 135 return self.err_head + 'Log by '+ self.name + ':\n' + err
141 136 else:
142 137 return ''
143 138
144 139 def flush_err(self):
145 140 """Flush the stdout log. All data held in the log is lost."""
146 141
147 142 self.err.close()
148 143 self.err = StringIO()
149 144
150 145 def trap_all(self):
151 146 """Trap and log both stdout and stderr.
152 147
153 148 Cacthes and discards OutputTrapError exceptions raised."""
154 149 try:
155 150 self.trap_out()
156 151 except OutputTrapError:
157 152 pass
158 153 try:
159 154 self.trap_err()
160 155 except OutputTrapError:
161 156 pass
162 157
163 158 def release_all(self):
164 159 """Release both stdout and stderr.
165 160
166 161 Cacthes and discards OutputTrapError exceptions raised."""
167 162 try:
168 163 self.release_out()
169 164 except OutputTrapError:
170 165 pass
171 166 try:
172 167 self.release_err()
173 168 except OutputTrapError:
174 169 pass
175 170
176 171 def summary_all(self):
177 172 """Return as a string the log from stdout and stderr, prepending a separator
178 173 to each (defined in __init__ as sum_sep)."""
179 174 sum = ''
180 175 sout = self.summary_out()
181 176 if sout:
182 177 sum += self.sum_sep + sout
183 178 serr = self.summary_err()
184 179 if serr:
185 180 sum += '\n'+self.sum_sep + serr
186 181 return sum
187 182
188 183 def flush_all(self):
189 184 """Flush stdout and stderr"""
190 185 self.flush_out()
191 186 self.flush_err()
192 187
193 188 # a few shorthands
194 189 trap = trap_all
195 190 release = release_all
196 191 summary = summary_all
197 192 flush = flush_all
198 193 # end OutputTrap
199 194
200 195
201 196 #****************************************************************************
202 197 # Module testing. Incomplete, I'm lazy...
203 198
204 199 def _test_all():
205 200
206 201 """Module testing functions, activated when the module is called as a
207 202 script (not imported)."""
208 203
209 204 # Put tests for this module in here.
210 205 # Define them as nested functions so they don't clobber the
211 206 # pydoc-generated docs
212 207
213 208 def _test_():
214 209 name = ''
215 210 print '#'*50+'\nRunning test for ' + name
216 211 # ...
217 212 print 'Finished test for '+ name +'\n'+'#'*50
218 213
219 214 def _test_OutputTrap():
220 215 trap = OutputTrap(name = 'Test Trap', sum_sep = '.'*50+'\n',
221 216 out_head = 'SOut. ', err_head = 'SErr. ')
222 217
223 218 name = 'OutputTrap class'
224 219 print '#'*50+'\nRunning test for ' + name
225 220 print 'Trapping out'
226 221 trap.trap_out()
227 222 print >>sys.stdout, '>>stdout. stdout is trapped.'
228 223 print >>sys.stderr, '>>stderr. stdout is trapped.'
229 224 trap.release_out()
230 225 print trap.summary_out()
231 226
232 227 print 'Trapping err'
233 228 trap.trap_err()
234 229 print >>sys.stdout, '>>stdout. stderr is trapped.'
235 230 print >>sys.stderr, '>>stderr. stderr is trapped.'
236 231 trap.release_err()
237 232 print trap.summary_err()
238 233
239 234 print 'Trapping all (no flushing)'
240 235 trap.trap_all()
241 236 print >>sys.stdout, '>>stdout. stdout/err is trapped.'
242 237 print >>sys.stderr, '>>stderr. stdout/err is trapped.'
243 238 trap.release_all()
244 239 print trap.summary_all()
245 240
246 241 print 'Trapping all (flushing first)'
247 242 trap.flush()
248 243 trap.trap_all()
249 244 print >>sys.stdout, '>>stdout. stdout/err is trapped.'
250 245 print >>sys.stderr, '>>stderr. stdout/err is trapped.'
251 246 trap.release_all()
252 247 print trap.summary_all()
253 248 print 'Finished test for '+ name +'\n'+'#'*50
254 249
255 250 # call the actual tests here:
256 251 _test_OutputTrap()
257 252
258 253
259 254 if __name__=="__main__":
260 255 # _test_all() # XXX BROKEN.
261 256 pass
262 257
263 258 #************************ end of file <OutputTrap.py> ************************
@@ -1,625 +1,624 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Classes for handling input/output prompts.
4
5 $Id: Prompts.py 3026 2008-02-07 16:03:16Z vivainio $"""
4 """
6 5
7 6 #*****************************************************************************
8 7 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 8 #
10 9 # Distributed under the terms of the BSD License. The full license is in
11 10 # the file COPYING, distributed as part of this software.
12 11 #*****************************************************************************
13 12
14 13 from IPython import Release
15 14 __author__ = '%s <%s>' % Release.authors['Fernando']
16 15 __license__ = Release.license
17 16 __version__ = Release.version
18 17
19 18 #****************************************************************************
20 19 # Required modules
21 20 import __builtin__
22 21 import os
23 22 import socket
24 23 import sys
25 24 import time
26 25
27 26 # IPython's own
28 27 from IPython import ColorANSI
29 28 from IPython.Itpl import ItplNS
30 29 from IPython.ipstruct import Struct
31 30 from IPython.macro import Macro
32 31 from IPython.genutils import *
33 32 from IPython.ipapi import TryNext
34 33
35 34 #****************************************************************************
36 35 #Color schemes for Prompts.
37 36
38 37 PromptColors = ColorANSI.ColorSchemeTable()
39 38 InputColors = ColorANSI.InputTermColors # just a shorthand
40 39 Colors = ColorANSI.TermColors # just a shorthand
41 40
42 41 PromptColors.add_scheme(ColorANSI.ColorScheme(
43 42 'NoColor',
44 43 in_prompt = InputColors.NoColor, # Input prompt
45 44 in_number = InputColors.NoColor, # Input prompt number
46 45 in_prompt2 = InputColors.NoColor, # Continuation prompt
47 46 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
48 47
49 48 out_prompt = Colors.NoColor, # Output prompt
50 49 out_number = Colors.NoColor, # Output prompt number
51 50
52 51 normal = Colors.NoColor # color off (usu. Colors.Normal)
53 52 ))
54 53
55 54 # make some schemes as instances so we can copy them for modification easily:
56 55 __PColLinux = ColorANSI.ColorScheme(
57 56 'Linux',
58 57 in_prompt = InputColors.Green,
59 58 in_number = InputColors.LightGreen,
60 59 in_prompt2 = InputColors.Green,
61 60 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
62 61
63 62 out_prompt = Colors.Red,
64 63 out_number = Colors.LightRed,
65 64
66 65 normal = Colors.Normal
67 66 )
68 67 # Don't forget to enter it into the table!
69 68 PromptColors.add_scheme(__PColLinux)
70 69
71 70 # Slightly modified Linux for light backgrounds
72 71 __PColLightBG = __PColLinux.copy('LightBG')
73 72
74 73 __PColLightBG.colors.update(
75 74 in_prompt = InputColors.Blue,
76 75 in_number = InputColors.LightBlue,
77 76 in_prompt2 = InputColors.Blue
78 77 )
79 78 PromptColors.add_scheme(__PColLightBG)
80 79
81 80 del Colors,InputColors
82 81
83 82 #-----------------------------------------------------------------------------
84 83 def multiple_replace(dict, text):
85 84 """ Replace in 'text' all occurences of any key in the given
86 85 dictionary by its corresponding value. Returns the new string."""
87 86
88 87 # Function by Xavier Defrang, originally found at:
89 88 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
90 89
91 90 # Create a regular expression from the dictionary keys
92 91 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
93 92 # For each match, look-up corresponding value in dictionary
94 93 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
95 94
96 95 #-----------------------------------------------------------------------------
97 96 # Special characters that can be used in prompt templates, mainly bash-like
98 97
99 98 # If $HOME isn't defined (Windows), make it an absurd string so that it can
100 99 # never be expanded out into '~'. Basically anything which can never be a
101 100 # reasonable directory name will do, we just want the $HOME -> '~' operation
102 101 # to become a no-op. We pre-compute $HOME here so it's not done on every
103 102 # prompt call.
104 103
105 104 # FIXME:
106 105
107 106 # - This should be turned into a class which does proper namespace management,
108 107 # since the prompt specials need to be evaluated in a certain namespace.
109 108 # Currently it's just globals, which need to be managed manually by code
110 109 # below.
111 110
112 111 # - I also need to split up the color schemes from the prompt specials
113 112 # somehow. I don't have a clean design for that quite yet.
114 113
115 114 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
116 115
117 116 # We precompute a few more strings here for the prompt_specials, which are
118 117 # fixed once ipython starts. This reduces the runtime overhead of computing
119 118 # prompt strings.
120 119 USER = os.environ.get("USER")
121 120 HOSTNAME = socket.gethostname()
122 121 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
123 122 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
124 123
125 124 prompt_specials_color = {
126 125 # Prompt/history count
127 126 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
128 127 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
129 128 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
130 129 # can get numbers displayed in whatever color they want.
131 130 r'\N': '${self.cache.prompt_count}',
132 131 # Prompt/history count, with the actual digits replaced by dots. Used
133 132 # mainly in continuation prompts (prompt_in2)
134 133 r'\D': '${"."*len(str(self.cache.prompt_count))}',
135 134 # Current working directory
136 135 r'\w': '${os.getcwd()}',
137 136 # Current time
138 137 r'\t' : '${time.strftime("%H:%M:%S")}',
139 138 # Basename of current working directory.
140 139 # (use os.sep to make this portable across OSes)
141 140 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
142 141 # These X<N> are an extension to the normal bash prompts. They return
143 142 # N terms of the path, after replacing $HOME with '~'
144 143 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
145 144 r'\X1': '${self.cwd_filt(1)}',
146 145 r'\X2': '${self.cwd_filt(2)}',
147 146 r'\X3': '${self.cwd_filt(3)}',
148 147 r'\X4': '${self.cwd_filt(4)}',
149 148 r'\X5': '${self.cwd_filt(5)}',
150 149 # Y<N> are similar to X<N>, but they show '~' if it's the directory
151 150 # N+1 in the list. Somewhat like %cN in tcsh.
152 151 r'\Y0': '${self.cwd_filt2(0)}',
153 152 r'\Y1': '${self.cwd_filt2(1)}',
154 153 r'\Y2': '${self.cwd_filt2(2)}',
155 154 r'\Y3': '${self.cwd_filt2(3)}',
156 155 r'\Y4': '${self.cwd_filt2(4)}',
157 156 r'\Y5': '${self.cwd_filt2(5)}',
158 157 # Hostname up to first .
159 158 r'\h': HOSTNAME_SHORT,
160 159 # Full hostname
161 160 r'\H': HOSTNAME,
162 161 # Username of current user
163 162 r'\u': USER,
164 163 # Escaped '\'
165 164 '\\\\': '\\',
166 165 # Newline
167 166 r'\n': '\n',
168 167 # Carriage return
169 168 r'\r': '\r',
170 169 # Release version
171 170 r'\v': __version__,
172 171 # Root symbol ($ or #)
173 172 r'\$': ROOT_SYMBOL,
174 173 }
175 174
176 175 # A copy of the prompt_specials dictionary but with all color escapes removed,
177 176 # so we can correctly compute the prompt length for the auto_rewrite method.
178 177 prompt_specials_nocolor = prompt_specials_color.copy()
179 178 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
180 179 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
181 180
182 181 # Add in all the InputTermColors color escapes as valid prompt characters.
183 182 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
184 183 # with a color name which may begin with a letter used by any other of the
185 184 # allowed specials. This of course means that \\C will never be allowed for
186 185 # anything else.
187 186 input_colors = ColorANSI.InputTermColors
188 187 for _color in dir(input_colors):
189 188 if _color[0] != '_':
190 189 c_name = r'\C_'+_color
191 190 prompt_specials_color[c_name] = getattr(input_colors,_color)
192 191 prompt_specials_nocolor[c_name] = ''
193 192
194 193 # we default to no color for safety. Note that prompt_specials is a global
195 194 # variable used by all prompt objects.
196 195 prompt_specials = prompt_specials_nocolor
197 196
198 197 #-----------------------------------------------------------------------------
199 198 def str_safe(arg):
200 199 """Convert to a string, without ever raising an exception.
201 200
202 201 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
203 202 error message."""
204 203
205 204 try:
206 205 out = str(arg)
207 206 except UnicodeError:
208 207 try:
209 208 out = arg.encode('utf_8','replace')
210 209 except Exception,msg:
211 210 # let's keep this little duplication here, so that the most common
212 211 # case doesn't suffer from a double try wrapping.
213 212 out = '<ERROR: %s>' % msg
214 213 except Exception,msg:
215 214 out = '<ERROR: %s>' % msg
216 215 return out
217 216
218 217 class BasePrompt(object):
219 218 """Interactive prompt similar to Mathematica's."""
220 219
221 220 def _get_p_template(self):
222 221 return self._p_template
223 222
224 223 def _set_p_template(self,val):
225 224 self._p_template = val
226 225 self.set_p_str()
227 226
228 227 p_template = property(_get_p_template,_set_p_template,
229 228 doc='Template for prompt string creation')
230 229
231 230 def __init__(self,cache,sep,prompt,pad_left=False):
232 231
233 232 # Hack: we access information about the primary prompt through the
234 233 # cache argument. We need this, because we want the secondary prompt
235 234 # to be aligned with the primary one. Color table info is also shared
236 235 # by all prompt classes through the cache. Nice OO spaghetti code!
237 236 self.cache = cache
238 237 self.sep = sep
239 238
240 239 # regexp to count the number of spaces at the end of a prompt
241 240 # expression, useful for prompt auto-rewriting
242 241 self.rspace = re.compile(r'(\s*)$')
243 242 # Flag to left-pad prompt strings to match the length of the primary
244 243 # prompt
245 244 self.pad_left = pad_left
246 245
247 246 # Set template to create each actual prompt (where numbers change).
248 247 # Use a property
249 248 self.p_template = prompt
250 249 self.set_p_str()
251 250
252 251 def set_p_str(self):
253 252 """ Set the interpolating prompt strings.
254 253
255 254 This must be called every time the color settings change, because the
256 255 prompt_specials global may have changed."""
257 256
258 257 import os,time # needed in locals for prompt string handling
259 258 loc = locals()
260 259 try:
261 260 self.p_str = ItplNS('%s%s%s' %
262 261 ('${self.sep}${self.col_p}',
263 262 multiple_replace(prompt_specials, self.p_template),
264 263 '${self.col_norm}'),self.cache.user_ns,loc)
265 264
266 265 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
267 266 self.p_template),
268 267 self.cache.user_ns,loc)
269 268 except:
270 269 print "Illegal prompt template (check $ usage!):",self.p_template
271 270 self.p_str = self.p_template
272 271 self.p_str_nocolor = self.p_template
273 272
274 273 def write(self,msg): # dbg
275 274 sys.stdout.write(msg)
276 275 return ''
277 276
278 277 def __str__(self):
279 278 """Return a string form of the prompt.
280 279
281 280 This for is useful for continuation and output prompts, since it is
282 281 left-padded to match lengths with the primary one (if the
283 282 self.pad_left attribute is set)."""
284 283
285 284 out_str = str_safe(self.p_str)
286 285 if self.pad_left:
287 286 # We must find the amount of padding required to match lengths,
288 287 # taking the color escapes (which are invisible on-screen) into
289 288 # account.
290 289 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
291 290 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
292 291 return format % out_str
293 292 else:
294 293 return out_str
295 294
296 295 # these path filters are put in as methods so that we can control the
297 296 # namespace where the prompt strings get evaluated
298 297 def cwd_filt(self,depth):
299 298 """Return the last depth elements of the current working directory.
300 299
301 300 $HOME is always replaced with '~'.
302 301 If depth==0, the full path is returned."""
303 302
304 303 cwd = os.getcwd().replace(HOME,"~")
305 304 out = os.sep.join(cwd.split(os.sep)[-depth:])
306 305 if out:
307 306 return out
308 307 else:
309 308 return os.sep
310 309
311 310 def cwd_filt2(self,depth):
312 311 """Return the last depth elements of the current working directory.
313 312
314 313 $HOME is always replaced with '~'.
315 314 If depth==0, the full path is returned."""
316 315
317 316 full_cwd = os.getcwd()
318 317 cwd = full_cwd.replace(HOME,"~").split(os.sep)
319 318 if '~' in cwd and len(cwd) == depth+1:
320 319 depth += 1
321 320 drivepart = ''
322 321 if sys.platform == 'win32' and len(cwd) > depth:
323 322 drivepart = os.path.splitdrive(full_cwd)[0]
324 323 out = drivepart + '/'.join(cwd[-depth:])
325 324
326 325 if out:
327 326 return out
328 327 else:
329 328 return os.sep
330 329
331 330 def __nonzero__(self):
332 331 """Implement boolean behavior.
333 332
334 333 Checks whether the p_str attribute is non-empty"""
335 334
336 335 return bool(self.p_template)
337 336
338 337 class Prompt1(BasePrompt):
339 338 """Input interactive prompt similar to Mathematica's."""
340 339
341 340 def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
342 341 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
343 342
344 343 def set_colors(self):
345 344 self.set_p_str()
346 345 Colors = self.cache.color_table.active_colors # shorthand
347 346 self.col_p = Colors.in_prompt
348 347 self.col_num = Colors.in_number
349 348 self.col_norm = Colors.in_normal
350 349 # We need a non-input version of these escapes for the '--->'
351 350 # auto-call prompts used in the auto_rewrite() method.
352 351 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
353 352 self.col_norm_ni = Colors.normal
354 353
355 354 def __str__(self):
356 355 self.cache.prompt_count += 1
357 356 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
358 357 return str_safe(self.p_str)
359 358
360 359 def auto_rewrite(self):
361 360 """Print a string of the form '--->' which lines up with the previous
362 361 input string. Useful for systems which re-write the user input when
363 362 handling automatically special syntaxes."""
364 363
365 364 curr = str(self.cache.last_prompt)
366 365 nrspaces = len(self.rspace.search(curr).group())
367 366 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
368 367 ' '*nrspaces,self.col_norm_ni)
369 368
370 369 class PromptOut(BasePrompt):
371 370 """Output interactive prompt similar to Mathematica's."""
372 371
373 372 def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
374 373 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
375 374 if not self.p_template:
376 375 self.__str__ = lambda: ''
377 376
378 377 def set_colors(self):
379 378 self.set_p_str()
380 379 Colors = self.cache.color_table.active_colors # shorthand
381 380 self.col_p = Colors.out_prompt
382 381 self.col_num = Colors.out_number
383 382 self.col_norm = Colors.normal
384 383
385 384 class Prompt2(BasePrompt):
386 385 """Interactive continuation prompt."""
387 386
388 387 def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
389 388 self.cache = cache
390 389 self.p_template = prompt
391 390 self.pad_left = pad_left
392 391 self.set_p_str()
393 392
394 393 def set_p_str(self):
395 394 import os,time # needed in locals for prompt string handling
396 395 loc = locals()
397 396 self.p_str = ItplNS('%s%s%s' %
398 397 ('${self.col_p2}',
399 398 multiple_replace(prompt_specials, self.p_template),
400 399 '$self.col_norm'),
401 400 self.cache.user_ns,loc)
402 401 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
403 402 self.p_template),
404 403 self.cache.user_ns,loc)
405 404
406 405 def set_colors(self):
407 406 self.set_p_str()
408 407 Colors = self.cache.color_table.active_colors
409 408 self.col_p2 = Colors.in_prompt2
410 409 self.col_norm = Colors.in_normal
411 410 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
412 411 # updated their prompt_in2 definitions. Remove eventually.
413 412 self.col_p = Colors.out_prompt
414 413 self.col_num = Colors.out_number
415 414
416 415
417 416 #-----------------------------------------------------------------------------
418 417 class CachedOutput:
419 418 """Class for printing output from calculations while keeping a cache of
420 419 reults. It dynamically creates global variables prefixed with _ which
421 420 contain these results.
422 421
423 422 Meant to be used as a sys.displayhook replacement, providing numbered
424 423 prompts and cache services.
425 424
426 425 Initialize with initial and final values for cache counter (this defines
427 426 the maximum size of the cache."""
428 427
429 428 def __init__(self,shell,cache_size,Pprint,
430 429 colors='NoColor',input_sep='\n',
431 430 output_sep='\n',output_sep2='',
432 431 ps1 = None, ps2 = None,ps_out = None,pad_left=True):
433 432
434 433 cache_size_min = 3
435 434 if cache_size <= 0:
436 435 self.do_full_cache = 0
437 436 cache_size = 0
438 437 elif cache_size < cache_size_min:
439 438 self.do_full_cache = 0
440 439 cache_size = 0
441 440 warn('caching was disabled (min value for cache size is %s).' %
442 441 cache_size_min,level=3)
443 442 else:
444 443 self.do_full_cache = 1
445 444
446 445 self.cache_size = cache_size
447 446 self.input_sep = input_sep
448 447
449 448 # we need a reference to the user-level namespace
450 449 self.shell = shell
451 450 self.user_ns = shell.user_ns
452 451 # and to the user's input
453 452 self.input_hist = shell.input_hist
454 453 # and to the user's logger, for logging output
455 454 self.logger = shell.logger
456 455
457 456 # Set input prompt strings and colors
458 457 if cache_size == 0:
459 458 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
460 459 or ps1.find(r'\N') > -1:
461 460 ps1 = '>>> '
462 461 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
463 462 or ps2.find(r'\N') > -1:
464 463 ps2 = '... '
465 464 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
466 465 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
467 466 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
468 467
469 468 self.color_table = PromptColors
470 469 self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
471 470 pad_left=pad_left)
472 471 self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
473 472 self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
474 473 pad_left=pad_left)
475 474 self.set_colors(colors)
476 475
477 476 # other more normal stuff
478 477 # b/c each call to the In[] prompt raises it by 1, even the first.
479 478 self.prompt_count = 0
480 479 # Store the last prompt string each time, we need it for aligning
481 480 # continuation and auto-rewrite prompts
482 481 self.last_prompt = ''
483 482 self.Pprint = Pprint
484 483 self.output_sep = output_sep
485 484 self.output_sep2 = output_sep2
486 485 self._,self.__,self.___ = '','',''
487 486 self.pprint_types = map(type,[(),[],{}])
488 487
489 488 # these are deliberately global:
490 489 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
491 490 self.user_ns.update(to_user_ns)
492 491
493 492 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
494 493 if p_str is None:
495 494 if self.do_full_cache:
496 495 return cache_def
497 496 else:
498 497 return no_cache_def
499 498 else:
500 499 return p_str
501 500
502 501 def set_colors(self,colors):
503 502 """Set the active color scheme and configure colors for the three
504 503 prompt subsystems."""
505 504
506 505 # FIXME: the prompt_specials global should be gobbled inside this
507 506 # class instead. Do it when cleaning up the whole 3-prompt system.
508 507 global prompt_specials
509 508 if colors.lower()=='nocolor':
510 509 prompt_specials = prompt_specials_nocolor
511 510 else:
512 511 prompt_specials = prompt_specials_color
513 512
514 513 self.color_table.set_active_scheme(colors)
515 514 self.prompt1.set_colors()
516 515 self.prompt2.set_colors()
517 516 self.prompt_out.set_colors()
518 517
519 518 def __call__(self,arg=None):
520 519 """Printing with history cache management.
521 520
522 521 This is invoked everytime the interpreter needs to print, and is
523 522 activated by setting the variable sys.displayhook to it."""
524 523
525 524 # If something injected a '_' variable in __builtin__, delete
526 525 # ipython's automatic one so we don't clobber that. gettext() in
527 526 # particular uses _, so we need to stay away from it.
528 527 if '_' in __builtin__.__dict__:
529 528 try:
530 529 del self.user_ns['_']
531 530 except KeyError:
532 531 pass
533 532 if arg is not None:
534 533 cout_write = Term.cout.write # fast lookup
535 534 # first handle the cache and counters
536 535
537 536 # do not print output if input ends in ';'
538 537 try:
539 538 if self.input_hist[self.prompt_count].endswith(';\n'):
540 539 return
541 540 except IndexError:
542 541 # some uses of ipshellembed may fail here
543 542 pass
544 543 # don't use print, puts an extra space
545 544 cout_write(self.output_sep)
546 545 outprompt = self.shell.hooks.generate_output_prompt()
547 546 if self.do_full_cache:
548 547 cout_write(outprompt)
549 548
550 549 # and now call a possibly user-defined print mechanism
551 550 manipulated_val = self.display(arg)
552 551
553 552 # user display hooks can change the variable to be stored in
554 553 # output history
555 554
556 555 if manipulated_val is not None:
557 556 arg = manipulated_val
558 557
559 558 # avoid recursive reference when displaying _oh/Out
560 559 if arg is not self.user_ns['_oh']:
561 560 self.update(arg)
562 561
563 562 if self.logger.log_output:
564 563 self.logger.log_write(repr(arg),'output')
565 564 cout_write(self.output_sep2)
566 565 Term.cout.flush()
567 566
568 567 def _display(self,arg):
569 568 """Default printer method, uses pprint.
570 569
571 570 Do ip.set_hook("result_display", my_displayhook) for custom result
572 571 display, e.g. when your own objects need special formatting.
573 572 """
574 573 try:
575 574 return IPython.generics.result_display(arg)
576 575 except TryNext:
577 576 return self.shell.hooks.result_display(arg)
578 577
579 578 # Assign the default display method:
580 579 display = _display
581 580
582 581 def update(self,arg):
583 582 #print '***cache_count', self.cache_count # dbg
584 583 if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
585 584 warn('Output cache limit (currently '+
586 585 `self.cache_size`+' entries) hit.\n'
587 586 'Flushing cache and resetting history counter...\n'
588 587 'The only history variables available will be _,__,___ and _1\n'
589 588 'with the current result.')
590 589
591 590 self.flush()
592 591 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
593 592 # we cause buggy behavior for things like gettext).
594 593 if '_' not in __builtin__.__dict__:
595 594 self.___ = self.__
596 595 self.__ = self._
597 596 self._ = arg
598 597 self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
599 598
600 599 # hackish access to top-level namespace to create _1,_2... dynamically
601 600 to_main = {}
602 601 if self.do_full_cache:
603 602 new_result = '_'+`self.prompt_count`
604 603 to_main[new_result] = arg
605 604 self.user_ns.update(to_main)
606 605 self.user_ns['_oh'][self.prompt_count] = arg
607 606
608 607 def flush(self):
609 608 if not self.do_full_cache:
610 609 raise ValueError,"You shouldn't have reached the cache flush "\
611 610 "if full caching is not enabled!"
612 611 # delete auto-generated vars from global namespace
613 612
614 613 for n in range(1,self.prompt_count + 1):
615 614 key = '_'+`n`
616 615 try:
617 616 del self.user_ns[key]
618 617 except: pass
619 618 self.user_ns['_oh'].clear()
620 619
621 620 if '_' not in __builtin__.__dict__:
622 621 self.user_ns.update({'_':None,'__':None, '___':None})
623 622 import gc
624 623 gc.collect() # xxx needed?
625 624
@@ -1,301 +1,300 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 Class and program to colorize python source code for ANSI terminals.
3 Class and program to colorize python source code for ANSI terminals.
4 4
5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7 7
8 Modifications by Fernando Perez (fperez@colorado.edu).
8 Modifications by Fernando Perez (fperez@colorado.edu).
9 9
10 Information on the original HTML highlighter follows:
11
12 MoinMoin - Python Source Parser
10 Information on the original HTML highlighter follows:
13 11
14 Title: Colorize Python source using the built-in tokenizer
15
16 Submitter: Jurgen Hermann
17 Last Updated:2001/04/06
18
19 Version no:1.2
12 MoinMoin - Python Source Parser
20 13
21 Description:
14 Title: Colorize Python source using the built-in tokenizer
22 15
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 Python source code to HTML markup, rendering comments, keywords,
25 operators, numeric and string literals in different colors.
16 Submitter: Jurgen Hermann
17 Last Updated:2001/04/06
26 18
27 It shows how to use the built-in keyword, token and tokenize modules to
28 scan Python source code and re-emit it with no changes to its original
29 formatting (which is the hard part).
19 Version no:1.2
30 20
31 $Id: PyColorize.py 2586 2007-08-06 19:30:09Z vivainio $"""
21 Description:
22
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 Python source code to HTML markup, rendering comments, keywords,
25 operators, numeric and string literals in different colors.
26
27 It shows how to use the built-in keyword, token and tokenize modules to
28 scan Python source code and re-emit it with no changes to its original
29 formatting (which is the hard part).
30 """
32 31
33 32 __all__ = ['ANSICodeColors','Parser']
34 33
35 34 _scheme_default = 'Linux'
36 35
37 36 # Imports
38 37 import cStringIO
39 38 import keyword
40 39 import os
41 40 import optparse
42 41 import string
43 42 import sys
44 43 import token
45 44 import tokenize
46 45
47 46 from IPython.ColorANSI import *
48 47
49 48 #############################################################################
50 49 ### Python Source Parser (does Hilighting)
51 50 #############################################################################
52 51
53 52 _KEYWORD = token.NT_OFFSET + 1
54 53 _TEXT = token.NT_OFFSET + 2
55 54
56 55 #****************************************************************************
57 56 # Builtin color schemes
58 57
59 58 Colors = TermColors # just a shorthand
60 59
61 60 # Build a few color schemes
62 61 NoColor = ColorScheme(
63 62 'NoColor',{
64 63 token.NUMBER : Colors.NoColor,
65 64 token.OP : Colors.NoColor,
66 65 token.STRING : Colors.NoColor,
67 66 tokenize.COMMENT : Colors.NoColor,
68 67 token.NAME : Colors.NoColor,
69 68 token.ERRORTOKEN : Colors.NoColor,
70 69
71 70 _KEYWORD : Colors.NoColor,
72 71 _TEXT : Colors.NoColor,
73 72
74 73 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
75 74 } )
76 75
77 76 LinuxColors = ColorScheme(
78 77 'Linux',{
79 78 token.NUMBER : Colors.LightCyan,
80 79 token.OP : Colors.Yellow,
81 80 token.STRING : Colors.LightBlue,
82 81 tokenize.COMMENT : Colors.LightRed,
83 82 token.NAME : Colors.White,
84 83 token.ERRORTOKEN : Colors.Red,
85 84
86 85 _KEYWORD : Colors.LightGreen,
87 86 _TEXT : Colors.Yellow,
88 87
89 88 'normal' : Colors.Normal # color off (usu. Colors.Normal)
90 89 } )
91 90
92 91 LightBGColors = ColorScheme(
93 92 'LightBG',{
94 93 token.NUMBER : Colors.Cyan,
95 94 token.OP : Colors.Blue,
96 95 token.STRING : Colors.Blue,
97 96 tokenize.COMMENT : Colors.Red,
98 97 token.NAME : Colors.Black,
99 98 token.ERRORTOKEN : Colors.Red,
100 99
101 100 _KEYWORD : Colors.Green,
102 101 _TEXT : Colors.Blue,
103 102
104 103 'normal' : Colors.Normal # color off (usu. Colors.Normal)
105 104 } )
106 105
107 106 # Build table of color schemes (needed by the parser)
108 107 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
109 108 _scheme_default)
110 109
111 110 class Parser:
112 111 """ Format colored Python source.
113 112 """
114 113
115 114 def __init__(self, color_table=None,out = sys.stdout):
116 115 """ Create a parser with a specified color table and output channel.
117 116
118 117 Call format() to process code.
119 118 """
120 119 self.color_table = color_table and color_table or ANSICodeColors
121 120 self.out = out
122 121
123 122 def format(self, raw, out = None, scheme = ''):
124 123 return self.format2(raw, out, scheme)[0]
125 124
126 125 def format2(self, raw, out = None, scheme = ''):
127 126 """ Parse and send the colored source.
128 127
129 128 If out and scheme are not specified, the defaults (given to
130 129 constructor) are used.
131 130
132 131 out should be a file-type object. Optionally, out can be given as the
133 132 string 'str' and the parser will automatically return the output in a
134 133 string."""
135 134
136 135 string_output = 0
137 136 if out == 'str' or self.out == 'str' or \
138 137 isinstance(self.out,cStringIO.OutputType):
139 138 # XXX - I don't really like this state handling logic, but at this
140 139 # point I don't want to make major changes, so adding the
141 140 # isinstance() check is the simplest I can do to ensure correct
142 141 # behavior.
143 142 out_old = self.out
144 143 self.out = cStringIO.StringIO()
145 144 string_output = 1
146 145 elif out is not None:
147 146 self.out = out
148 147
149 148 # Fast return of the unmodified input for NoColor scheme
150 149 if scheme == 'NoColor':
151 150 error = False
152 151 self.out.write(raw)
153 152 if string_output:
154 153 return raw,error
155 154 else:
156 155 return None,error
157 156
158 157 # local shorthands
159 158 colors = self.color_table[scheme].colors
160 159 self.colors = colors # put in object so __call__ sees it
161 160
162 161 # Remove trailing whitespace and normalize tabs
163 162 self.raw = raw.expandtabs().rstrip()
164 163
165 164 # store line offsets in self.lines
166 165 self.lines = [0, 0]
167 166 pos = 0
168 167 raw_find = self.raw.find
169 168 lines_append = self.lines.append
170 169 while 1:
171 170 pos = raw_find('\n', pos) + 1
172 171 if not pos: break
173 172 lines_append(pos)
174 173 lines_append(len(self.raw))
175 174
176 175 # parse the source and write it
177 176 self.pos = 0
178 177 text = cStringIO.StringIO(self.raw)
179 178
180 179 error = False
181 180 try:
182 181 tokenize.tokenize(text.readline, self)
183 182 except tokenize.TokenError, ex:
184 183 msg = ex[0]
185 184 line = ex[1][0]
186 185 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
187 186 (colors[token.ERRORTOKEN],
188 187 msg, self.raw[self.lines[line]:],
189 188 colors.normal)
190 189 )
191 190 error = True
192 191 self.out.write(colors.normal+'\n')
193 192 if string_output:
194 193 output = self.out.getvalue()
195 194 self.out = out_old
196 195 return (output, error)
197 196 return (None, error)
198 197
199 198 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
200 199 """ Token handler, with syntax highlighting."""
201 200
202 201 # local shorthands
203 202 colors = self.colors
204 203 owrite = self.out.write
205 204
206 205 # line separator, so this works across platforms
207 206 linesep = os.linesep
208 207
209 208 # calculate new positions
210 209 oldpos = self.pos
211 210 newpos = self.lines[srow] + scol
212 211 self.pos = newpos + len(toktext)
213 212
214 213 # handle newlines
215 214 if toktype in [token.NEWLINE, tokenize.NL]:
216 215 owrite(linesep)
217 216 return
218 217
219 218 # send the original whitespace, if needed
220 219 if newpos > oldpos:
221 220 owrite(self.raw[oldpos:newpos])
222 221
223 222 # skip indenting tokens
224 223 if toktype in [token.INDENT, token.DEDENT]:
225 224 self.pos = newpos
226 225 return
227 226
228 227 # map token type to a color group
229 228 if token.LPAR <= toktype and toktype <= token.OP:
230 229 toktype = token.OP
231 230 elif toktype == token.NAME and keyword.iskeyword(toktext):
232 231 toktype = _KEYWORD
233 232 color = colors.get(toktype, colors[_TEXT])
234 233
235 234 #print '<%s>' % toktext, # dbg
236 235
237 236 # Triple quoted strings must be handled carefully so that backtracking
238 237 # in pagers works correctly. We need color terminators on _each_ line.
239 238 if linesep in toktext:
240 239 toktext = toktext.replace(linesep, '%s%s%s' %
241 240 (colors.normal,linesep,color))
242 241
243 242 # send text
244 243 owrite('%s%s%s' % (color,toktext,colors.normal))
245 244
246 245 def main(argv=None):
247 246 """Run as a command-line script: colorize a python file or stdin using ANSI
248 247 color escapes and print to stdout.
249 248
250 249 Inputs:
251 250
252 251 - argv(None): a list of strings like sys.argv[1:] giving the command-line
253 252 arguments. If None, use sys.argv[1:].
254 253 """
255 254
256 255 usage_msg = """%prog [options] [filename]
257 256
258 257 Colorize a python file or stdin using ANSI color escapes and print to stdout.
259 258 If no filename is given, or if filename is -, read standard input."""
260 259
261 260 parser = optparse.OptionParser(usage=usage_msg)
262 261 newopt = parser.add_option
263 262 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
264 263 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
265 264 help="give the color scheme to use. Currently only 'Linux'\
266 265 (default) and 'LightBG' and 'NoColor' are implemented (give without\
267 266 quotes)")
268 267
269 268 opts,args = parser.parse_args(argv)
270 269
271 270 if len(args) > 1:
272 271 parser.error("you must give at most one filename.")
273 272
274 273 if len(args) == 0:
275 274 fname = '-' # no filename given; setup to read from stdin
276 275 else:
277 276 fname = args[0]
278 277
279 278 if fname == '-':
280 279 stream = sys.stdin
281 280 else:
282 281 stream = file(fname)
283 282
284 283 parser = Parser()
285 284
286 285 # we need nested try blocks because pre-2.5 python doesn't support unified
287 286 # try-except-finally
288 287 try:
289 288 try:
290 289 # write colorized version to stdout
291 290 parser.format(stream.read(),scheme=opts.scheme_name)
292 291 except IOError,msg:
293 292 # if user reads through a pager and quits, don't print traceback
294 293 if msg.args != (32,'Broken pipe'):
295 294 raise
296 295 finally:
297 296 if stream is not sys.stdin:
298 297 stream.close() # in case a non-handled exception happened above
299 298
300 299 if __name__ == "__main__":
301 300 main()
@@ -1,1238 +1,1233 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Shell classes.
3 3
4 4 All the matplotlib support code was co-developed with John Hunter,
5 5 matplotlib's author.
6
7 $Id: Shell.py 3024 2008-02-07 15:34:42Z darren.dale $"""
6 """
8 7
9 8 #*****************************************************************************
10 9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
11 10 #
12 11 # Distributed under the terms of the BSD License. The full license is in
13 12 # the file COPYING, distributed as part of this software.
14 13 #*****************************************************************************
15 14
16 from IPython import Release
17 __author__ = '%s <%s>' % Release.authors['Fernando']
18 __license__ = Release.license
19
20 15 # Code begins
21 16 # Stdlib imports
22 17 import __builtin__
23 18 import __main__
24 19 import Queue
25 20 import inspect
26 21 import os
27 22 import sys
28 23 import thread
29 24 import threading
30 25 import time
31 26
32 27 from signal import signal, SIGINT
33 28
34 29 try:
35 30 import ctypes
36 31 HAS_CTYPES = True
37 32 except ImportError:
38 33 HAS_CTYPES = False
39 34
40 35 # IPython imports
41 36 import IPython
42 37 from IPython import ultraTB, ipapi
43 38 from IPython.Magic import Magic
44 39 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
45 40 from IPython.iplib import InteractiveShell
46 41 from IPython.ipmaker import make_IPython
47 42 from IPython.ipstruct import Struct
48 43 from IPython.testing import decorators as testdec
49 44
50 45 # Globals
51 46 # global flag to pass around information about Ctrl-C without exceptions
52 47 KBINT = False
53 48
54 49 # global flag to turn on/off Tk support.
55 50 USE_TK = False
56 51
57 52 # ID for the main thread, used for cross-thread exceptions
58 53 MAIN_THREAD_ID = thread.get_ident()
59 54
60 55 # Tag when runcode() is active, for exception handling
61 56 CODE_RUN = None
62 57
63 58 # Default timeout for waiting for multithreaded shells (in seconds)
64 59 GUI_TIMEOUT = 10
65 60
66 61 #-----------------------------------------------------------------------------
67 62 # This class is trivial now, but I want to have it in to publish a clean
68 63 # interface. Later when the internals are reorganized, code that uses this
69 64 # shouldn't have to change.
70 65
71 66 class IPShell:
72 67 """Create an IPython instance."""
73 68
74 69 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
75 70 debug=1,shell_class=InteractiveShell):
76 71 self.IP = make_IPython(argv,user_ns=user_ns,
77 72 user_global_ns=user_global_ns,
78 73 debug=debug,shell_class=shell_class)
79 74
80 75 def mainloop(self,sys_exit=0,banner=None):
81 76 self.IP.mainloop(banner)
82 77 if sys_exit:
83 78 sys.exit()
84 79
85 80 #-----------------------------------------------------------------------------
86 81 def kill_embedded(self,parameter_s=''):
87 82 """%kill_embedded : deactivate for good the current embedded IPython.
88 83
89 84 This function (after asking for confirmation) sets an internal flag so that
90 85 an embedded IPython will never activate again. This is useful to
91 86 permanently disable a shell that is being called inside a loop: once you've
92 87 figured out what you needed from it, you may then kill it and the program
93 88 will then continue to run without the interactive shell interfering again.
94 89 """
95 90
96 91 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
97 92 "(y/n)? [y/N] ",'n')
98 93 if kill:
99 94 self.shell.embedded_active = False
100 95 print "This embedded IPython will not reactivate anymore once you exit."
101 96
102 97 class IPShellEmbed:
103 98 """Allow embedding an IPython shell into a running program.
104 99
105 100 Instances of this class are callable, with the __call__ method being an
106 101 alias to the embed() method of an InteractiveShell instance.
107 102
108 103 Usage (see also the example-embed.py file for a running example):
109 104
110 105 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
111 106
112 107 - argv: list containing valid command-line options for IPython, as they
113 108 would appear in sys.argv[1:].
114 109
115 110 For example, the following command-line options:
116 111
117 112 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
118 113
119 114 would be passed in the argv list as:
120 115
121 116 ['-prompt_in1','Input <\\#>','-colors','LightBG']
122 117
123 118 - banner: string which gets printed every time the interpreter starts.
124 119
125 120 - exit_msg: string which gets printed every time the interpreter exits.
126 121
127 122 - rc_override: a dict or Struct of configuration options such as those
128 123 used by IPython. These options are read from your ~/.ipython/ipythonrc
129 124 file when the Shell object is created. Passing an explicit rc_override
130 125 dict with any options you want allows you to override those values at
131 126 creation time without having to modify the file. This way you can create
132 127 embeddable instances configured in any way you want without editing any
133 128 global files (thus keeping your interactive IPython configuration
134 129 unchanged).
135 130
136 131 Then the ipshell instance can be called anywhere inside your code:
137 132
138 133 ipshell(header='') -> Opens up an IPython shell.
139 134
140 135 - header: string printed by the IPython shell upon startup. This can let
141 136 you know where in your code you are when dropping into the shell. Note
142 137 that 'banner' gets prepended to all calls, so header is used for
143 138 location-specific information.
144 139
145 140 For more details, see the __call__ method below.
146 141
147 142 When the IPython shell is exited with Ctrl-D, normal program execution
148 143 resumes.
149 144
150 145 This functionality was inspired by a posting on comp.lang.python by cmkl
151 146 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
152 147 by the IDL stop/continue commands."""
153 148
154 149 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
155 150 user_ns=None):
156 151 """Note that argv here is a string, NOT a list."""
157 152 self.set_banner(banner)
158 153 self.set_exit_msg(exit_msg)
159 154 self.set_dummy_mode(0)
160 155
161 156 # sys.displayhook is a global, we need to save the user's original
162 157 # Don't rely on __displayhook__, as the user may have changed that.
163 158 self.sys_displayhook_ori = sys.displayhook
164 159
165 160 # save readline completer status
166 161 try:
167 162 #print 'Save completer',sys.ipcompleter # dbg
168 163 self.sys_ipcompleter_ori = sys.ipcompleter
169 164 except:
170 165 pass # not nested with IPython
171 166
172 167 self.IP = make_IPython(argv,rc_override=rc_override,
173 168 embedded=True,
174 169 user_ns=user_ns)
175 170
176 171 ip = ipapi.IPApi(self.IP)
177 172 ip.expose_magic("kill_embedded",kill_embedded)
178 173
179 174 # copy our own displayhook also
180 175 self.sys_displayhook_embed = sys.displayhook
181 176 # and leave the system's display hook clean
182 177 sys.displayhook = self.sys_displayhook_ori
183 178 # don't use the ipython crash handler so that user exceptions aren't
184 179 # trapped
185 180 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
186 181 mode = self.IP.rc.xmode,
187 182 call_pdb = self.IP.rc.pdb)
188 183 self.restore_system_completer()
189 184
190 185 def restore_system_completer(self):
191 186 """Restores the readline completer which was in place.
192 187
193 188 This allows embedded IPython within IPython not to disrupt the
194 189 parent's completion.
195 190 """
196 191
197 192 try:
198 193 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
199 194 sys.ipcompleter = self.sys_ipcompleter_ori
200 195 except:
201 196 pass
202 197
203 198 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
204 199 """Activate the interactive interpreter.
205 200
206 201 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
207 202 the interpreter shell with the given local and global namespaces, and
208 203 optionally print a header string at startup.
209 204
210 205 The shell can be globally activated/deactivated using the
211 206 set/get_dummy_mode methods. This allows you to turn off a shell used
212 207 for debugging globally.
213 208
214 209 However, *each* time you call the shell you can override the current
215 210 state of dummy_mode with the optional keyword parameter 'dummy'. For
216 211 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
217 212 can still have a specific call work by making it as IPShell(dummy=0).
218 213
219 214 The optional keyword parameter dummy controls whether the call
220 215 actually does anything. """
221 216
222 217 # If the user has turned it off, go away
223 218 if not self.IP.embedded_active:
224 219 return
225 220
226 221 # Normal exits from interactive mode set this flag, so the shell can't
227 222 # re-enter (it checks this variable at the start of interactive mode).
228 223 self.IP.exit_now = False
229 224
230 225 # Allow the dummy parameter to override the global __dummy_mode
231 226 if dummy or (dummy != 0 and self.__dummy_mode):
232 227 return
233 228
234 229 # Set global subsystems (display,completions) to our values
235 230 sys.displayhook = self.sys_displayhook_embed
236 231 if self.IP.has_readline:
237 232 self.IP.set_completer()
238 233
239 234 if self.banner and header:
240 235 format = '%s\n%s\n'
241 236 else:
242 237 format = '%s%s\n'
243 238 banner = format % (self.banner,header)
244 239
245 240 # Call the embedding code with a stack depth of 1 so it can skip over
246 241 # our call and get the original caller's namespaces.
247 242 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
248 243
249 244 if self.exit_msg:
250 245 print self.exit_msg
251 246
252 247 # Restore global systems (display, completion)
253 248 sys.displayhook = self.sys_displayhook_ori
254 249 self.restore_system_completer()
255 250
256 251 def set_dummy_mode(self,dummy):
257 252 """Sets the embeddable shell's dummy mode parameter.
258 253
259 254 set_dummy_mode(dummy): dummy = 0 or 1.
260 255
261 256 This parameter is persistent and makes calls to the embeddable shell
262 257 silently return without performing any action. This allows you to
263 258 globally activate or deactivate a shell you're using with a single call.
264 259
265 260 If you need to manually"""
266 261
267 262 if dummy not in [0,1,False,True]:
268 263 raise ValueError,'dummy parameter must be boolean'
269 264 self.__dummy_mode = dummy
270 265
271 266 def get_dummy_mode(self):
272 267 """Return the current value of the dummy mode parameter.
273 268 """
274 269 return self.__dummy_mode
275 270
276 271 def set_banner(self,banner):
277 272 """Sets the global banner.
278 273
279 274 This banner gets prepended to every header printed when the shell
280 275 instance is called."""
281 276
282 277 self.banner = banner
283 278
284 279 def set_exit_msg(self,exit_msg):
285 280 """Sets the global exit_msg.
286 281
287 282 This exit message gets printed upon exiting every time the embedded
288 283 shell is called. It is None by default. """
289 284
290 285 self.exit_msg = exit_msg
291 286
292 287 #-----------------------------------------------------------------------------
293 288 if HAS_CTYPES:
294 289 # Add async exception support. Trick taken from:
295 290 # http://sebulba.wikispaces.com/recipe+thread2
296 291 def _async_raise(tid, exctype):
297 292 """raises the exception, performs cleanup if needed"""
298 293 if not inspect.isclass(exctype):
299 294 raise TypeError("Only types can be raised (not instances)")
300 295 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
301 296 ctypes.py_object(exctype))
302 297 if res == 0:
303 298 raise ValueError("invalid thread id")
304 299 elif res != 1:
305 300 # """if it returns a number greater than one, you're in trouble,
306 301 # and you should call it again with exc=NULL to revert the effect"""
307 302 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
308 303 raise SystemError("PyThreadState_SetAsyncExc failed")
309 304
310 305 def sigint_handler (signum,stack_frame):
311 306 """Sigint handler for threaded apps.
312 307
313 308 This is a horrible hack to pass information about SIGINT _without_
314 309 using exceptions, since I haven't been able to properly manage
315 310 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
316 311 done (or at least that's my understanding from a c.l.py thread where
317 312 this was discussed)."""
318 313
319 314 global KBINT
320 315
321 316 if CODE_RUN:
322 317 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
323 318 else:
324 319 KBINT = True
325 320 print '\nKeyboardInterrupt - Press <Enter> to continue.',
326 321 Term.cout.flush()
327 322
328 323 else:
329 324 def sigint_handler (signum,stack_frame):
330 325 """Sigint handler for threaded apps.
331 326
332 327 This is a horrible hack to pass information about SIGINT _without_
333 328 using exceptions, since I haven't been able to properly manage
334 329 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
335 330 done (or at least that's my understanding from a c.l.py thread where
336 331 this was discussed)."""
337 332
338 333 global KBINT
339 334
340 335 print '\nKeyboardInterrupt - Press <Enter> to continue.',
341 336 Term.cout.flush()
342 337 # Set global flag so that runsource can know that Ctrl-C was hit
343 338 KBINT = True
344 339
345 340
346 341 class MTInteractiveShell(InteractiveShell):
347 342 """Simple multi-threaded shell."""
348 343
349 344 # Threading strategy taken from:
350 345 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
351 346 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
352 347 # from the pygtk mailing list, to avoid lockups with system calls.
353 348
354 349 # class attribute to indicate whether the class supports threads or not.
355 350 # Subclasses with thread support should override this as needed.
356 351 isthreaded = True
357 352
358 353 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
359 354 user_ns=None,user_global_ns=None,banner2='',
360 355 gui_timeout=GUI_TIMEOUT,**kw):
361 356 """Similar to the normal InteractiveShell, but with threading control"""
362 357
363 358 InteractiveShell.__init__(self,name,usage,rc,user_ns,
364 359 user_global_ns,banner2)
365 360
366 361 # Timeout we wait for GUI thread
367 362 self.gui_timeout = gui_timeout
368 363
369 364 # A queue to hold the code to be executed.
370 365 self.code_queue = Queue.Queue()
371 366
372 367 # Stuff to do at closing time
373 368 self._kill = None
374 369 on_kill = kw.get('on_kill', [])
375 370 # Check that all things to kill are callable:
376 371 for t in on_kill:
377 372 if not callable(t):
378 373 raise TypeError,'on_kill must be a list of callables'
379 374 self.on_kill = on_kill
380 375 # thread identity of the "worker thread" (that may execute code directly)
381 376 self.worker_ident = None
382 377
383 378 def runsource(self, source, filename="<input>", symbol="single"):
384 379 """Compile and run some source in the interpreter.
385 380
386 381 Modified version of code.py's runsource(), to handle threading issues.
387 382 See the original for full docstring details."""
388 383
389 384 global KBINT
390 385
391 386 # If Ctrl-C was typed, we reset the flag and return right away
392 387 if KBINT:
393 388 KBINT = False
394 389 return False
395 390
396 391 if self._kill:
397 392 # can't queue new code if we are being killed
398 393 return True
399 394
400 395 try:
401 396 code = self.compile(source, filename, symbol)
402 397 except (OverflowError, SyntaxError, ValueError):
403 398 # Case 1
404 399 self.showsyntaxerror(filename)
405 400 return False
406 401
407 402 if code is None:
408 403 # Case 2
409 404 return True
410 405
411 406 # shortcut - if we are in worker thread, or the worker thread is not
412 407 # running, execute directly (to allow recursion and prevent deadlock if
413 408 # code is run early in IPython construction)
414 409
415 410 if (self.worker_ident is None
416 411 or self.worker_ident == thread.get_ident() ):
417 412 InteractiveShell.runcode(self,code)
418 413 return
419 414
420 415 # Case 3
421 416 # Store code in queue, so the execution thread can handle it.
422 417
423 418 completed_ev, received_ev = threading.Event(), threading.Event()
424 419
425 420 self.code_queue.put((code,completed_ev, received_ev))
426 421 # first make sure the message was received, with timeout
427 422 received_ev.wait(self.gui_timeout)
428 423 if not received_ev.isSet():
429 424 # the mainloop is dead, start executing code directly
430 425 print "Warning: Timeout for mainloop thread exceeded"
431 426 print "switching to nonthreaded mode (until mainloop wakes up again)"
432 427 self.worker_ident = None
433 428 else:
434 429 completed_ev.wait()
435 430 return False
436 431
437 432 def runcode(self):
438 433 """Execute a code object.
439 434
440 435 Multithreaded wrapper around IPython's runcode()."""
441 436
442 437 global CODE_RUN
443 438
444 439 # we are in worker thread, stash out the id for runsource()
445 440 self.worker_ident = thread.get_ident()
446 441
447 442 if self._kill:
448 443 print >>Term.cout, 'Closing threads...',
449 444 Term.cout.flush()
450 445 for tokill in self.on_kill:
451 446 tokill()
452 447 print >>Term.cout, 'Done.'
453 448 # allow kill() to return
454 449 self._kill.set()
455 450 return True
456 451
457 452 # Install sigint handler. We do it every time to ensure that if user
458 453 # code modifies it, we restore our own handling.
459 454 try:
460 455 signal(SIGINT,sigint_handler)
461 456 except SystemError:
462 457 # This happens under Windows, which seems to have all sorts
463 458 # of problems with signal handling. Oh well...
464 459 pass
465 460
466 461 # Flush queue of pending code by calling the run methood of the parent
467 462 # class with all items which may be in the queue.
468 463 code_to_run = None
469 464 while 1:
470 465 try:
471 466 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
472 467 except Queue.Empty:
473 468 break
474 469 received_ev.set()
475 470
476 471 # Exceptions need to be raised differently depending on which
477 472 # thread is active. This convoluted try/except is only there to
478 473 # protect against asynchronous exceptions, to ensure that a KBINT
479 474 # at the wrong time doesn't deadlock everything. The global
480 475 # CODE_TO_RUN is set to true/false as close as possible to the
481 476 # runcode() call, so that the KBINT handler is correctly informed.
482 477 try:
483 478 try:
484 479 CODE_RUN = True
485 480 InteractiveShell.runcode(self,code_to_run)
486 481 except KeyboardInterrupt:
487 482 print "Keyboard interrupted in mainloop"
488 483 while not self.code_queue.empty():
489 484 code, ev1,ev2 = self.code_queue.get_nowait()
490 485 ev1.set()
491 486 ev2.set()
492 487 break
493 488 finally:
494 489 CODE_RUN = False
495 490 # allow runsource() return from wait
496 491 completed_ev.set()
497 492
498 493
499 494 # This MUST return true for gtk threading to work
500 495 return True
501 496
502 497 def kill(self):
503 498 """Kill the thread, returning when it has been shut down."""
504 499 self._kill = threading.Event()
505 500 self._kill.wait()
506 501
507 502 class MatplotlibShellBase:
508 503 """Mixin class to provide the necessary modifications to regular IPython
509 504 shell classes for matplotlib support.
510 505
511 506 Given Python's MRO, this should be used as the FIRST class in the
512 507 inheritance hierarchy, so that it overrides the relevant methods."""
513 508
514 509 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
515 510 """Return items needed to setup the user's shell with matplotlib"""
516 511
517 512 # Initialize matplotlib to interactive mode always
518 513 import matplotlib
519 514 from matplotlib import backends
520 515 matplotlib.interactive(True)
521 516
522 517 def use(arg):
523 518 """IPython wrapper for matplotlib's backend switcher.
524 519
525 520 In interactive use, we can not allow switching to a different
526 521 interactive backend, since thread conflicts will most likely crash
527 522 the python interpreter. This routine does a safety check first,
528 523 and refuses to perform a dangerous switch. It still allows
529 524 switching to non-interactive backends."""
530 525
531 526 if arg in backends.interactive_bk and arg != self.mpl_backend:
532 527 m=('invalid matplotlib backend switch.\n'
533 528 'This script attempted to switch to the interactive '
534 529 'backend: `%s`\n'
535 530 'Your current choice of interactive backend is: `%s`\n\n'
536 531 'Switching interactive matplotlib backends at runtime\n'
537 532 'would crash the python interpreter, '
538 533 'and IPython has blocked it.\n\n'
539 534 'You need to either change your choice of matplotlib backend\n'
540 535 'by editing your .matplotlibrc file, or run this script as a \n'
541 536 'standalone file from the command line, not using IPython.\n' %
542 537 (arg,self.mpl_backend) )
543 538 raise RuntimeError, m
544 539 else:
545 540 self.mpl_use(arg)
546 541 self.mpl_use._called = True
547 542
548 543 self.matplotlib = matplotlib
549 544 self.mpl_backend = matplotlib.rcParams['backend']
550 545
551 546 # we also need to block switching of interactive backends by use()
552 547 self.mpl_use = matplotlib.use
553 548 self.mpl_use._called = False
554 549 # overwrite the original matplotlib.use with our wrapper
555 550 matplotlib.use = use
556 551
557 552 # This must be imported last in the matplotlib series, after
558 553 # backend/interactivity choices have been made
559 554 import matplotlib.pylab as pylab
560 555 self.pylab = pylab
561 556
562 557 self.pylab.show._needmain = False
563 558 # We need to detect at runtime whether show() is called by the user.
564 559 # For this, we wrap it into a decorator which adds a 'called' flag.
565 560 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
566 561
567 562 # Build a user namespace initialized with matplotlib/matlab features.
568 563 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
569 564 user_global_ns)
570 565
571 566 # Import numpy as np/pyplot as plt are conventions we're trying to
572 567 # somewhat standardize on. Making them available to users by default
573 568 # will greatly help this.
574 569 exec ("import numpy\n"
575 570 "import numpy as np\n"
576 571 "import matplotlib\n"
577 572 "import matplotlib.pylab as pylab\n"
578 573 "try:\n"
579 574 " import matplotlib.pyplot as plt\n"
580 575 "except ImportError:\n"
581 576 " pass\n"
582 577 ) in user_ns
583 578
584 579 # Build matplotlib info banner
585 580 b="""
586 581 Welcome to pylab, a matplotlib-based Python environment.
587 582 For more information, type 'help(pylab)'.
588 583 """
589 584 return user_ns,user_global_ns,b
590 585
591 586 def mplot_exec(self,fname,*where,**kw):
592 587 """Execute a matplotlib script.
593 588
594 589 This is a call to execfile(), but wrapped in safeties to properly
595 590 handle interactive rendering and backend switching."""
596 591
597 592 #print '*** Matplotlib runner ***' # dbg
598 593 # turn off rendering until end of script
599 594 isInteractive = self.matplotlib.rcParams['interactive']
600 595 self.matplotlib.interactive(False)
601 596 self.safe_execfile(fname,*where,**kw)
602 597 self.matplotlib.interactive(isInteractive)
603 598 # make rendering call now, if the user tried to do it
604 599 if self.pylab.draw_if_interactive.called:
605 600 self.pylab.draw()
606 601 self.pylab.draw_if_interactive.called = False
607 602
608 603 # if a backend switch was performed, reverse it now
609 604 if self.mpl_use._called:
610 605 self.matplotlib.rcParams['backend'] = self.mpl_backend
611 606
612 607 @testdec.skip_doctest
613 608 def magic_run(self,parameter_s=''):
614 609 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
615 610
616 611 # Fix the docstring so users see the original as well
617 612 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
618 613 "\n *** Modified %run for Matplotlib,"
619 614 " with proper interactive handling ***")
620 615
621 616 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
622 617 # and multithreaded. Note that these are meant for internal use, the IPShell*
623 618 # classes below are the ones meant for public consumption.
624 619
625 620 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
626 621 """Single-threaded shell with matplotlib support."""
627 622
628 623 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
629 624 user_ns=None,user_global_ns=None,**kw):
630 625 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
631 626 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
632 627 banner2=b2,**kw)
633 628
634 629 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
635 630 """Multi-threaded shell with matplotlib support."""
636 631
637 632 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
638 633 user_ns=None,user_global_ns=None, **kw):
639 634 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
640 635 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
641 636 banner2=b2,**kw)
642 637
643 638 #-----------------------------------------------------------------------------
644 639 # Utility functions for the different GUI enabled IPShell* classes.
645 640
646 641 def get_tk():
647 642 """Tries to import Tkinter and returns a withdrawn Tkinter root
648 643 window. If Tkinter is already imported or not available, this
649 644 returns None. This function calls `hijack_tk` underneath.
650 645 """
651 646 if not USE_TK or sys.modules.has_key('Tkinter'):
652 647 return None
653 648 else:
654 649 try:
655 650 import Tkinter
656 651 except ImportError:
657 652 return None
658 653 else:
659 654 hijack_tk()
660 655 r = Tkinter.Tk()
661 656 r.withdraw()
662 657 return r
663 658
664 659 def hijack_tk():
665 660 """Modifies Tkinter's mainloop with a dummy so when a module calls
666 661 mainloop, it does not block.
667 662
668 663 """
669 664 def misc_mainloop(self, n=0):
670 665 pass
671 666 def tkinter_mainloop(n=0):
672 667 pass
673 668
674 669 import Tkinter
675 670 Tkinter.Misc.mainloop = misc_mainloop
676 671 Tkinter.mainloop = tkinter_mainloop
677 672
678 673 def update_tk(tk):
679 674 """Updates the Tkinter event loop. This is typically called from
680 675 the respective WX or GTK mainloops.
681 676 """
682 677 if tk:
683 678 tk.update()
684 679
685 680 def hijack_wx():
686 681 """Modifies wxPython's MainLoop with a dummy so user code does not
687 682 block IPython. The hijacked mainloop function is returned.
688 683 """
689 684 def dummy_mainloop(*args, **kw):
690 685 pass
691 686
692 687 try:
693 688 import wx
694 689 except ImportError:
695 690 # For very old versions of WX
696 691 import wxPython as wx
697 692
698 693 ver = wx.__version__
699 694 orig_mainloop = None
700 695 if ver[:3] >= '2.5':
701 696 import wx
702 697 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
703 698 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
704 699 else: raise AttributeError('Could not find wx core module')
705 700 orig_mainloop = core.PyApp_MainLoop
706 701 core.PyApp_MainLoop = dummy_mainloop
707 702 elif ver[:3] == '2.4':
708 703 orig_mainloop = wx.wxc.wxPyApp_MainLoop
709 704 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
710 705 else:
711 706 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
712 707 return orig_mainloop
713 708
714 709 def hijack_gtk():
715 710 """Modifies pyGTK's mainloop with a dummy so user code does not
716 711 block IPython. This function returns the original `gtk.mainloop`
717 712 function that has been hijacked.
718 713 """
719 714 def dummy_mainloop(*args, **kw):
720 715 pass
721 716 import gtk
722 717 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
723 718 else: orig_mainloop = gtk.mainloop
724 719 gtk.mainloop = dummy_mainloop
725 720 gtk.main = dummy_mainloop
726 721 return orig_mainloop
727 722
728 723 def hijack_qt():
729 724 """Modifies PyQt's mainloop with a dummy so user code does not
730 725 block IPython. This function returns the original
731 726 `qt.qApp.exec_loop` function that has been hijacked.
732 727 """
733 728 def dummy_mainloop(*args, **kw):
734 729 pass
735 730 import qt
736 731 orig_mainloop = qt.qApp.exec_loop
737 732 qt.qApp.exec_loop = dummy_mainloop
738 733 qt.QApplication.exec_loop = dummy_mainloop
739 734 return orig_mainloop
740 735
741 736 def hijack_qt4():
742 737 """Modifies PyQt4's mainloop with a dummy so user code does not
743 738 block IPython. This function returns the original
744 739 `QtGui.qApp.exec_` function that has been hijacked.
745 740 """
746 741 def dummy_mainloop(*args, **kw):
747 742 pass
748 743 from PyQt4 import QtGui, QtCore
749 744 orig_mainloop = QtGui.qApp.exec_
750 745 QtGui.qApp.exec_ = dummy_mainloop
751 746 QtGui.QApplication.exec_ = dummy_mainloop
752 747 QtCore.QCoreApplication.exec_ = dummy_mainloop
753 748 return orig_mainloop
754 749
755 750 #-----------------------------------------------------------------------------
756 751 # The IPShell* classes below are the ones meant to be run by external code as
757 752 # IPython instances. Note that unless a specific threading strategy is
758 753 # desired, the factory function start() below should be used instead (it
759 754 # selects the proper threaded class).
760 755
761 756 class IPThread(threading.Thread):
762 757 def run(self):
763 758 self.IP.mainloop(self._banner)
764 759 self.IP.kill()
765 760
766 761 class IPShellGTK(IPThread):
767 762 """Run a gtk mainloop() in a separate thread.
768 763
769 764 Python commands can be passed to the thread where they will be executed.
770 765 This is implemented by periodically checking for passed code using a
771 766 GTK timeout callback."""
772 767
773 768 TIMEOUT = 100 # Millisecond interval between timeouts.
774 769
775 770 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
776 771 debug=1,shell_class=MTInteractiveShell):
777 772
778 773 import gtk
779 774
780 775 self.gtk = gtk
781 776 self.gtk_mainloop = hijack_gtk()
782 777
783 778 # Allows us to use both Tk and GTK.
784 779 self.tk = get_tk()
785 780
786 781 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
787 782 else: mainquit = self.gtk.mainquit
788 783
789 784 self.IP = make_IPython(argv,user_ns=user_ns,
790 785 user_global_ns=user_global_ns,
791 786 debug=debug,
792 787 shell_class=shell_class,
793 788 on_kill=[mainquit])
794 789
795 790 # HACK: slot for banner in self; it will be passed to the mainloop
796 791 # method only and .run() needs it. The actual value will be set by
797 792 # .mainloop().
798 793 self._banner = None
799 794
800 795 threading.Thread.__init__(self)
801 796
802 797 def mainloop(self,sys_exit=0,banner=None):
803 798
804 799 self._banner = banner
805 800
806 801 if self.gtk.pygtk_version >= (2,4,0):
807 802 import gobject
808 803 gobject.idle_add(self.on_timer)
809 804 else:
810 805 self.gtk.idle_add(self.on_timer)
811 806
812 807 if sys.platform != 'win32':
813 808 try:
814 809 if self.gtk.gtk_version[0] >= 2:
815 810 self.gtk.gdk.threads_init()
816 811 except AttributeError:
817 812 pass
818 813 except RuntimeError:
819 814 error('Your pyGTK likely has not been compiled with '
820 815 'threading support.\n'
821 816 'The exception printout is below.\n'
822 817 'You can either rebuild pyGTK with threads, or '
823 818 'try using \n'
824 819 'matplotlib with a different backend (like Tk or WX).\n'
825 820 'Note that matplotlib will most likely not work in its '
826 821 'current state!')
827 822 self.IP.InteractiveTB()
828 823
829 824 self.start()
830 825 self.gtk.gdk.threads_enter()
831 826 self.gtk_mainloop()
832 827 self.gtk.gdk.threads_leave()
833 828 self.join()
834 829
835 830 def on_timer(self):
836 831 """Called when GTK is idle.
837 832
838 833 Must return True always, otherwise GTK stops calling it"""
839 834
840 835 update_tk(self.tk)
841 836 self.IP.runcode()
842 837 time.sleep(0.01)
843 838 return True
844 839
845 840
846 841 class IPShellWX(IPThread):
847 842 """Run a wx mainloop() in a separate thread.
848 843
849 844 Python commands can be passed to the thread where they will be executed.
850 845 This is implemented by periodically checking for passed code using a
851 846 GTK timeout callback."""
852 847
853 848 TIMEOUT = 100 # Millisecond interval between timeouts.
854 849
855 850 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
856 851 debug=1,shell_class=MTInteractiveShell):
857 852
858 853 self.IP = make_IPython(argv,user_ns=user_ns,
859 854 user_global_ns=user_global_ns,
860 855 debug=debug,
861 856 shell_class=shell_class,
862 857 on_kill=[self.wxexit])
863 858
864 859 wantedwxversion=self.IP.rc.wxversion
865 860 if wantedwxversion!="0":
866 861 try:
867 862 import wxversion
868 863 except ImportError:
869 864 error('The wxversion module is needed for WX version selection')
870 865 else:
871 866 try:
872 867 wxversion.select(wantedwxversion)
873 868 except:
874 869 self.IP.InteractiveTB()
875 870 error('Requested wxPython version %s could not be loaded' %
876 871 wantedwxversion)
877 872
878 873 import wx
879 874
880 875 threading.Thread.__init__(self)
881 876 self.wx = wx
882 877 self.wx_mainloop = hijack_wx()
883 878
884 879 # Allows us to use both Tk and GTK.
885 880 self.tk = get_tk()
886 881
887 882 # HACK: slot for banner in self; it will be passed to the mainloop
888 883 # method only and .run() needs it. The actual value will be set by
889 884 # .mainloop().
890 885 self._banner = None
891 886
892 887 self.app = None
893 888
894 889 def wxexit(self, *args):
895 890 if self.app is not None:
896 891 self.app.agent.timer.Stop()
897 892 self.app.ExitMainLoop()
898 893
899 894 def mainloop(self,sys_exit=0,banner=None):
900 895
901 896 self._banner = banner
902 897
903 898 self.start()
904 899
905 900 class TimerAgent(self.wx.MiniFrame):
906 901 wx = self.wx
907 902 IP = self.IP
908 903 tk = self.tk
909 904 def __init__(self, parent, interval):
910 905 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
911 906 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
912 907 size=(100, 100),style=style)
913 908 self.Show(False)
914 909 self.interval = interval
915 910 self.timerId = self.wx.NewId()
916 911
917 912 def StartWork(self):
918 913 self.timer = self.wx.Timer(self, self.timerId)
919 914 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
920 915 self.timer.Start(self.interval)
921 916
922 917 def OnTimer(self, event):
923 918 update_tk(self.tk)
924 919 self.IP.runcode()
925 920
926 921 class App(self.wx.App):
927 922 wx = self.wx
928 923 TIMEOUT = self.TIMEOUT
929 924 def OnInit(self):
930 925 'Create the main window and insert the custom frame'
931 926 self.agent = TimerAgent(None, self.TIMEOUT)
932 927 self.agent.Show(False)
933 928 self.agent.StartWork()
934 929 return True
935 930
936 931 self.app = App(redirect=False)
937 932 self.wx_mainloop(self.app)
938 933 self.join()
939 934
940 935
941 936 class IPShellQt(IPThread):
942 937 """Run a Qt event loop in a separate thread.
943 938
944 939 Python commands can be passed to the thread where they will be executed.
945 940 This is implemented by periodically checking for passed code using a
946 941 Qt timer / slot."""
947 942
948 943 TIMEOUT = 100 # Millisecond interval between timeouts.
949 944
950 945 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
951 946 debug=0, shell_class=MTInteractiveShell):
952 947
953 948 import qt
954 949
955 950 self.exec_loop = hijack_qt()
956 951
957 952 # Allows us to use both Tk and QT.
958 953 self.tk = get_tk()
959 954
960 955 self.IP = make_IPython(argv,
961 956 user_ns=user_ns,
962 957 user_global_ns=user_global_ns,
963 958 debug=debug,
964 959 shell_class=shell_class,
965 960 on_kill=[qt.qApp.exit])
966 961
967 962 # HACK: slot for banner in self; it will be passed to the mainloop
968 963 # method only and .run() needs it. The actual value will be set by
969 964 # .mainloop().
970 965 self._banner = None
971 966
972 967 threading.Thread.__init__(self)
973 968
974 969 def mainloop(self, sys_exit=0, banner=None):
975 970
976 971 import qt
977 972
978 973 self._banner = banner
979 974
980 975 if qt.QApplication.startingUp():
981 976 a = qt.QApplication(sys.argv)
982 977
983 978 self.timer = qt.QTimer()
984 979 qt.QObject.connect(self.timer,
985 980 qt.SIGNAL('timeout()'),
986 981 self.on_timer)
987 982
988 983 self.start()
989 984 self.timer.start(self.TIMEOUT, True)
990 985 while True:
991 986 if self.IP._kill: break
992 987 self.exec_loop()
993 988 self.join()
994 989
995 990 def on_timer(self):
996 991 update_tk(self.tk)
997 992 result = self.IP.runcode()
998 993 self.timer.start(self.TIMEOUT, True)
999 994 return result
1000 995
1001 996
1002 997 class IPShellQt4(IPThread):
1003 998 """Run a Qt event loop in a separate thread.
1004 999
1005 1000 Python commands can be passed to the thread where they will be executed.
1006 1001 This is implemented by periodically checking for passed code using a
1007 1002 Qt timer / slot."""
1008 1003
1009 1004 TIMEOUT = 100 # Millisecond interval between timeouts.
1010 1005
1011 1006 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1012 1007 debug=0, shell_class=MTInteractiveShell):
1013 1008
1014 1009 from PyQt4 import QtCore, QtGui
1015 1010
1016 1011 try:
1017 1012 # present in PyQt4-4.2.1 or later
1018 1013 QtCore.pyqtRemoveInputHook()
1019 1014 except AttributeError:
1020 1015 pass
1021 1016
1022 1017 if QtCore.PYQT_VERSION_STR == '4.3':
1023 1018 warn('''PyQt4 version 4.3 detected.
1024 1019 If you experience repeated threading warnings, please update PyQt4.
1025 1020 ''')
1026 1021
1027 1022 self.exec_ = hijack_qt4()
1028 1023
1029 1024 # Allows us to use both Tk and QT.
1030 1025 self.tk = get_tk()
1031 1026
1032 1027 self.IP = make_IPython(argv,
1033 1028 user_ns=user_ns,
1034 1029 user_global_ns=user_global_ns,
1035 1030 debug=debug,
1036 1031 shell_class=shell_class,
1037 1032 on_kill=[QtGui.qApp.exit])
1038 1033
1039 1034 # HACK: slot for banner in self; it will be passed to the mainloop
1040 1035 # method only and .run() needs it. The actual value will be set by
1041 1036 # .mainloop().
1042 1037 self._banner = None
1043 1038
1044 1039 threading.Thread.__init__(self)
1045 1040
1046 1041 def mainloop(self, sys_exit=0, banner=None):
1047 1042
1048 1043 from PyQt4 import QtCore, QtGui
1049 1044
1050 1045 self._banner = banner
1051 1046
1052 1047 if QtGui.QApplication.startingUp():
1053 1048 a = QtGui.QApplication(sys.argv)
1054 1049
1055 1050 self.timer = QtCore.QTimer()
1056 1051 QtCore.QObject.connect(self.timer,
1057 1052 QtCore.SIGNAL('timeout()'),
1058 1053 self.on_timer)
1059 1054
1060 1055 self.start()
1061 1056 self.timer.start(self.TIMEOUT)
1062 1057 while True:
1063 1058 if self.IP._kill: break
1064 1059 self.exec_()
1065 1060 self.join()
1066 1061
1067 1062 def on_timer(self):
1068 1063 update_tk(self.tk)
1069 1064 result = self.IP.runcode()
1070 1065 self.timer.start(self.TIMEOUT)
1071 1066 return result
1072 1067
1073 1068
1074 1069 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1075 1070 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1076 1071 def _load_pylab(user_ns):
1077 1072 """Allow users to disable pulling all of pylab into the top-level
1078 1073 namespace.
1079 1074
1080 1075 This little utility must be called AFTER the actual ipython instance is
1081 1076 running, since only then will the options file have been fully parsed."""
1082 1077
1083 1078 ip = IPython.ipapi.get()
1084 1079 if ip.options.pylab_import_all:
1085 1080 ip.ex("from matplotlib.pylab import *")
1086 1081 ip.IP.user_config_ns.update(ip.user_ns)
1087 1082
1088 1083
1089 1084 class IPShellMatplotlib(IPShell):
1090 1085 """Subclass IPShell with MatplotlibShell as the internal shell.
1091 1086
1092 1087 Single-threaded class, meant for the Tk* and FLTK* backends.
1093 1088
1094 1089 Having this on a separate class simplifies the external driver code."""
1095 1090
1096 1091 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1097 1092 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1098 1093 shell_class=MatplotlibShell)
1099 1094 _load_pylab(self.IP.user_ns)
1100 1095
1101 1096 class IPShellMatplotlibGTK(IPShellGTK):
1102 1097 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1103 1098
1104 1099 Multi-threaded class, meant for the GTK* backends."""
1105 1100
1106 1101 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1107 1102 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1108 1103 shell_class=MatplotlibMTShell)
1109 1104 _load_pylab(self.IP.user_ns)
1110 1105
1111 1106 class IPShellMatplotlibWX(IPShellWX):
1112 1107 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1113 1108
1114 1109 Multi-threaded class, meant for the WX* backends."""
1115 1110
1116 1111 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1117 1112 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1118 1113 shell_class=MatplotlibMTShell)
1119 1114 _load_pylab(self.IP.user_ns)
1120 1115
1121 1116 class IPShellMatplotlibQt(IPShellQt):
1122 1117 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1123 1118
1124 1119 Multi-threaded class, meant for the Qt* backends."""
1125 1120
1126 1121 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1127 1122 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1128 1123 shell_class=MatplotlibMTShell)
1129 1124 _load_pylab(self.IP.user_ns)
1130 1125
1131 1126 class IPShellMatplotlibQt4(IPShellQt4):
1132 1127 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1133 1128
1134 1129 Multi-threaded class, meant for the Qt4* backends."""
1135 1130
1136 1131 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1137 1132 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1138 1133 shell_class=MatplotlibMTShell)
1139 1134 _load_pylab(self.IP.user_ns)
1140 1135
1141 1136 #-----------------------------------------------------------------------------
1142 1137 # Factory functions to actually start the proper thread-aware shell
1143 1138
1144 1139 def _select_shell(argv):
1145 1140 """Select a shell from the given argv vector.
1146 1141
1147 1142 This function implements the threading selection policy, allowing runtime
1148 1143 control of the threading mode, both for general users and for matplotlib.
1149 1144
1150 1145 Return:
1151 1146 Shell class to be instantiated for runtime operation.
1152 1147 """
1153 1148
1154 1149 global USE_TK
1155 1150
1156 1151 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1157 1152 'wthread' : IPShellMatplotlibWX,
1158 1153 'qthread' : IPShellMatplotlibQt,
1159 1154 'q4thread' : IPShellMatplotlibQt4,
1160 1155 'tkthread' : IPShellMatplotlib, # Tk is built-in
1161 1156 }
1162 1157
1163 1158 th_shell = {'gthread' : IPShellGTK,
1164 1159 'wthread' : IPShellWX,
1165 1160 'qthread' : IPShellQt,
1166 1161 'q4thread' : IPShellQt4,
1167 1162 'tkthread' : IPShell, # Tk is built-in
1168 1163 }
1169 1164
1170 1165 backends = {'gthread' : 'GTKAgg',
1171 1166 'wthread' : 'WXAgg',
1172 1167 'qthread' : 'QtAgg',
1173 1168 'q4thread' :'Qt4Agg',
1174 1169 'tkthread' :'TkAgg',
1175 1170 }
1176 1171
1177 1172 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1178 1173 'tkthread'])
1179 1174 user_opts = set([s.replace('-','') for s in argv[:3]])
1180 1175 special_opts = user_opts & all_opts
1181 1176
1182 1177 if 'tk' in special_opts:
1183 1178 USE_TK = True
1184 1179 special_opts.remove('tk')
1185 1180
1186 1181 if 'pylab' in special_opts:
1187 1182
1188 1183 try:
1189 1184 import matplotlib
1190 1185 except ImportError:
1191 1186 error('matplotlib could NOT be imported! Starting normal IPython.')
1192 1187 return IPShell
1193 1188
1194 1189 special_opts.remove('pylab')
1195 1190 # If there's any option left, it means the user wants to force the
1196 1191 # threading backend, else it's auto-selected from the rc file
1197 1192 if special_opts:
1198 1193 th_mode = special_opts.pop()
1199 1194 matplotlib.rcParams['backend'] = backends[th_mode]
1200 1195 else:
1201 1196 backend = matplotlib.rcParams['backend']
1202 1197 if backend.startswith('GTK'):
1203 1198 th_mode = 'gthread'
1204 1199 elif backend.startswith('WX'):
1205 1200 th_mode = 'wthread'
1206 1201 elif backend.startswith('Qt4'):
1207 1202 th_mode = 'q4thread'
1208 1203 elif backend.startswith('Qt'):
1209 1204 th_mode = 'qthread'
1210 1205 else:
1211 1206 # Any other backend, use plain Tk
1212 1207 th_mode = 'tkthread'
1213 1208
1214 1209 return mpl_shell[th_mode]
1215 1210 else:
1216 1211 # No pylab requested, just plain threads
1217 1212 try:
1218 1213 th_mode = special_opts.pop()
1219 1214 except KeyError:
1220 1215 th_mode = 'tkthread'
1221 1216 return th_shell[th_mode]
1222 1217
1223 1218
1224 1219 # This is the one which should be called by external code.
1225 1220 def start(user_ns = None):
1226 1221 """Return a running shell instance, dealing with threading options.
1227 1222
1228 1223 This is a factory function which will instantiate the proper IPython shell
1229 1224 based on the user's threading choice. Such a selector is needed because
1230 1225 different GUI toolkits require different thread handling details."""
1231 1226
1232 1227 shell = _select_shell(sys.argv)
1233 1228 return shell(user_ns = user_ns)
1234 1229
1235 1230 # Some aliases for backwards compatibility
1236 1231 IPythonShell = IPShell
1237 1232 IPythonShellEmbed = IPShellEmbed
1238 1233 #************************ End of file <Shell.py> ***************************
@@ -1,72 +1,71 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 IPython -- An enhanced Interactive Python
4 4
5 5 One of Python's nicest features is its interactive interpreter. This allows
6 6 very fast testing of ideas without the overhead of creating test files as is
7 7 typical in most programming languages. However, the interpreter supplied with
8 8 the standard Python distribution is fairly primitive (and IDLE isn't really
9 9 much better).
10 10
11 11 IPython tries to:
12 12
13 13 i - provide an efficient environment for interactive work in Python
14 14 programming. It tries to address what we see as shortcomings of the standard
15 15 Python prompt, and adds many features to make interactive work much more
16 16 efficient.
17 17
18 18 ii - offer a flexible framework so that it can be used as the base
19 19 environment for other projects and problems where Python can be the
20 20 underlying language. Specifically scientific environments like Mathematica,
21 21 IDL and Mathcad inspired its design, but similar ideas can be useful in many
22 22 fields. Python is a fabulous language for implementing this kind of system
23 23 (due to its dynamic and introspective features), and with suitable libraries
24 24 entire systems could be built leveraging Python's power.
25 25
26 26 iii - serve as an embeddable, ready to go interpreter for your own programs.
27 27
28 IPython requires Python 2.3 or newer.
29
30 $Id: __init__.py 2399 2007-05-26 10:23:10Z vivainio $"""
28 IPython requires Python 2.4 or newer.
29 """
31 30
32 31 #*****************************************************************************
33 32 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
34 33 #
35 34 # Distributed under the terms of the BSD License. The full license is in
36 35 # the file COPYING, distributed as part of this software.
37 36 #*****************************************************************************
38 37
39 38 # Enforce proper version requirements
40 39 import sys
41 40
42 41 if sys.version[0:3] < '2.4':
43 42 raise ImportError('Python Version 2.4 or above is required for IPython.')
44 43
45 44 # Make it easy to import extensions - they are always directly on pythonpath.
46 45 # Therefore, non-IPython modules can be added to Extensions directory
47 46 import os
48 47 sys.path.append(os.path.dirname(__file__) + "/Extensions")
49 48
50 49 # Define what gets imported with a 'from IPython import *'
51 50 __all__ = ['ipapi','generics','ipstruct','Release','Shell']
52 51
53 52 # Load __all__ in IPython namespace so that a simple 'import IPython' gives
54 53 # access to them via IPython.<name>
55 54 glob,loc = globals(),locals()
56 55 for name in __all__:
57 56 #print 'Importing: ',name # dbg
58 57 __import__(name,glob,loc,[])
59 58
60 59 import Shell
61 60
62 61 # Release data
63 62 from IPython import Release # do it explicitly so pydoc can see it - pydoc bug
64 63 __author__ = '%s <%s>\n%s <%s>\n%s <%s>' % \
65 64 ( Release.authors['Fernando'] + Release.authors['Janko'] + \
66 65 Release.authors['Nathan'] )
67 66 __license__ = Release.license
68 67 __version__ = Release.version
69 68 __revision__ = Release.revision
70 69
71 70 # Namespace cleanup
72 71 del name,glob,loc
@@ -1,496 +1,490 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Manage background (threaded) jobs conveniently from an interactive shell.
3 3
4 4 This module provides a BackgroundJobManager class. This is the main class
5 5 meant for public usage, it implements an object which can create and manage
6 6 new background jobs.
7 7
8 8 It also provides the actual job classes managed by these BackgroundJobManager
9 9 objects, see their docstrings below.
10 10
11 11
12 12 This system was inspired by discussions with B. Granger and the
13 13 BackgroundCommand class described in the book Python Scripting for
14 14 Computational Science, by H. P. Langtangen:
15 15
16 16 http://folk.uio.no/hpl/scripting
17 17
18 18 (although ultimately no code from this text was used, as IPython's system is a
19 19 separate implementation).
20
21 $Id: background_jobs.py 994 2006-01-08 08:29:44Z fperez $
22 20 """
23 21
24 22 #*****************************************************************************
25 23 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
26 24 #
27 25 # Distributed under the terms of the BSD License. The full license is in
28 26 # the file COPYING, distributed as part of this software.
29 27 #*****************************************************************************
30 28
31 from IPython import Release
32 __author__ = '%s <%s>' % Release.authors['Fernando']
33 __license__ = Release.license
34
35 29 # Code begins
36 30 import sys
37 31 import threading
38 32
39 33 from IPython.ultraTB import AutoFormattedTB
40 34 from IPython.genutils import warn,error
41 35
42 36 class BackgroundJobManager:
43 37 """Class to manage a pool of backgrounded threaded jobs.
44 38
45 39 Below, we assume that 'jobs' is a BackgroundJobManager instance.
46 40
47 41 Usage summary (see the method docstrings for details):
48 42
49 43 jobs.new(...) -> start a new job
50 44
51 45 jobs() or jobs.status() -> print status summary of all jobs
52 46
53 47 jobs[N] -> returns job number N.
54 48
55 49 foo = jobs[N].result -> assign to variable foo the result of job N
56 50
57 51 jobs[N].traceback() -> print the traceback of dead job N
58 52
59 53 jobs.remove(N) -> remove (finished) job N
60 54
61 55 jobs.flush_finished() -> remove all finished jobs
62 56
63 57 As a convenience feature, BackgroundJobManager instances provide the
64 58 utility result and traceback methods which retrieve the corresponding
65 59 information from the jobs list:
66 60
67 61 jobs.result(N) <--> jobs[N].result
68 62 jobs.traceback(N) <--> jobs[N].traceback()
69 63
70 64 While this appears minor, it allows you to use tab completion
71 65 interactively on the job manager instance.
72 66
73 67 In interactive mode, IPython provides the magic fuction %bg for quick
74 68 creation of backgrounded expression-based jobs. Type bg? for details."""
75 69
76 70 def __init__(self):
77 71 # Lists for job management
78 72 self.jobs_run = []
79 73 self.jobs_comp = []
80 74 self.jobs_dead = []
81 75 # A dict of all jobs, so users can easily access any of them
82 76 self.jobs_all = {}
83 77 # For reporting
84 78 self._comp_report = []
85 79 self._dead_report = []
86 80 # Store status codes locally for fast lookups
87 81 self._s_created = BackgroundJobBase.stat_created_c
88 82 self._s_running = BackgroundJobBase.stat_running_c
89 83 self._s_completed = BackgroundJobBase.stat_completed_c
90 84 self._s_dead = BackgroundJobBase.stat_dead_c
91 85
92 86 def new(self,func_or_exp,*args,**kwargs):
93 87 """Add a new background job and start it in a separate thread.
94 88
95 89 There are two types of jobs which can be created:
96 90
97 91 1. Jobs based on expressions which can be passed to an eval() call.
98 92 The expression must be given as a string. For example:
99 93
100 94 job_manager.new('myfunc(x,y,z=1)'[,glob[,loc]])
101 95
102 96 The given expression is passed to eval(), along with the optional
103 97 global/local dicts provided. If no dicts are given, they are
104 98 extracted automatically from the caller's frame.
105 99
106 100 A Python statement is NOT a valid eval() expression. Basically, you
107 101 can only use as an eval() argument something which can go on the right
108 102 of an '=' sign and be assigned to a variable.
109 103
110 104 For example,"print 'hello'" is not valid, but '2+3' is.
111 105
112 106 2. Jobs given a function object, optionally passing additional
113 107 positional arguments:
114 108
115 109 job_manager.new(myfunc,x,y)
116 110
117 111 The function is called with the given arguments.
118 112
119 113 If you need to pass keyword arguments to your function, you must
120 114 supply them as a dict named kw:
121 115
122 116 job_manager.new(myfunc,x,y,kw=dict(z=1))
123 117
124 118 The reason for this assymmetry is that the new() method needs to
125 119 maintain access to its own keywords, and this prevents name collisions
126 120 between arguments to new() and arguments to your own functions.
127 121
128 122 In both cases, the result is stored in the job.result field of the
129 123 background job object.
130 124
131 125
132 126 Notes and caveats:
133 127
134 128 1. All threads running share the same standard output. Thus, if your
135 129 background jobs generate output, it will come out on top of whatever
136 130 you are currently writing. For this reason, background jobs are best
137 131 used with silent functions which simply return their output.
138 132
139 133 2. Threads also all work within the same global namespace, and this
140 134 system does not lock interactive variables. So if you send job to the
141 135 background which operates on a mutable object for a long time, and
142 136 start modifying that same mutable object interactively (or in another
143 137 backgrounded job), all sorts of bizarre behaviour will occur.
144 138
145 139 3. If a background job is spending a lot of time inside a C extension
146 140 module which does not release the Python Global Interpreter Lock
147 141 (GIL), this will block the IPython prompt. This is simply because the
148 142 Python interpreter can only switch between threads at Python
149 143 bytecodes. While the execution is inside C code, the interpreter must
150 144 simply wait unless the extension module releases the GIL.
151 145
152 146 4. There is no way, due to limitations in the Python threads library,
153 147 to kill a thread once it has started."""
154 148
155 149 if callable(func_or_exp):
156 150 kw = kwargs.get('kw',{})
157 151 job = BackgroundJobFunc(func_or_exp,*args,**kw)
158 152 elif isinstance(func_or_exp,basestring):
159 153 if not args:
160 154 frame = sys._getframe(1)
161 155 glob, loc = frame.f_globals, frame.f_locals
162 156 elif len(args)==1:
163 157 glob = loc = args[0]
164 158 elif len(args)==2:
165 159 glob,loc = args
166 160 else:
167 161 raise ValueError,\
168 162 'Expression jobs take at most 2 args (globals,locals)'
169 163 job = BackgroundJobExpr(func_or_exp,glob,loc)
170 164 else:
171 165 raise
172 166 jkeys = self.jobs_all.keys()
173 167 if jkeys:
174 168 job.num = max(jkeys)+1
175 169 else:
176 170 job.num = 0
177 171 self.jobs_run.append(job)
178 172 self.jobs_all[job.num] = job
179 173 print 'Starting job # %s in a separate thread.' % job.num
180 174 job.start()
181 175 return job
182 176
183 177 def __getitem__(self,key):
184 178 return self.jobs_all[key]
185 179
186 180 def __call__(self):
187 181 """An alias to self.status(),
188 182
189 183 This allows you to simply call a job manager instance much like the
190 184 Unix jobs shell command."""
191 185
192 186 return self.status()
193 187
194 188 def _update_status(self):
195 189 """Update the status of the job lists.
196 190
197 191 This method moves finished jobs to one of two lists:
198 192 - self.jobs_comp: jobs which completed successfully
199 193 - self.jobs_dead: jobs which finished but died.
200 194
201 195 It also copies those jobs to corresponding _report lists. These lists
202 196 are used to report jobs completed/dead since the last update, and are
203 197 then cleared by the reporting function after each call."""
204 198
205 199 run,comp,dead = self._s_running,self._s_completed,self._s_dead
206 200 jobs_run = self.jobs_run
207 201 for num in range(len(jobs_run)):
208 202 job = jobs_run[num]
209 203 stat = job.stat_code
210 204 if stat == run:
211 205 continue
212 206 elif stat == comp:
213 207 self.jobs_comp.append(job)
214 208 self._comp_report.append(job)
215 209 jobs_run[num] = False
216 210 elif stat == dead:
217 211 self.jobs_dead.append(job)
218 212 self._dead_report.append(job)
219 213 jobs_run[num] = False
220 214 self.jobs_run = filter(None,self.jobs_run)
221 215
222 216 def _group_report(self,group,name):
223 217 """Report summary for a given job group.
224 218
225 219 Return True if the group had any elements."""
226 220
227 221 if group:
228 222 print '%s jobs:' % name
229 223 for job in group:
230 224 print '%s : %s' % (job.num,job)
231 225 print
232 226 return True
233 227
234 228 def _group_flush(self,group,name):
235 229 """Flush a given job group
236 230
237 231 Return True if the group had any elements."""
238 232
239 233 njobs = len(group)
240 234 if njobs:
241 235 plural = {1:''}.setdefault(njobs,'s')
242 236 print 'Flushing %s %s job%s.' % (njobs,name,plural)
243 237 group[:] = []
244 238 return True
245 239
246 240 def _status_new(self):
247 241 """Print the status of newly finished jobs.
248 242
249 243 Return True if any new jobs are reported.
250 244
251 245 This call resets its own state every time, so it only reports jobs
252 246 which have finished since the last time it was called."""
253 247
254 248 self._update_status()
255 249 new_comp = self._group_report(self._comp_report,'Completed')
256 250 new_dead = self._group_report(self._dead_report,
257 251 'Dead, call job.traceback() for details')
258 252 self._comp_report[:] = []
259 253 self._dead_report[:] = []
260 254 return new_comp or new_dead
261 255
262 256 def status(self,verbose=0):
263 257 """Print a status of all jobs currently being managed."""
264 258
265 259 self._update_status()
266 260 self._group_report(self.jobs_run,'Running')
267 261 self._group_report(self.jobs_comp,'Completed')
268 262 self._group_report(self.jobs_dead,'Dead')
269 263 # Also flush the report queues
270 264 self._comp_report[:] = []
271 265 self._dead_report[:] = []
272 266
273 267 def remove(self,num):
274 268 """Remove a finished (completed or dead) job."""
275 269
276 270 try:
277 271 job = self.jobs_all[num]
278 272 except KeyError:
279 273 error('Job #%s not found' % num)
280 274 else:
281 275 stat_code = job.stat_code
282 276 if stat_code == self._s_running:
283 277 error('Job #%s is still running, it can not be removed.' % num)
284 278 return
285 279 elif stat_code == self._s_completed:
286 280 self.jobs_comp.remove(job)
287 281 elif stat_code == self._s_dead:
288 282 self.jobs_dead.remove(job)
289 283
290 284 def flush_finished(self):
291 285 """Flush all jobs finished (completed and dead) from lists.
292 286
293 287 Running jobs are never flushed.
294 288
295 289 It first calls _status_new(), to update info. If any jobs have
296 290 completed since the last _status_new() call, the flush operation
297 291 aborts."""
298 292
299 293 if self._status_new():
300 294 error('New jobs completed since last '\
301 295 '_status_new(), aborting flush.')
302 296 return
303 297
304 298 # Remove the finished jobs from the master dict
305 299 jobs_all = self.jobs_all
306 300 for job in self.jobs_comp+self.jobs_dead:
307 301 del(jobs_all[job.num])
308 302
309 303 # Now flush these lists completely
310 304 fl_comp = self._group_flush(self.jobs_comp,'Completed')
311 305 fl_dead = self._group_flush(self.jobs_dead,'Dead')
312 306 if not (fl_comp or fl_dead):
313 307 print 'No jobs to flush.'
314 308
315 309 def result(self,num):
316 310 """result(N) -> return the result of job N."""
317 311 try:
318 312 return self.jobs_all[num].result
319 313 except KeyError:
320 314 error('Job #%s not found' % num)
321 315
322 316 def traceback(self,num):
323 317 try:
324 318 self.jobs_all[num].traceback()
325 319 except KeyError:
326 320 error('Job #%s not found' % num)
327 321
328 322
329 323 class BackgroundJobBase(threading.Thread):
330 324 """Base class to build BackgroundJob classes.
331 325
332 326 The derived classes must implement:
333 327
334 328 - Their own __init__, since the one here raises NotImplementedError. The
335 329 derived constructor must call self._init() at the end, to provide common
336 330 initialization.
337 331
338 332 - A strform attribute used in calls to __str__.
339 333
340 334 - A call() method, which will make the actual execution call and must
341 335 return a value to be held in the 'result' field of the job object."""
342 336
343 337 # Class constants for status, in string and as numerical codes (when
344 338 # updating jobs lists, we don't want to do string comparisons). This will
345 339 # be done at every user prompt, so it has to be as fast as possible
346 340 stat_created = 'Created'; stat_created_c = 0
347 341 stat_running = 'Running'; stat_running_c = 1
348 342 stat_completed = 'Completed'; stat_completed_c = 2
349 343 stat_dead = 'Dead (Exception), call job.traceback() for details'
350 344 stat_dead_c = -1
351 345
352 346 def __init__(self):
353 347 raise NotImplementedError, \
354 348 "This class can not be instantiated directly."
355 349
356 350 def _init(self):
357 351 """Common initialization for all BackgroundJob objects"""
358 352
359 353 for attr in ['call','strform']:
360 354 assert hasattr(self,attr), "Missing attribute <%s>" % attr
361 355
362 356 # The num tag can be set by an external job manager
363 357 self.num = None
364 358
365 359 self.status = BackgroundJobBase.stat_created
366 360 self.stat_code = BackgroundJobBase.stat_created_c
367 361 self.finished = False
368 362 self.result = '<BackgroundJob has not completed>'
369 363 # reuse the ipython traceback handler if we can get to it, otherwise
370 364 # make a new one
371 365 try:
372 366 self._make_tb = __IPYTHON__.InteractiveTB.text
373 367 except:
374 368 self._make_tb = AutoFormattedTB(mode = 'Context',
375 369 color_scheme='NoColor',
376 370 tb_offset = 1).text
377 371 # Hold a formatted traceback if one is generated.
378 372 self._tb = None
379 373
380 374 threading.Thread.__init__(self)
381 375
382 376 def __str__(self):
383 377 return self.strform
384 378
385 379 def __repr__(self):
386 380 return '<BackgroundJob: %s>' % self.strform
387 381
388 382 def traceback(self):
389 383 print self._tb
390 384
391 385 def run(self):
392 386 try:
393 387 self.status = BackgroundJobBase.stat_running
394 388 self.stat_code = BackgroundJobBase.stat_running_c
395 389 self.result = self.call()
396 390 except:
397 391 self.status = BackgroundJobBase.stat_dead
398 392 self.stat_code = BackgroundJobBase.stat_dead_c
399 393 self.finished = None
400 394 self.result = ('<BackgroundJob died, call job.traceback() for details>')
401 395 self._tb = self._make_tb()
402 396 else:
403 397 self.status = BackgroundJobBase.stat_completed
404 398 self.stat_code = BackgroundJobBase.stat_completed_c
405 399 self.finished = True
406 400
407 401 class BackgroundJobExpr(BackgroundJobBase):
408 402 """Evaluate an expression as a background job (uses a separate thread)."""
409 403
410 404 def __init__(self,expression,glob=None,loc=None):
411 405 """Create a new job from a string which can be fed to eval().
412 406
413 407 global/locals dicts can be provided, which will be passed to the eval
414 408 call."""
415 409
416 410 # fail immediately if the given expression can't be compiled
417 411 self.code = compile(expression,'<BackgroundJob compilation>','eval')
418 412
419 413 if glob is None:
420 414 glob = {}
421 415 if loc is None:
422 416 loc = {}
423 417
424 418 self.expression = self.strform = expression
425 419 self.glob = glob
426 420 self.loc = loc
427 421 self._init()
428 422
429 423 def call(self):
430 424 return eval(self.code,self.glob,self.loc)
431 425
432 426 class BackgroundJobFunc(BackgroundJobBase):
433 427 """Run a function call as a background job (uses a separate thread)."""
434 428
435 429 def __init__(self,func,*args,**kwargs):
436 430 """Create a new job from a callable object.
437 431
438 432 Any positional arguments and keyword args given to this constructor
439 433 after the initial callable are passed directly to it."""
440 434
441 435 assert callable(func),'first argument must be callable'
442 436
443 437 if args is None:
444 438 args = []
445 439 if kwargs is None:
446 440 kwargs = {}
447 441
448 442 self.func = func
449 443 self.args = args
450 444 self.kwargs = kwargs
451 445 # The string form will only include the function passed, because
452 446 # generating string representations of the arguments is a potentially
453 447 # _very_ expensive operation (e.g. with large arrays).
454 448 self.strform = str(func)
455 449 self._init()
456 450
457 451 def call(self):
458 452 return self.func(*self.args,**self.kwargs)
459 453
460 454
461 455 if __name__=='__main__':
462 456
463 457 import time
464 458
465 459 def sleepfunc(interval=2,*a,**kw):
466 460 args = dict(interval=interval,
467 461 args=a,
468 462 kwargs=kw)
469 463 time.sleep(interval)
470 464 return args
471 465
472 466 def diefunc(interval=2,*a,**kw):
473 467 time.sleep(interval)
474 468 die
475 469
476 470 def printfunc(interval=1,reps=5):
477 471 for n in range(reps):
478 472 time.sleep(interval)
479 473 print 'In the background...'
480 474
481 475 jobs = BackgroundJobManager()
482 476 # first job will have # 0
483 477 jobs.new(sleepfunc,4)
484 478 jobs.new(sleepfunc,kw={'reps':2})
485 479 # This makes a job which will die
486 480 jobs.new(diefunc,1)
487 481 jobs.new('printfunc(1,3)')
488 482
489 483 # after a while, you can get the traceback of a dead job. Run the line
490 484 # below again interactively until it prints a traceback (check the status
491 485 # of the job):
492 486 print jobs[1].status
493 487 jobs[1].traceback()
494 488
495 489 # Run this line again until the printed result changes
496 490 print "The result of job #0 is:",jobs[0].result
@@ -1,189 +1,182 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 A module to change reload() so that it acts recursively.
4 4 To enable it type:
5 5 >>> import __builtin__, deep_reload
6 6 >>> __builtin__.reload = deep_reload.reload
7 7
8 8 You can then disable it with:
9 9 >>> __builtin__.reload = deep_reload.original_reload
10 10
11 11 Alternatively, you can add a dreload builtin alongside normal reload with:
12 12 >>> __builtin__.dreload = deep_reload.reload
13 13
14 14 This code is almost entirely based on knee.py from the standard library.
15
16 $Id: deep_reload.py 958 2005-12-27 23:17:51Z fperez $"""
15 """
17 16
18 17 #*****************************************************************************
19 18 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
20 19 #
21 20 # Distributed under the terms of the BSD License. The full license is in
22 21 # the file COPYING, distributed as part of this software.
23 22 #*****************************************************************************
24 23
25 from IPython import Release # do it explicitly so pydoc can see it - pydoc bug
26 __author__ = '%s <%s>' % Release.authors['Nathan']
27 __license__ = Release.license
28 __version__ = "0.5"
29 __date__ = "21 August 2001"
30
31 24 import __builtin__
32 25 import imp
33 26 import sys
34 27
35 28 # Replacement for __import__()
36 29 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
37 30 # For now level is ignored, it's just there to prevent crash
38 31 # with from __future__ import absolute_import
39 32 parent = determine_parent(globals)
40 33 q, tail = find_head_package(parent, name)
41 34 m = load_tail(q, tail)
42 35 if not fromlist:
43 36 return q
44 37 if hasattr(m, "__path__"):
45 38 ensure_fromlist(m, fromlist)
46 39 return m
47 40
48 41 def determine_parent(globals):
49 42 if not globals or not globals.has_key("__name__"):
50 43 return None
51 44 pname = globals['__name__']
52 45 if globals.has_key("__path__"):
53 46 parent = sys.modules[pname]
54 47 assert globals is parent.__dict__
55 48 return parent
56 49 if '.' in pname:
57 50 i = pname.rfind('.')
58 51 pname = pname[:i]
59 52 parent = sys.modules[pname]
60 53 assert parent.__name__ == pname
61 54 return parent
62 55 return None
63 56
64 57 def find_head_package(parent, name):
65 58 # Import the first
66 59 if '.' in name:
67 60 # 'some.nested.package' -> head = 'some', tail = 'nested.package'
68 61 i = name.find('.')
69 62 head = name[:i]
70 63 tail = name[i+1:]
71 64 else:
72 65 # 'packagename' -> head = 'packagename', tail = ''
73 66 head = name
74 67 tail = ""
75 68 if parent:
76 69 # If this is a subpackage then qname = parent's name + head
77 70 qname = "%s.%s" % (parent.__name__, head)
78 71 else:
79 72 qname = head
80 73 q = import_module(head, qname, parent)
81 74 if q: return q, tail
82 75 if parent:
83 76 qname = head
84 77 parent = None
85 78 q = import_module(head, qname, parent)
86 79 if q: return q, tail
87 80 raise ImportError, "No module named " + qname
88 81
89 82 def load_tail(q, tail):
90 83 m = q
91 84 while tail:
92 85 i = tail.find('.')
93 86 if i < 0: i = len(tail)
94 87 head, tail = tail[:i], tail[i+1:]
95 88
96 89 # fperez: fix dotted.name reloading failures by changing:
97 90 #mname = "%s.%s" % (m.__name__, head)
98 91 # to:
99 92 mname = m.__name__
100 93 # This needs more testing!!! (I don't understand this module too well)
101 94
102 95 #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg
103 96 m = import_module(head, mname, m)
104 97 if not m:
105 98 raise ImportError, "No module named " + mname
106 99 return m
107 100
108 101 def ensure_fromlist(m, fromlist, recursive=0):
109 102 for sub in fromlist:
110 103 if sub == "*":
111 104 if not recursive:
112 105 try:
113 106 all = m.__all__
114 107 except AttributeError:
115 108 pass
116 109 else:
117 110 ensure_fromlist(m, all, 1)
118 111 continue
119 112 if sub != "*" and not hasattr(m, sub):
120 113 subname = "%s.%s" % (m.__name__, sub)
121 114 submod = import_module(sub, subname, m)
122 115 if not submod:
123 116 raise ImportError, "No module named " + subname
124 117
125 118 # Need to keep track of what we've already reloaded to prevent cyclic evil
126 119 found_now = {}
127 120
128 121 def import_module(partname, fqname, parent):
129 122 global found_now
130 123 if found_now.has_key(fqname):
131 124 try:
132 125 return sys.modules[fqname]
133 126 except KeyError:
134 127 pass
135 128
136 129 print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \
137 130 #sys.displayhook is sys.__displayhook__
138 131
139 132 found_now[fqname] = 1
140 133 try:
141 134 fp, pathname, stuff = imp.find_module(partname,
142 135 parent and parent.__path__)
143 136 except ImportError:
144 137 return None
145 138
146 139 try:
147 140 m = imp.load_module(fqname, fp, pathname, stuff)
148 141 finally:
149 142 if fp: fp.close()
150 143
151 144 if parent:
152 145 setattr(parent, partname, m)
153 146
154 147 return m
155 148
156 149 def deep_reload_hook(module):
157 150 name = module.__name__
158 151 if '.' not in name:
159 152 return import_module(name, name, None)
160 153 i = name.rfind('.')
161 154 pname = name[:i]
162 155 parent = sys.modules[pname]
163 156 return import_module(name[i+1:], name, parent)
164 157
165 158 # Save the original hooks
166 159 original_reload = __builtin__.reload
167 160
168 161 # Replacement for reload()
169 162 def reload(module, exclude=['sys', '__builtin__', '__main__']):
170 163 """Recursively reload all modules used in the given module. Optionally
171 164 takes a list of modules to exclude from reloading. The default exclude
172 165 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
173 166 display, exception, and io hooks.
174 167 """
175 168 global found_now
176 169 for i in exclude:
177 170 found_now[i] = 1
178 171 original_import = __builtin__.__import__
179 172 __builtin__.__import__ = deep_import_hook
180 173 try:
181 174 ret = deep_reload_hook(module)
182 175 finally:
183 176 __builtin__.__import__ = original_import
184 177 found_now = {}
185 178 return ret
186 179
187 180 # Uncomment the following to automatically activate deep reloading whenever
188 181 # this module is imported
189 182 #__builtin__.reload = reload
@@ -1,143 +1,137 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Color schemes for exception handling code in IPython.
4
5 $Id: Prompts.py 638 2005-07-18 03:01:41Z fperez $"""
4 """
6 5
7 6 #*****************************************************************************
8 7 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
9 8 #
10 9 # Distributed under the terms of the BSD License. The full license is in
11 10 # the file COPYING, distributed as part of this software.
12 11 #*****************************************************************************
13 12
14 from IPython import Release
15 __author__ = '%s <%s>' % Release.authors['Fernando']
16 __license__ = Release.license
17 __version__ = Release.version
18
19 13 #****************************************************************************
20 14 # Required modules
21 15 from IPython.ColorANSI import ColorSchemeTable, TermColors, ColorScheme
22 16
23 17 def exception_colors():
24 18 """Return a color table with fields for exception reporting.
25 19
26 20 The table is an instance of ColorSchemeTable with schemes added for
27 21 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled
28 22 in.
29 23
30 24 Examples:
31 25
32 26 >>> ec = exception_colors()
33 27 >>> ec.active_scheme_name
34 28 ''
35 29 >>> print ec.active_colors
36 30 None
37 31
38 32 Now we activate a color scheme:
39 33 >>> ec.set_active_scheme('NoColor')
40 34 >>> ec.active_scheme_name
41 35 'NoColor'
42 36 >>> ec.active_colors.keys()
43 37 ['em', 'caret', '__allownew', 'name', 'val', 'vName', 'Normal', 'normalEm',
44 38 'filename', 'linenoEm', 'excName', 'lineno', 'valEm', 'filenameEm',
45 39 'nameEm', 'line', 'topline']
46 40 """
47 41
48 42 ex_colors = ColorSchemeTable()
49 43
50 44 # Populate it with color schemes
51 45 C = TermColors # shorthand and local lookup
52 46 ex_colors.add_scheme(ColorScheme(
53 47 'NoColor',
54 48 # The color to be used for the top line
55 49 topline = C.NoColor,
56 50
57 51 # The colors to be used in the traceback
58 52 filename = C.NoColor,
59 53 lineno = C.NoColor,
60 54 name = C.NoColor,
61 55 vName = C.NoColor,
62 56 val = C.NoColor,
63 57 em = C.NoColor,
64 58
65 59 # Emphasized colors for the last frame of the traceback
66 60 normalEm = C.NoColor,
67 61 filenameEm = C.NoColor,
68 62 linenoEm = C.NoColor,
69 63 nameEm = C.NoColor,
70 64 valEm = C.NoColor,
71 65
72 66 # Colors for printing the exception
73 67 excName = C.NoColor,
74 68 line = C.NoColor,
75 69 caret = C.NoColor,
76 70 Normal = C.NoColor
77 71 ))
78 72
79 73 # make some schemes as instances so we can copy them for modification easily
80 74 ex_colors.add_scheme(ColorScheme(
81 75 'Linux',
82 76 # The color to be used for the top line
83 77 topline = C.LightRed,
84 78
85 79 # The colors to be used in the traceback
86 80 filename = C.Green,
87 81 lineno = C.Green,
88 82 name = C.Purple,
89 83 vName = C.Cyan,
90 84 val = C.Green,
91 85 em = C.LightCyan,
92 86
93 87 # Emphasized colors for the last frame of the traceback
94 88 normalEm = C.LightCyan,
95 89 filenameEm = C.LightGreen,
96 90 linenoEm = C.LightGreen,
97 91 nameEm = C.LightPurple,
98 92 valEm = C.LightBlue,
99 93
100 94 # Colors for printing the exception
101 95 excName = C.LightRed,
102 96 line = C.Yellow,
103 97 caret = C.White,
104 98 Normal = C.Normal
105 99 ))
106 100
107 101 # For light backgrounds, swap dark/light colors
108 102 ex_colors.add_scheme(ColorScheme(
109 103 'LightBG',
110 104 # The color to be used for the top line
111 105 topline = C.Red,
112 106
113 107 # The colors to be used in the traceback
114 108 filename = C.LightGreen,
115 109 lineno = C.LightGreen,
116 110 name = C.LightPurple,
117 111 vName = C.Cyan,
118 112 val = C.LightGreen,
119 113 em = C.Cyan,
120 114
121 115 # Emphasized colors for the last frame of the traceback
122 116 normalEm = C.Cyan,
123 117 filenameEm = C.Green,
124 118 linenoEm = C.Green,
125 119 nameEm = C.Purple,
126 120 valEm = C.Blue,
127 121
128 122 # Colors for printing the exception
129 123 excName = C.Red,
130 124 #line = C.Brown, # brown often is displayed as yellow
131 125 line = C.Red,
132 126 caret = C.Normal,
133 127 Normal = C.Normal
134 128 ))
135 129
136 130 return ex_colors
137 131
138 132
139 133 # For backwards compatibility, keep around a single global object. Note that
140 134 # this should NOT be used, the factory function should be used instead, since
141 135 # these objects are stateful and it's very easy to get strange bugs if any code
142 136 # modifies the module-level object's state.
143 137 ExceptionColors = exception_colors()
@@ -1,278 +1,276 b''
1 1 # -*- coding: utf-8 -*-
2 2 """String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
3 3
4 4 This module lets you quickly and conveniently interpolate values into
5 5 strings (in the flavour of Perl or Tcl, but with less extraneous
6 6 punctuation). You get a bit more power than in the other languages,
7 7 because this module allows subscripting, slicing, function calls,
8 8 attribute lookup, or arbitrary expressions. Variables and expressions
9 9 are evaluated in the namespace of the caller.
10 10
11 11 The itpl() function returns the result of interpolating a string, and
12 12 printpl() prints out an interpolated string. Here are some examples:
13 13
14 14 from Itpl import printpl
15 15 printpl("Here is a $string.")
16 16 printpl("Here is a $module.member.")
17 17 printpl("Here is an $object.member.")
18 18 printpl("Here is a $functioncall(with, arguments).")
19 19 printpl("Here is an ${arbitrary + expression}.")
20 20 printpl("Here is an $array[3] member.")
21 21 printpl("Here is a $dictionary['member'].")
22 22
23 23 The filter() function filters a file object so that output through it
24 24 is interpolated. This lets you produce the illusion that Python knows
25 25 how to do interpolation:
26 26
27 27 import Itpl
28 28 sys.stdout = Itpl.filter()
29 29 f = "fancy"
30 print "Isn't this $f?"
30 print "Is this not $f?"
31 31 print "Standard output has been replaced with a $sys.stdout object."
32 32 sys.stdout = Itpl.unfilter()
33 33 print "Okay, back $to $normal."
34 34
35 35 Under the hood, the Itpl class represents a string that knows how to
36 36 interpolate values. An instance of the class parses the string once
37 37 upon initialization; the evaluation and substitution can then be done
38 38 each time the instance is evaluated with str(instance). For example:
39 39
40 40 from Itpl import Itpl
41 41 s = Itpl("Here is $foo.")
42 42 foo = 5
43 43 print str(s)
44 44 foo = "bar"
45 45 print str(s)
46
47 $Id: Itpl.py 2305 2007-05-04 05:34:42Z bgranger $
48 """ # ' -> close an open quote for stupid emacs
46 """
49 47
50 48 #*****************************************************************************
51 49 #
52 50 # Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
53 51 #
54 52 #
55 53 # Published under the terms of the MIT license, hereby reproduced:
56 54 #
57 55 # Permission is hereby granted, free of charge, to any person obtaining a copy
58 56 # of this software and associated documentation files (the "Software"), to
59 57 # deal in the Software without restriction, including without limitation the
60 58 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
61 59 # sell copies of the Software, and to permit persons to whom the Software is
62 60 # furnished to do so, subject to the following conditions:
63 61 #
64 62 # The above copyright notice and this permission notice shall be included in
65 63 # all copies or substantial portions of the Software.
66 64 #
67 65 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68 66 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69 67 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70 68 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71 69 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
72 70 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
73 71 # IN THE SOFTWARE.
74 72 #
75 73 #*****************************************************************************
76 74
77 75 __author__ = 'Ka-Ping Yee <ping@lfw.org>'
78 76 __license__ = 'MIT'
79 77
80 78 import string
81 79 import sys
82 80 from tokenize import tokenprog
83 81 from types import StringType
84 82
85 83 class ItplError(ValueError):
86 84 def __init__(self, text, pos):
87 85 self.text = text
88 86 self.pos = pos
89 87 def __str__(self):
90 88 return "unfinished expression in %s at char %d" % (
91 89 repr(self.text), self.pos)
92 90
93 91 def matchorfail(text, pos):
94 92 match = tokenprog.match(text, pos)
95 93 if match is None:
96 94 raise ItplError(text, pos)
97 95 return match, match.end()
98 96
99 97 class Itpl:
100 98 """Class representing a string with interpolation abilities.
101 99
102 100 Upon creation, an instance works out what parts of the format
103 101 string are literal and what parts need to be evaluated. The
104 102 evaluation and substitution happens in the namespace of the
105 103 caller when str(instance) is called."""
106 104
107 105 def __init__(self, format,codec='utf_8',encoding_errors='backslashreplace'):
108 106 """The single mandatory argument to this constructor is a format
109 107 string.
110 108
111 109 The format string is parsed according to the following rules:
112 110
113 111 1. A dollar sign and a name, possibly followed by any of:
114 112 - an open-paren, and anything up to the matching paren
115 113 - an open-bracket, and anything up to the matching bracket
116 114 - a period and a name
117 115 any number of times, is evaluated as a Python expression.
118 116
119 117 2. A dollar sign immediately followed by an open-brace, and
120 118 anything up to the matching close-brace, is evaluated as
121 119 a Python expression.
122 120
123 121 3. Outside of the expressions described in the above two rules,
124 122 two dollar signs in a row give you one literal dollar sign.
125 123
126 124 Optional arguments:
127 125
128 126 - codec('utf_8'): a string containing the name of a valid Python
129 127 codec.
130 128
131 129 - encoding_errors('backslashreplace'): a string with a valid error handling
132 130 policy. See the codecs module documentation for details.
133 131
134 132 These are used to encode the format string if a call to str() fails on
135 133 the expanded result."""
136 134
137 135 if not isinstance(format,basestring):
138 136 raise TypeError, "needs string initializer"
139 137 self.format = format
140 138 self.codec = codec
141 139 self.encoding_errors = encoding_errors
142 140
143 141 namechars = "abcdefghijklmnopqrstuvwxyz" \
144 142 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
145 143 chunks = []
146 144 pos = 0
147 145
148 146 while 1:
149 147 dollar = string.find(format, "$", pos)
150 148 if dollar < 0: break
151 149 nextchar = format[dollar+1]
152 150
153 151 if nextchar == "{":
154 152 chunks.append((0, format[pos:dollar]))
155 153 pos, level = dollar+2, 1
156 154 while level:
157 155 match, pos = matchorfail(format, pos)
158 156 tstart, tend = match.regs[3]
159 157 token = format[tstart:tend]
160 158 if token == "{": level = level+1
161 159 elif token == "}": level = level-1
162 160 chunks.append((1, format[dollar+2:pos-1]))
163 161
164 162 elif nextchar in namechars:
165 163 chunks.append((0, format[pos:dollar]))
166 164 match, pos = matchorfail(format, dollar+1)
167 165 while pos < len(format):
168 166 if format[pos] == "." and \
169 167 pos+1 < len(format) and format[pos+1] in namechars:
170 168 match, pos = matchorfail(format, pos+1)
171 169 elif format[pos] in "([":
172 170 pos, level = pos+1, 1
173 171 while level:
174 172 match, pos = matchorfail(format, pos)
175 173 tstart, tend = match.regs[3]
176 174 token = format[tstart:tend]
177 175 if token[0] in "([": level = level+1
178 176 elif token[0] in ")]": level = level-1
179 177 else: break
180 178 chunks.append((1, format[dollar+1:pos]))
181 179
182 180 else:
183 181 chunks.append((0, format[pos:dollar+1]))
184 182 pos = dollar + 1 + (nextchar == "$")
185 183
186 184 if pos < len(format): chunks.append((0, format[pos:]))
187 185 self.chunks = chunks
188 186
189 187 def __repr__(self):
190 188 return "<Itpl %s >" % repr(self.format)
191 189
192 190 def _str(self,glob,loc):
193 191 """Evaluate to a string in the given globals/locals.
194 192
195 193 The final output is built by calling str(), but if this fails, the
196 194 result is encoded with the instance's codec and error handling policy,
197 195 via a call to out.encode(self.codec,self.encoding_errors)"""
198 196 result = []
199 197 app = result.append
200 198 for live, chunk in self.chunks:
201 199 if live: app(str(eval(chunk,glob,loc)))
202 200 else: app(chunk)
203 201 out = ''.join(result)
204 202 try:
205 203 return str(out)
206 204 except UnicodeError:
207 205 return out.encode(self.codec,self.encoding_errors)
208 206
209 207 def __str__(self):
210 208 """Evaluate and substitute the appropriate parts of the string."""
211 209
212 210 # We need to skip enough frames to get to the actual caller outside of
213 211 # Itpl.
214 212 frame = sys._getframe(1)
215 213 while frame.f_globals["__name__"] == __name__: frame = frame.f_back
216 214 loc, glob = frame.f_locals, frame.f_globals
217 215
218 216 return self._str(glob,loc)
219 217
220 218 class ItplNS(Itpl):
221 219 """Class representing a string with interpolation abilities.
222 220
223 221 This inherits from Itpl, but at creation time a namespace is provided
224 222 where the evaluation will occur. The interpolation becomes a bit more
225 223 efficient, as no traceback needs to be extracte. It also allows the
226 224 caller to supply a different namespace for the interpolation to occur than
227 225 its own."""
228 226
229 227 def __init__(self, format,globals,locals=None,
230 228 codec='utf_8',encoding_errors='backslashreplace'):
231 229 """ItplNS(format,globals[,locals]) -> interpolating string instance.
232 230
233 231 This constructor, besides a format string, takes a globals dictionary
234 232 and optionally a locals (which defaults to globals if not provided).
235 233
236 234 For further details, see the Itpl constructor."""
237 235
238 236 if locals is None:
239 237 locals = globals
240 238 self.globals = globals
241 239 self.locals = locals
242 240 Itpl.__init__(self,format,codec,encoding_errors)
243 241
244 242 def __str__(self):
245 243 """Evaluate and substitute the appropriate parts of the string."""
246 244 return self._str(self.globals,self.locals)
247 245
248 246 def __repr__(self):
249 247 return "<ItplNS %s >" % repr(self.format)
250 248
251 249 # utilities for fast printing
252 250 def itpl(text): return str(Itpl(text))
253 251 def printpl(text): print itpl(text)
254 252 # versions with namespace
255 253 def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
256 254 def printplns(text,globals,locals=None): print itplns(text,globals,locals)
257 255
258 256 class ItplFile:
259 257 """A file object that filters each write() through an interpolator."""
260 258 def __init__(self, file): self.file = file
261 259 def __repr__(self): return "<interpolated " + repr(self.file) + ">"
262 260 def __getattr__(self, attr): return getattr(self.file, attr)
263 261 def write(self, text): self.file.write(str(Itpl(text)))
264 262
265 263 def filter(file=sys.stdout):
266 264 """Return an ItplFile that filters writes to the given file object.
267 265
268 266 'file = filter(file)' replaces 'file' with a filtered object that
269 267 has a write() method. When called with no argument, this creates
270 268 a filter to sys.stdout."""
271 269 return ItplFile(file)
272 270
273 271 def unfilter(ifile=None):
274 272 """Return the original file that corresponds to the given ItplFile.
275 273
276 274 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
277 275 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
278 276 return ifile and ifile.file or sys.stdout.file
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now