##// END OF EJS Templates
crlf -> lf
Ville M. Vainio -
Show More

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

@@ -1,170 +1,170 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for coloring text in ANSI terminals.
2 """Tools for coloring text in ANSI terminals.
3
3
4 $Id: ColorANSI.py 2167 2007-03-21 06:57:50Z fperez $"""
4 $Id: ColorANSI.py 2167 2007-03-21 06:57:50Z fperez $"""
5
5
6 #*****************************************************************************
6 #*****************************************************************************
7 # Copyright (C) 2002-2006 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2002-2006 Fernando Perez. <fperez@colorado.edu>
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #*****************************************************************************
11 #*****************************************************************************
12
12
13 from IPython import Release
13 from IPython import Release
14 __author__ = '%s <%s>' % Release.authors['Fernando']
14 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __license__ = Release.license
15 __license__ = Release.license
16
16
17 __all__ = ['TermColors','InputTermColors','ColorScheme','ColorSchemeTable']
17 __all__ = ['TermColors','InputTermColors','ColorScheme','ColorSchemeTable']
18
18
19 import os
19 import os
20
20
21 from IPython.ipstruct import Struct
21 from IPython.ipstruct import Struct
22
22
23 def make_color_table(in_class):
23 def make_color_table(in_class):
24 """Build a set of color attributes in a class.
24 """Build a set of color attributes in a class.
25
25
26 Helper function for building the *TermColors classes."""
26 Helper function for building the *TermColors classes."""
27
27
28 color_templates = (
28 color_templates = (
29 ("Black" , "0;30"),
29 ("Black" , "0;30"),
30 ("Red" , "0;31"),
30 ("Red" , "0;31"),
31 ("Green" , "0;32"),
31 ("Green" , "0;32"),
32 ("Brown" , "0;33"),
32 ("Brown" , "0;33"),
33 ("Blue" , "0;34"),
33 ("Blue" , "0;34"),
34 ("Purple" , "0;35"),
34 ("Purple" , "0;35"),
35 ("Cyan" , "0;36"),
35 ("Cyan" , "0;36"),
36 ("LightGray" , "0;37"),
36 ("LightGray" , "0;37"),
37 ("DarkGray" , "1;30"),
37 ("DarkGray" , "1;30"),
38 ("LightRed" , "1;31"),
38 ("LightRed" , "1;31"),
39 ("LightGreen" , "1;32"),
39 ("LightGreen" , "1;32"),
40 ("Yellow" , "1;33"),
40 ("Yellow" , "1;33"),
41 ("LightBlue" , "1;34"),
41 ("LightBlue" , "1;34"),
42 ("LightPurple" , "1;35"),
42 ("LightPurple" , "1;35"),
43 ("LightCyan" , "1;36"),
43 ("LightCyan" , "1;36"),
44 ("White" , "1;37"), )
44 ("White" , "1;37"), )
45
45
46 for name,value in color_templates:
46 for name,value in color_templates:
47 setattr(in_class,name,in_class._base % value)
47 setattr(in_class,name,in_class._base % value)
48
48
49 class TermColors:
49 class TermColors:
50 """Color escape sequences.
50 """Color escape sequences.
51
51
52 This class defines the escape sequences for all the standard (ANSI?)
52 This class defines the escape sequences for all the standard (ANSI?)
53 colors in terminals. Also defines a NoColor escape which is just the null
53 colors in terminals. Also defines a NoColor escape which is just the null
54 string, suitable for defining 'dummy' color schemes in terminals which get
54 string, suitable for defining 'dummy' color schemes in terminals which get
55 confused by color escapes.
55 confused by color escapes.
56
56
57 This class should be used as a mixin for building color schemes."""
57 This class should be used as a mixin for building color schemes."""
58
58
59 NoColor = '' # for color schemes in color-less terminals.
59 NoColor = '' # for color schemes in color-less terminals.
60 Normal = '\033[0m' # Reset normal coloring
60 Normal = '\033[0m' # Reset normal coloring
61 _base = '\033[%sm' # Template for all other colors
61 _base = '\033[%sm' # Template for all other colors
62
62
63 # Build the actual color table as a set of class attributes:
63 # Build the actual color table as a set of class attributes:
64 make_color_table(TermColors)
64 make_color_table(TermColors)
65
65
66 class InputTermColors:
66 class InputTermColors:
67 """Color escape sequences for input prompts.
67 """Color escape sequences for input prompts.
68
68
69 This class is similar to TermColors, but the escapes are wrapped in \001
69 This class is similar to TermColors, but the escapes are wrapped in \001
70 and \002 so that readline can properly know the length of each line and
70 and \002 so that readline can properly know the length of each line and
71 can wrap lines accordingly. Use this class for any colored text which
71 can wrap lines accordingly. Use this class for any colored text which
72 needs to be used in input prompts, such as in calls to raw_input().
72 needs to be used in input prompts, such as in calls to raw_input().
73
73
74 This class defines the escape sequences for all the standard (ANSI?)
74 This class defines the escape sequences for all the standard (ANSI?)
75 colors in terminals. Also defines a NoColor escape which is just the null
75 colors in terminals. Also defines a NoColor escape which is just the null
76 string, suitable for defining 'dummy' color schemes in terminals which get
76 string, suitable for defining 'dummy' color schemes in terminals which get
77 confused by color escapes.
77 confused by color escapes.
78
78
79 This class should be used as a mixin for building color schemes."""
79 This class should be used as a mixin for building color schemes."""
80
80
81 NoColor = '' # for color schemes in color-less terminals.
81 NoColor = '' # for color schemes in color-less terminals.
82
82
83 if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs':
83 if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs':
84 # (X)emacs on W32 gets confused with \001 and \002 so we remove them
84 # (X)emacs on W32 gets confused with \001 and \002 so we remove them
85 Normal = '\033[0m' # Reset normal coloring
85 Normal = '\033[0m' # Reset normal coloring
86 _base = '\033[%sm' # Template for all other colors
86 _base = '\033[%sm' # Template for all other colors
87 else:
87 else:
88 Normal = '\001\033[0m\002' # Reset normal coloring
88 Normal = '\001\033[0m\002' # Reset normal coloring
89 _base = '\001\033[%sm\002' # Template for all other colors
89 _base = '\001\033[%sm\002' # Template for all other colors
90
90
91 # Build the actual color table as a set of class attributes:
91 # Build the actual color table as a set of class attributes:
92 make_color_table(InputTermColors)
92 make_color_table(InputTermColors)
93
93
94 class ColorScheme:
94 class ColorScheme:
95 """Generic color scheme class. Just a name and a Struct."""
95 """Generic color scheme class. Just a name and a Struct."""
96 def __init__(self,__scheme_name_,colordict=None,**colormap):
96 def __init__(self,__scheme_name_,colordict=None,**colormap):
97 self.name = __scheme_name_
97 self.name = __scheme_name_
98 if colordict is None:
98 if colordict is None:
99 self.colors = Struct(**colormap)
99 self.colors = Struct(**colormap)
100 else:
100 else:
101 self.colors = Struct(colordict)
101 self.colors = Struct(colordict)
102
102
103 def copy(self,name=None):
103 def copy(self,name=None):
104 """Return a full copy of the object, optionally renaming it."""
104 """Return a full copy of the object, optionally renaming it."""
105 if name is None:
105 if name is None:
106 name = self.name
106 name = self.name
107 return ColorScheme(name,self.colors.__dict__)
107 return ColorScheme(name,self.colors.__dict__)
108
108
109 class ColorSchemeTable(dict):
109 class ColorSchemeTable(dict):
110 """General class to handle tables of color schemes.
110 """General class to handle tables of color schemes.
111
111
112 It's basically a dict of color schemes with a couple of shorthand
112 It's basically a dict of color schemes with a couple of shorthand
113 attributes and some convenient methods.
113 attributes and some convenient methods.
114
114
115 active_scheme_name -> obvious
115 active_scheme_name -> obvious
116 active_colors -> actual color table of the active scheme"""
116 active_colors -> actual color table of the active scheme"""
117
117
118 def __init__(self,scheme_list=None,default_scheme=''):
118 def __init__(self,scheme_list=None,default_scheme=''):
119 """Create a table of color schemes.
119 """Create a table of color schemes.
120
120
121 The table can be created empty and manually filled or it can be
121 The table can be created empty and manually filled or it can be
122 created with a list of valid color schemes AND the specification for
122 created with a list of valid color schemes AND the specification for
123 the default active scheme.
123 the default active scheme.
124 """
124 """
125
125
126 # create object attributes to be set later
126 # create object attributes to be set later
127 self.active_scheme_name = ''
127 self.active_scheme_name = ''
128 self.active_colors = None
128 self.active_colors = None
129
129
130 if scheme_list:
130 if scheme_list:
131 if default_scheme == '':
131 if default_scheme == '':
132 raise ValueError,'you must specify the default color scheme'
132 raise ValueError,'you must specify the default color scheme'
133 for scheme in scheme_list:
133 for scheme in scheme_list:
134 self.add_scheme(scheme)
134 self.add_scheme(scheme)
135 self.set_active_scheme(default_scheme)
135 self.set_active_scheme(default_scheme)
136
136
137 def copy(self):
137 def copy(self):
138 """Return full copy of object"""
138 """Return full copy of object"""
139 return ColorSchemeTable(self.values(),self.active_scheme_name)
139 return ColorSchemeTable(self.values(),self.active_scheme_name)
140
140
141 def add_scheme(self,new_scheme):
141 def add_scheme(self,new_scheme):
142 """Add a new color scheme to the table."""
142 """Add a new color scheme to the table."""
143 if not isinstance(new_scheme,ColorScheme):
143 if not isinstance(new_scheme,ColorScheme):
144 raise ValueError,'ColorSchemeTable only accepts ColorScheme instances'
144 raise ValueError,'ColorSchemeTable only accepts ColorScheme instances'
145 self[new_scheme.name] = new_scheme
145 self[new_scheme.name] = new_scheme
146
146
147 def set_active_scheme(self,scheme,case_sensitive=0):
147 def set_active_scheme(self,scheme,case_sensitive=0):
148 """Set the currently active scheme.
148 """Set the currently active scheme.
149
149
150 Names are by default compared in a case-insensitive way, but this can
150 Names are by default compared in a case-insensitive way, but this can
151 be changed by setting the parameter case_sensitive to true."""
151 be changed by setting the parameter case_sensitive to true."""
152
152
153 scheme_names = self.keys()
153 scheme_names = self.keys()
154 if case_sensitive:
154 if case_sensitive:
155 valid_schemes = scheme_names
155 valid_schemes = scheme_names
156 scheme_test = scheme
156 scheme_test = scheme
157 else:
157 else:
158 valid_schemes = [s.lower() for s in scheme_names]
158 valid_schemes = [s.lower() for s in scheme_names]
159 scheme_test = scheme.lower()
159 scheme_test = scheme.lower()
160 try:
160 try:
161 scheme_idx = valid_schemes.index(scheme_test)
161 scheme_idx = valid_schemes.index(scheme_test)
162 except ValueError:
162 except ValueError:
163 raise ValueError,'Unrecognized color scheme: ' + scheme + \
163 raise ValueError,'Unrecognized color scheme: ' + scheme + \
164 '\nValid schemes: '+str(scheme_names).replace("'', ",'')
164 '\nValid schemes: '+str(scheme_names).replace("'', ",'')
165 else:
165 else:
166 active = scheme_names[scheme_idx]
166 active = scheme_names[scheme_idx]
167 self.active_scheme_name = active
167 self.active_scheme_name = active
168 self.active_colors = self[active].colors
168 self.active_colors = self[active].colors
169 # Now allow using '' as an index for the current active scheme
169 # Now allow using '' as an index for the current active scheme
170 self[''] = self[active]
170 self[''] = self[active]
@@ -1,116 +1,116 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Configuration loader
2 """Configuration loader
3
3
4 $Id: ConfigLoader.py 1005 2006-01-12 08:39:26Z fperez $"""
4 $Id: ConfigLoader.py 1005 2006-01-12 08:39:26Z fperez $"""
5
5
6 #*****************************************************************************
6 #*****************************************************************************
7 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #*****************************************************************************
11 #*****************************************************************************
12
12
13 from IPython import Release
13 from IPython import Release
14 __author__ = '%s <%s>' % Release.authors['Fernando']
14 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __license__ = Release.license
15 __license__ = Release.license
16
16
17 import exceptions
17 import exceptions
18 import os
18 import os
19 from pprint import pprint
19 from pprint import pprint
20
20
21 from IPython import ultraTB
21 from IPython import ultraTB
22 from IPython.ipstruct import Struct
22 from IPython.ipstruct import Struct
23 from IPython.genutils import *
23 from IPython.genutils import *
24
24
25 class ConfigLoaderError(exceptions.Exception):
25 class ConfigLoaderError(exceptions.Exception):
26 """Exception for ConfigLoader class."""
26 """Exception for ConfigLoader class."""
27
27
28 def __init__(self,args=None):
28 def __init__(self,args=None):
29 self.args = args
29 self.args = args
30
30
31 class ConfigLoader:
31 class ConfigLoader:
32
32
33 """Configuration file loader capable of handling recursive inclusions and
33 """Configuration file loader capable of handling recursive inclusions and
34 with parametrized conflict resolution for multiply found keys."""
34 with parametrized conflict resolution for multiply found keys."""
35
35
36 def __init__(self,conflict=None,field_sep=None,reclimit=15):
36 def __init__(self,conflict=None,field_sep=None,reclimit=15):
37
37
38 """The reclimit parameter controls the number of recursive
38 """The reclimit parameter controls the number of recursive
39 configuration file inclusions. This way we can stop early on (before
39 configuration file inclusions. This way we can stop early on (before
40 python's own recursion limit is hit) if there is a circular
40 python's own recursion limit is hit) if there is a circular
41 inclusion.
41 inclusion.
42
42
43 - conflict: dictionary for conflict resolutions (see Struct.merge())
43 - conflict: dictionary for conflict resolutions (see Struct.merge())
44
44
45 """
45 """
46 self.conflict = conflict
46 self.conflict = conflict
47 self.field_sep = field_sep
47 self.field_sep = field_sep
48 self.reset(reclimit)
48 self.reset(reclimit)
49
49
50 def reset(self,reclimit=15):
50 def reset(self,reclimit=15):
51 self.reclimit = reclimit
51 self.reclimit = reclimit
52 self.recdepth = 0
52 self.recdepth = 0
53 self.included = []
53 self.included = []
54
54
55 def load(self,fname,convert=None,recurse_key='',incpath = '.',**kw):
55 def load(self,fname,convert=None,recurse_key='',incpath = '.',**kw):
56 """Load a configuration file, return the resulting Struct.
56 """Load a configuration file, return the resulting Struct.
57
57
58 Call: load_config(fname,convert=None,conflict=None,recurse_key='')
58 Call: load_config(fname,convert=None,conflict=None,recurse_key='')
59
59
60 - fname: file to load from.
60 - fname: file to load from.
61 - convert: dictionary of type conversions (see read_dict())
61 - convert: dictionary of type conversions (see read_dict())
62 - recurse_key: keyword in dictionary to trigger recursive file
62 - recurse_key: keyword in dictionary to trigger recursive file
63 inclusions.
63 inclusions.
64 """
64 """
65
65
66 if self.recdepth > self.reclimit:
66 if self.recdepth > self.reclimit:
67 raise ConfigLoaderError, 'maximum recursive inclusion of rcfiles '+\
67 raise ConfigLoaderError, 'maximum recursive inclusion of rcfiles '+\
68 'exceeded: ' + `self.recdepth` + \
68 'exceeded: ' + `self.recdepth` + \
69 '.\nMaybe you have a circular chain of inclusions?'
69 '.\nMaybe you have a circular chain of inclusions?'
70 self.recdepth += 1
70 self.recdepth += 1
71 fname = filefind(fname,incpath)
71 fname = filefind(fname,incpath)
72 data = Struct()
72 data = Struct()
73 # avoid including the same file more than once
73 # avoid including the same file more than once
74 if fname in self.included:
74 if fname in self.included:
75 return data
75 return data
76 Xinfo = ultraTB.AutoFormattedTB()
76 Xinfo = ultraTB.AutoFormattedTB()
77 if convert==None and recurse_key : convert = {qwflat:recurse_key}
77 if convert==None and recurse_key : convert = {qwflat:recurse_key}
78 # for production, change warn to 0:
78 # for production, change warn to 0:
79 data.merge(read_dict(fname,convert,fs=self.field_sep,strip=1,
79 data.merge(read_dict(fname,convert,fs=self.field_sep,strip=1,
80 warn=0,no_empty=0,**kw))
80 warn=0,no_empty=0,**kw))
81 # keep track of successfully loaded files
81 # keep track of successfully loaded files
82 self.included.append(fname)
82 self.included.append(fname)
83 if recurse_key in data.keys():
83 if recurse_key in data.keys():
84 for incfilename in data[recurse_key]:
84 for incfilename in data[recurse_key]:
85 found=0
85 found=0
86 try:
86 try:
87 incfile = filefind(incfilename,incpath)
87 incfile = filefind(incfilename,incpath)
88 except IOError:
88 except IOError:
89 if os.name in ['nt','dos']:
89 if os.name in ['nt','dos']:
90 try:
90 try:
91 # Try again with '.ini' extension
91 # Try again with '.ini' extension
92 incfilename += '.ini'
92 incfilename += '.ini'
93 incfile = filefind(incfilename,incpath)
93 incfile = filefind(incfilename,incpath)
94 except IOError:
94 except IOError:
95 found = 0
95 found = 0
96 else:
96 else:
97 found = 1
97 found = 1
98 else:
98 else:
99 found = 0
99 found = 0
100 else:
100 else:
101 found = 1
101 found = 1
102 if found:
102 if found:
103 try:
103 try:
104 data.merge(self.load(incfile,convert,recurse_key,
104 data.merge(self.load(incfile,convert,recurse_key,
105 incpath,**kw),
105 incpath,**kw),
106 self.conflict)
106 self.conflict)
107 except:
107 except:
108 Xinfo()
108 Xinfo()
109 warn('Problem loading included file: '+
109 warn('Problem loading included file: '+
110 `incfilename` + '. Ignoring it...')
110 `incfilename` + '. Ignoring it...')
111 else:
111 else:
112 warn('File `%s` not found. Included by %s' % (incfilename,fname))
112 warn('File `%s` not found. Included by %s' % (incfilename,fname))
113
113
114 return data
114 return data
115
115
116 # end ConfigLoader
116 # end ConfigLoader
@@ -1,228 +1,228 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 $Id: CrashHandler.py 2908 2007-12-30 21:07:46Z vivainio $"""
4 $Id: CrashHandler.py 2908 2007-12-30 21:07:46Z vivainio $"""
5
5
6 #*****************************************************************************
6 #*****************************************************************************
7 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #*****************************************************************************
11 #*****************************************************************************
12
12
13 from IPython import Release
13 from IPython import Release
14 __author__ = '%s <%s>' % Release.authors['Fernando']
14 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __license__ = Release.license
15 __license__ = Release.license
16 __version__ = Release.version
16 __version__ = Release.version
17
17
18 #****************************************************************************
18 #****************************************************************************
19 # Required modules
19 # Required modules
20
20
21 # From the standard library
21 # From the standard library
22 import os
22 import os
23 import sys
23 import sys
24 from pprint import pprint,pformat
24 from pprint import pprint,pformat
25
25
26 # Homebrewed
26 # Homebrewed
27 from IPython.Itpl import Itpl,itpl,printpl
27 from IPython.Itpl import Itpl,itpl,printpl
28 from IPython.ColorANSI import ColorScheme,ColorSchemeTable # too long names
28 from IPython.ColorANSI import ColorScheme,ColorSchemeTable # too long names
29 from IPython import ultraTB
29 from IPython import ultraTB
30 from IPython.genutils import *
30 from IPython.genutils import *
31
31
32 #****************************************************************************
32 #****************************************************************************
33 class CrashHandler:
33 class CrashHandler:
34 """Customizable crash handlers for IPython-based systems.
34 """Customizable crash handlers for IPython-based systems.
35
35
36 Instances of this class provide a __call__ method which can be used as a
36 Instances of this class provide a __call__ method which can be used as a
37 sys.excepthook, i.e., the __call__ signature is:
37 sys.excepthook, i.e., the __call__ signature is:
38
38
39 def __call__(self,etype, evalue, etb)
39 def __call__(self,etype, evalue, etb)
40
40
41 """
41 """
42
42
43 def __init__(self,IP,app_name,contact_name,contact_email,
43 def __init__(self,IP,app_name,contact_name,contact_email,
44 bug_tracker,crash_report_fname,
44 bug_tracker,crash_report_fname,
45 show_crash_traceback=True):
45 show_crash_traceback=True):
46 """New crash handler.
46 """New crash handler.
47
47
48 Inputs:
48 Inputs:
49
49
50 - IP: a running IPython instance, which will be queried at crash time
50 - IP: a running IPython instance, which will be queried at crash time
51 for internal information.
51 for internal information.
52
52
53 - app_name: a string containing the name of your application.
53 - app_name: a string containing the name of your application.
54
54
55 - contact_name: a string with the name of the person to contact.
55 - contact_name: a string with the name of the person to contact.
56
56
57 - contact_email: a string with the email address of the contact.
57 - contact_email: a string with the email address of the contact.
58
58
59 - bug_tracker: a string with the URL for your project's bug tracker.
59 - bug_tracker: a string with the URL for your project's bug tracker.
60
60
61 - crash_report_fname: a string with the filename for the crash report
61 - crash_report_fname: a string with the filename for the crash report
62 to be saved in. These reports are left in the ipython user directory
62 to be saved in. These reports are left in the ipython user directory
63 as determined by the running IPython instance.
63 as determined by the running IPython instance.
64
64
65 Optional inputs:
65 Optional inputs:
66
66
67 - show_crash_traceback(True): if false, don't print the crash
67 - show_crash_traceback(True): if false, don't print the crash
68 traceback on stderr, only generate the on-disk report
68 traceback on stderr, only generate the on-disk report
69
69
70
70
71 Non-argument instance attributes:
71 Non-argument instance attributes:
72
72
73 These instances contain some non-argument attributes which allow for
73 These instances contain some non-argument attributes which allow for
74 further customization of the crash handler's behavior. Please see the
74 further customization of the crash handler's behavior. Please see the
75 source for further details.
75 source for further details.
76 """
76 """
77
77
78 # apply args into instance
78 # apply args into instance
79 self.IP = IP # IPython instance
79 self.IP = IP # IPython instance
80 self.app_name = app_name
80 self.app_name = app_name
81 self.contact_name = contact_name
81 self.contact_name = contact_name
82 self.contact_email = contact_email
82 self.contact_email = contact_email
83 self.bug_tracker = bug_tracker
83 self.bug_tracker = bug_tracker
84 self.crash_report_fname = crash_report_fname
84 self.crash_report_fname = crash_report_fname
85 self.show_crash_traceback = show_crash_traceback
85 self.show_crash_traceback = show_crash_traceback
86
86
87 # Hardcoded defaults, which can be overridden either by subclasses or
87 # Hardcoded defaults, which can be overridden either by subclasses or
88 # at runtime for the instance.
88 # at runtime for the instance.
89
89
90 # Template for the user message. Subclasses which completely override
90 # Template for the user message. Subclasses which completely override
91 # this, or user apps, can modify it to suit their tastes. It gets
91 # this, or user apps, can modify it to suit their tastes. It gets
92 # expanded using itpl, so calls of the kind $self.foo are valid.
92 # expanded using itpl, so calls of the kind $self.foo are valid.
93 self.user_message_template = """
93 self.user_message_template = """
94 Oops, $self.app_name crashed. We do our best to make it stable, but...
94 Oops, $self.app_name crashed. We do our best to make it stable, but...
95
95
96 A crash report was automatically generated with the following information:
96 A crash report was automatically generated with the following information:
97 - A verbatim copy of the crash traceback.
97 - A verbatim copy of the crash traceback.
98 - A copy of your input history during this session.
98 - A copy of your input history during this session.
99 - Data on your current $self.app_name configuration.
99 - Data on your current $self.app_name configuration.
100
100
101 It was left in the file named:
101 It was left in the file named:
102 \t'$self.crash_report_fname'
102 \t'$self.crash_report_fname'
103 If you can email this file to the developers, the information in it will help
103 If you can email this file to the developers, the information in it will help
104 them in understanding and correcting the problem.
104 them in understanding and correcting the problem.
105
105
106 You can mail it to: $self.contact_name at $self.contact_email
106 You can mail it to: $self.contact_name at $self.contact_email
107 with the subject '$self.app_name Crash Report'.
107 with the subject '$self.app_name Crash Report'.
108
108
109 If you want to do it now, the following command will work (under Unix):
109 If you want to do it now, the following command will work (under Unix):
110 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
110 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
111
111
112 To ensure accurate tracking of this issue, please file a report about it at:
112 To ensure accurate tracking of this issue, please file a report about it at:
113 $self.bug_tracker
113 $self.bug_tracker
114 """
114 """
115
115
116 def __call__(self,etype, evalue, etb):
116 def __call__(self,etype, evalue, etb):
117 """Handle an exception, call for compatible with sys.excepthook"""
117 """Handle an exception, call for compatible with sys.excepthook"""
118
118
119 # Report tracebacks shouldn't use color in general (safer for users)
119 # Report tracebacks shouldn't use color in general (safer for users)
120 color_scheme = 'NoColor'
120 color_scheme = 'NoColor'
121
121
122 # Use this ONLY for developer debugging (keep commented out for release)
122 # Use this ONLY for developer debugging (keep commented out for release)
123 #color_scheme = 'Linux' # dbg
123 #color_scheme = 'Linux' # dbg
124
124
125 try:
125 try:
126 rptdir = self.IP.rc.ipythondir
126 rptdir = self.IP.rc.ipythondir
127 except:
127 except:
128 rptdir = os.getcwd()
128 rptdir = os.getcwd()
129 if not os.path.isdir(rptdir):
129 if not os.path.isdir(rptdir):
130 rptdir = os.getcwd()
130 rptdir = os.getcwd()
131 report_name = os.path.join(rptdir,self.crash_report_fname)
131 report_name = os.path.join(rptdir,self.crash_report_fname)
132 # write the report filename into the instance dict so it can get
132 # write the report filename into the instance dict so it can get
133 # properly expanded out in the user message template
133 # properly expanded out in the user message template
134 self.crash_report_fname = report_name
134 self.crash_report_fname = report_name
135 TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,
135 TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,
136 long_header=1)
136 long_header=1)
137 traceback = TBhandler.text(etype,evalue,etb,context=31)
137 traceback = TBhandler.text(etype,evalue,etb,context=31)
138
138
139 # print traceback to screen
139 # print traceback to screen
140 if self.show_crash_traceback:
140 if self.show_crash_traceback:
141 print >> sys.stderr, traceback
141 print >> sys.stderr, traceback
142
142
143 # and generate a complete report on disk
143 # and generate a complete report on disk
144 try:
144 try:
145 report = open(report_name,'w')
145 report = open(report_name,'w')
146 except:
146 except:
147 print >> sys.stderr, 'Could not create crash report on disk.'
147 print >> sys.stderr, 'Could not create crash report on disk.'
148 return
148 return
149
149
150 # Inform user on stderr of what happened
150 # Inform user on stderr of what happened
151 msg = itpl('\n'+'*'*70+'\n'+self.user_message_template)
151 msg = itpl('\n'+'*'*70+'\n'+self.user_message_template)
152 print >> sys.stderr, msg
152 print >> sys.stderr, msg
153
153
154 # Construct report on disk
154 # Construct report on disk
155 report.write(self.make_report(traceback))
155 report.write(self.make_report(traceback))
156 report.close()
156 report.close()
157 raw_input("Press enter to exit:")
157 raw_input("Press enter to exit:")
158
158
159 def make_report(self,traceback):
159 def make_report(self,traceback):
160 """Return a string containing a crash report."""
160 """Return a string containing a crash report."""
161
161
162 sec_sep = '\n\n'+'*'*75+'\n\n'
162 sec_sep = '\n\n'+'*'*75+'\n\n'
163
163
164 report = []
164 report = []
165 rpt_add = report.append
165 rpt_add = report.append
166
166
167 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
167 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
168 rpt_add('IPython version: %s \n\n' % Release.version)
168 rpt_add('IPython version: %s \n\n' % Release.version)
169 rpt_add('SVN revision : %s \n\n' % Release.revision)
169 rpt_add('SVN revision : %s \n\n' % Release.revision)
170 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
170 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
171 (os.name,sys.platform) )
171 (os.name,sys.platform) )
172 rpt_add(sec_sep+'Current user configuration structure:\n\n')
172 rpt_add(sec_sep+'Current user configuration structure:\n\n')
173 rpt_add(pformat(self.IP.rc.dict()))
173 rpt_add(pformat(self.IP.rc.dict()))
174 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
174 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
175 try:
175 try:
176 rpt_add(sec_sep+"History of session input:")
176 rpt_add(sec_sep+"History of session input:")
177 for line in self.IP.user_ns['_ih']:
177 for line in self.IP.user_ns['_ih']:
178 rpt_add(line)
178 rpt_add(line)
179 rpt_add('\n*** Last line of input (may not be in above history):\n')
179 rpt_add('\n*** Last line of input (may not be in above history):\n')
180 rpt_add(self.IP._last_input_line+'\n')
180 rpt_add(self.IP._last_input_line+'\n')
181 except:
181 except:
182 pass
182 pass
183
183
184 return ''.join(report)
184 return ''.join(report)
185
185
186 class IPythonCrashHandler(CrashHandler):
186 class IPythonCrashHandler(CrashHandler):
187 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
187 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
188
188
189 def __init__(self,IP):
189 def __init__(self,IP):
190
190
191 # Set here which of the IPython authors should be listed as contact
191 # Set here which of the IPython authors should be listed as contact
192 AUTHOR_CONTACT = 'Ville'
192 AUTHOR_CONTACT = 'Ville'
193
193
194 # Set argument defaults
194 # Set argument defaults
195 app_name = 'IPython'
195 app_name = 'IPython'
196 bug_tracker = 'http://projects.scipy.org/ipython/ipython/report'
196 bug_tracker = 'http://projects.scipy.org/ipython/ipython/report'
197 contact_name,contact_email = Release.authors[AUTHOR_CONTACT][:2]
197 contact_name,contact_email = Release.authors[AUTHOR_CONTACT][:2]
198 crash_report_fname = 'IPython_crash_report.txt'
198 crash_report_fname = 'IPython_crash_report.txt'
199 # Call parent constructor
199 # Call parent constructor
200 CrashHandler.__init__(self,IP,app_name,contact_name,contact_email,
200 CrashHandler.__init__(self,IP,app_name,contact_name,contact_email,
201 bug_tracker,crash_report_fname)
201 bug_tracker,crash_report_fname)
202
202
203 def make_report(self,traceback):
203 def make_report(self,traceback):
204 """Return a string containing a crash report."""
204 """Return a string containing a crash report."""
205
205
206 sec_sep = '\n\n'+'*'*75+'\n\n'
206 sec_sep = '\n\n'+'*'*75+'\n\n'
207
207
208 report = []
208 report = []
209 rpt_add = report.append
209 rpt_add = report.append
210
210
211 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
211 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
212 rpt_add('IPython version: %s \n\n' % Release.version)
212 rpt_add('IPython version: %s \n\n' % Release.version)
213 rpt_add('SVN revision : %s \n\n' % Release.revision)
213 rpt_add('SVN revision : %s \n\n' % Release.revision)
214 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
214 rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
215 (os.name,sys.platform) )
215 (os.name,sys.platform) )
216 rpt_add(sec_sep+'Current user configuration structure:\n\n')
216 rpt_add(sec_sep+'Current user configuration structure:\n\n')
217 rpt_add(pformat(self.IP.rc.dict()))
217 rpt_add(pformat(self.IP.rc.dict()))
218 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
218 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
219 try:
219 try:
220 rpt_add(sec_sep+"History of session input:")
220 rpt_add(sec_sep+"History of session input:")
221 for line in self.IP.user_ns['_ih']:
221 for line in self.IP.user_ns['_ih']:
222 rpt_add(line)
222 rpt_add(line)
223 rpt_add('\n*** Last line of input (may not be in above history):\n')
223 rpt_add('\n*** Last line of input (may not be in above history):\n')
224 rpt_add(self.IP._last_input_line+'\n')
224 rpt_add(self.IP._last_input_line+'\n')
225 except:
225 except:
226 pass
226 pass
227
227
228 return ''.join(report)
228 return ''.join(report)
This diff has been collapsed as it changes many lines, (1386 lines changed) Show them Hide them
@@ -1,693 +1,693 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """DPyGetOpt -- Demiurge Python GetOptions Module
2 """DPyGetOpt -- Demiurge Python GetOptions Module
3
3
4 $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $
4 $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $
5
5
6 This module is modeled after perl's Getopt::Long module-- which
6 This module is modeled after perl's Getopt::Long module-- which
7 is, in turn, modeled after GNU's extended getopt() function.
7 is, in turn, modeled after GNU's extended getopt() function.
8
8
9 Upon instantiation, the option specification should be a sequence
9 Upon instantiation, the option specification should be a sequence
10 (list) of option definitions.
10 (list) of option definitions.
11
11
12 Options that take no arguments should simply contain the name of
12 Options that take no arguments should simply contain the name of
13 the option. If a ! is post-pended, the option can be negated by
13 the option. If a ! is post-pended, the option can be negated by
14 prepending 'no'; ie 'debug!' specifies that -debug and -nodebug
14 prepending 'no'; ie 'debug!' specifies that -debug and -nodebug
15 should be accepted.
15 should be accepted.
16
16
17 Mandatory arguments to options are specified using a postpended
17 Mandatory arguments to options are specified using a postpended
18 '=' + a type specifier. '=s' specifies a mandatory string
18 '=' + a type specifier. '=s' specifies a mandatory string
19 argument, '=i' specifies a mandatory integer argument, and '=f'
19 argument, '=i' specifies a mandatory integer argument, and '=f'
20 specifies a mandatory real number. In all cases, the '=' can be
20 specifies a mandatory real number. In all cases, the '=' can be
21 substituted with ':' to specify that the argument is optional.
21 substituted with ':' to specify that the argument is optional.
22
22
23 Dashes '-' in option names are allowed.
23 Dashes '-' in option names are allowed.
24
24
25 If an option has the character '@' postpended (after the
25 If an option has the character '@' postpended (after the
26 argumentation specification), it can appear multiple times within
26 argumentation specification), it can appear multiple times within
27 each argument list that is processed. The results will be stored
27 each argument list that is processed. The results will be stored
28 in a list.
28 in a list.
29
29
30 The option name can actually be a list of names separated by '|'
30 The option name can actually be a list of names separated by '|'
31 characters; ie-- 'foo|bar|baz=f@' specifies that all -foo, -bar,
31 characters; ie-- 'foo|bar|baz=f@' specifies that all -foo, -bar,
32 and -baz options that appear on within the parsed argument list
32 and -baz options that appear on within the parsed argument list
33 must have a real number argument and that the accumulated list
33 must have a real number argument and that the accumulated list
34 of values will be available under the name 'foo'
34 of values will be available under the name 'foo'
35
35
36 $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $"""
36 $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $"""
37
37
38 #*****************************************************************************
38 #*****************************************************************************
39 #
39 #
40 # Copyright (c) 2001 Bill Bumgarner <bbum@friday.com>
40 # Copyright (c) 2001 Bill Bumgarner <bbum@friday.com>
41 #
41 #
42 #
42 #
43 # Published under the terms of the MIT license, hereby reproduced:
43 # Published under the terms of the MIT license, hereby reproduced:
44 #
44 #
45 # Permission is hereby granted, free of charge, to any person obtaining a copy
45 # Permission is hereby granted, free of charge, to any person obtaining a copy
46 # of this software and associated documentation files (the "Software"), to
46 # of this software and associated documentation files (the "Software"), to
47 # deal in the Software without restriction, including without limitation the
47 # deal in the Software without restriction, including without limitation the
48 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
48 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
49 # sell copies of the Software, and to permit persons to whom the Software is
49 # sell copies of the Software, and to permit persons to whom the Software is
50 # furnished to do so, subject to the following conditions:
50 # furnished to do so, subject to the following conditions:
51 #
51 #
52 # The above copyright notice and this permission notice shall be included in
52 # The above copyright notice and this permission notice shall be included in
53 # all copies or substantial portions of the Software.
53 # all copies or substantial portions of the Software.
54 #
54 #
55 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
59 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
60 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
60 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
61 # IN THE SOFTWARE.
61 # IN THE SOFTWARE.
62 #
62 #
63 #*****************************************************************************
63 #*****************************************************************************
64
64
65 __author__ = 'Bill Bumgarner <bbum@friday.com>'
65 __author__ = 'Bill Bumgarner <bbum@friday.com>'
66 __license__ = 'MIT'
66 __license__ = 'MIT'
67 __version__ = '1.2'
67 __version__ = '1.2'
68
68
69 # Modified to use re instead of regex and regsub modules.
69 # Modified to use re instead of regex and regsub modules.
70 # 2001/5/7, Jonathan Hogg <jonathan@onegoodidea.com>
70 # 2001/5/7, Jonathan Hogg <jonathan@onegoodidea.com>
71
71
72 import re
72 import re
73 import string
73 import string
74 import sys
74 import sys
75 import types
75 import types
76
76
77 class Error(Exception):
77 class Error(Exception):
78 """Base class for exceptions in the DPyGetOpt module."""
78 """Base class for exceptions in the DPyGetOpt module."""
79
79
80 class ArgumentError(Error):
80 class ArgumentError(Error):
81 """Exception indicating an error in the arguments passed to
81 """Exception indicating an error in the arguments passed to
82 DPyGetOpt.processArguments."""
82 DPyGetOpt.processArguments."""
83
83
84 class SpecificationError(Error):
84 class SpecificationError(Error):
85 """Exception indicating an error with an option specification."""
85 """Exception indicating an error with an option specification."""
86
86
87 class TerminationError(Error):
87 class TerminationError(Error):
88 """Exception indicating an error with an option processing terminator."""
88 """Exception indicating an error with an option processing terminator."""
89
89
90 specificationExpr = re.compile('(?P<required>.)(?P<type>.)(?P<multi>@?)')
90 specificationExpr = re.compile('(?P<required>.)(?P<type>.)(?P<multi>@?)')
91
91
92 ArgRequired = 'Requires an Argument'
92 ArgRequired = 'Requires an Argument'
93 ArgOptional = 'Argument Optional'
93 ArgOptional = 'Argument Optional'
94
94
95 # The types modules is not used for these identifiers because there
95 # The types modules is not used for these identifiers because there
96 # is no identifier for 'boolean' or 'generic'
96 # is no identifier for 'boolean' or 'generic'
97 StringArgType = 'String Argument Type'
97 StringArgType = 'String Argument Type'
98 IntegerArgType = 'Integer Argument Type'
98 IntegerArgType = 'Integer Argument Type'
99 RealArgType = 'Real Argument Type'
99 RealArgType = 'Real Argument Type'
100 BooleanArgType = 'Boolean Argument Type'
100 BooleanArgType = 'Boolean Argument Type'
101 GenericArgType = 'Generic Argument Type'
101 GenericArgType = 'Generic Argument Type'
102
102
103 # dictionary of conversion functions-- boolean and generic options
103 # dictionary of conversion functions-- boolean and generic options
104 # do not accept arguments and do not need conversion functions;
104 # do not accept arguments and do not need conversion functions;
105 # the identity function is used purely for convenience.
105 # the identity function is used purely for convenience.
106 ConversionFunctions = {
106 ConversionFunctions = {
107 StringArgType : lambda x: x,
107 StringArgType : lambda x: x,
108 IntegerArgType : string.atoi,
108 IntegerArgType : string.atoi,
109 RealArgType : string.atof,
109 RealArgType : string.atof,
110 BooleanArgType : lambda x: x,
110 BooleanArgType : lambda x: x,
111 GenericArgType : lambda x: x,
111 GenericArgType : lambda x: x,
112 }
112 }
113
113
114 class DPyGetOpt:
114 class DPyGetOpt:
115
115
116 def __init__(self, spec = None, terminators = ['--']):
116 def __init__(self, spec = None, terminators = ['--']):
117 """
117 """
118 Declare and intialize instance variables
118 Declare and intialize instance variables
119
119
120 Yes, declaration is not necessary... but one of the things
120 Yes, declaration is not necessary... but one of the things
121 I sorely miss from C/Obj-C is the concept of having an
121 I sorely miss from C/Obj-C is the concept of having an
122 interface definition that clearly declares all instance
122 interface definition that clearly declares all instance
123 variables and methods without providing any implementation
123 variables and methods without providing any implementation
124 details. it is a useful reference!
124 details. it is a useful reference!
125
125
126 all instance variables are initialized to 0/Null/None of
126 all instance variables are initialized to 0/Null/None of
127 the appropriate type-- not even the default value...
127 the appropriate type-- not even the default value...
128 """
128 """
129
129
130 # sys.stderr.write(string.join(spec) + "\n")
130 # sys.stderr.write(string.join(spec) + "\n")
131
131
132 self.allowAbbreviations = 1 # boolean, 1 if abbreviations will
132 self.allowAbbreviations = 1 # boolean, 1 if abbreviations will
133 # be expanded
133 # be expanded
134 self.freeValues = [] # list, contains free values
134 self.freeValues = [] # list, contains free values
135 self.ignoreCase = 0 # boolean, YES if ignoring case
135 self.ignoreCase = 0 # boolean, YES if ignoring case
136 self.needsParse = 0 # boolean, YES if need to reparse parameter spec
136 self.needsParse = 0 # boolean, YES if need to reparse parameter spec
137 self.optionNames = {} # dict, all option names-- value is index of tuple
137 self.optionNames = {} # dict, all option names-- value is index of tuple
138 self.optionStartExpr = None # regexp defining the start of an option (ie; '-', '--')
138 self.optionStartExpr = None # regexp defining the start of an option (ie; '-', '--')
139 self.optionTuples = [] # list o' tuples containing defn of options AND aliases
139 self.optionTuples = [] # list o' tuples containing defn of options AND aliases
140 self.optionValues = {} # dict, option names (after alias expansion) -> option value(s)
140 self.optionValues = {} # dict, option names (after alias expansion) -> option value(s)
141 self.orderMixed = 0 # boolean, YES if options can be mixed with args
141 self.orderMixed = 0 # boolean, YES if options can be mixed with args
142 self.posixCompliance = 0 # boolean, YES indicates posix like behaviour
142 self.posixCompliance = 0 # boolean, YES indicates posix like behaviour
143 self.spec = [] # list, raw specs (in case it must be reparsed)
143 self.spec = [] # list, raw specs (in case it must be reparsed)
144 self.terminators = terminators # list, strings that terminate argument processing
144 self.terminators = terminators # list, strings that terminate argument processing
145 self.termValues = [] # list, values after terminator
145 self.termValues = [] # list, values after terminator
146 self.terminator = None # full name of terminator that ended
146 self.terminator = None # full name of terminator that ended
147 # option processing
147 # option processing
148
148
149 # set up defaults
149 # set up defaults
150 self.setPosixCompliance()
150 self.setPosixCompliance()
151 self.setIgnoreCase()
151 self.setIgnoreCase()
152 self.setAllowAbbreviations()
152 self.setAllowAbbreviations()
153
153
154 # parse spec-- if present
154 # parse spec-- if present
155 if spec:
155 if spec:
156 self.parseConfiguration(spec)
156 self.parseConfiguration(spec)
157
157
158 def setPosixCompliance(self, aFlag = 0):
158 def setPosixCompliance(self, aFlag = 0):
159 """
159 """
160 Enables and disables posix compliance.
160 Enables and disables posix compliance.
161
161
162 When enabled, '+' can be used as an option prefix and free
162 When enabled, '+' can be used as an option prefix and free
163 values can be mixed with options.
163 values can be mixed with options.
164 """
164 """
165 self.posixCompliance = aFlag
165 self.posixCompliance = aFlag
166 self.needsParse = 1
166 self.needsParse = 1
167
167
168 if self.posixCompliance:
168 if self.posixCompliance:
169 self.optionStartExpr = re.compile('(--|-)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
169 self.optionStartExpr = re.compile('(--|-)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
170 self.orderMixed = 0
170 self.orderMixed = 0
171 else:
171 else:
172 self.optionStartExpr = re.compile('(--|-|\+)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
172 self.optionStartExpr = re.compile('(--|-|\+)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
173 self.orderMixed = 1
173 self.orderMixed = 1
174
174
175 def isPosixCompliant(self):
175 def isPosixCompliant(self):
176 """
176 """
177 Returns the value of the posix compliance flag.
177 Returns the value of the posix compliance flag.
178 """
178 """
179 return self.posixCompliance
179 return self.posixCompliance
180
180
181 def setIgnoreCase(self, aFlag = 1):
181 def setIgnoreCase(self, aFlag = 1):
182 """
182 """
183 Enables and disables ignoring case during option processing.
183 Enables and disables ignoring case during option processing.
184 """
184 """
185 self.needsParse = 1
185 self.needsParse = 1
186 self.ignoreCase = aFlag
186 self.ignoreCase = aFlag
187
187
188 def ignoreCase(self):
188 def ignoreCase(self):
189 """
189 """
190 Returns 1 if the option processor will ignore case when
190 Returns 1 if the option processor will ignore case when
191 processing options.
191 processing options.
192 """
192 """
193 return self.ignoreCase
193 return self.ignoreCase
194
194
195 def setAllowAbbreviations(self, aFlag = 1):
195 def setAllowAbbreviations(self, aFlag = 1):
196 """
196 """
197 Enables and disables the expansion of abbreviations during
197 Enables and disables the expansion of abbreviations during
198 option processing.
198 option processing.
199 """
199 """
200 self.allowAbbreviations = aFlag
200 self.allowAbbreviations = aFlag
201
201
202 def willAllowAbbreviations(self):
202 def willAllowAbbreviations(self):
203 """
203 """
204 Returns 1 if abbreviated options will be automatically
204 Returns 1 if abbreviated options will be automatically
205 expanded to the non-abbreviated form (instead of causing an
205 expanded to the non-abbreviated form (instead of causing an
206 unrecognized option error).
206 unrecognized option error).
207 """
207 """
208 return self.allowAbbreviations
208 return self.allowAbbreviations
209
209
210 def addTerminator(self, newTerm):
210 def addTerminator(self, newTerm):
211 """
211 """
212 Adds newTerm as terminator of option processing.
212 Adds newTerm as terminator of option processing.
213
213
214 Whenever the option processor encounters one of the terminators
214 Whenever the option processor encounters one of the terminators
215 during option processing, the processing of options terminates
215 during option processing, the processing of options terminates
216 immediately, all remaining options are stored in the termValues
216 immediately, all remaining options are stored in the termValues
217 instance variable and the full name of the terminator is stored
217 instance variable and the full name of the terminator is stored
218 in the terminator instance variable.
218 in the terminator instance variable.
219 """
219 """
220 self.terminators = self.terminators + [newTerm]
220 self.terminators = self.terminators + [newTerm]
221
221
222 def _addOption(self, oTuple):
222 def _addOption(self, oTuple):
223 """
223 """
224 Adds the option described by oTuple (name, (type, mode,
224 Adds the option described by oTuple (name, (type, mode,
225 default), alias) to optionTuples. Adds index keyed under name
225 default), alias) to optionTuples. Adds index keyed under name
226 to optionNames. Raises SpecificationError if name already in
226 to optionNames. Raises SpecificationError if name already in
227 optionNames
227 optionNames
228 """
228 """
229 (name, (type, mode, default, multi), realName) = oTuple
229 (name, (type, mode, default, multi), realName) = oTuple
230
230
231 # verify name and add to option names dictionary
231 # verify name and add to option names dictionary
232 if self.optionNames.has_key(name):
232 if self.optionNames.has_key(name):
233 if realName:
233 if realName:
234 raise SpecificationError('Alias \'' + name + '\' for \'' +
234 raise SpecificationError('Alias \'' + name + '\' for \'' +
235 realName +
235 realName +
236 '\' already used for another option or alias.')
236 '\' already used for another option or alias.')
237 else:
237 else:
238 raise SpecificationError('Option named \'' + name +
238 raise SpecificationError('Option named \'' + name +
239 '\' specified more than once. Specification: '
239 '\' specified more than once. Specification: '
240 + option)
240 + option)
241
241
242 # validated. add to optionNames
242 # validated. add to optionNames
243 self.optionNames[name] = self.tupleIndex
243 self.optionNames[name] = self.tupleIndex
244 self.tupleIndex = self.tupleIndex + 1
244 self.tupleIndex = self.tupleIndex + 1
245
245
246 # add to optionTuples
246 # add to optionTuples
247 self.optionTuples = self.optionTuples + [oTuple]
247 self.optionTuples = self.optionTuples + [oTuple]
248
248
249 # if type is boolean, add negation
249 # if type is boolean, add negation
250 if type == BooleanArgType:
250 if type == BooleanArgType:
251 alias = 'no' + name
251 alias = 'no' + name
252 specTuple = (type, mode, 0, multi)
252 specTuple = (type, mode, 0, multi)
253 oTuple = (alias, specTuple, name)
253 oTuple = (alias, specTuple, name)
254
254
255 # verify name and add to option names dictionary
255 # verify name and add to option names dictionary
256 if self.optionNames.has_key(alias):
256 if self.optionNames.has_key(alias):
257 if realName:
257 if realName:
258 raise SpecificationError('Negated alias \'' + name +
258 raise SpecificationError('Negated alias \'' + name +
259 '\' for \'' + realName +
259 '\' for \'' + realName +
260 '\' already used for another option or alias.')
260 '\' already used for another option or alias.')
261 else:
261 else:
262 raise SpecificationError('Negated option named \'' + name +
262 raise SpecificationError('Negated option named \'' + name +
263 '\' specified more than once. Specification: '
263 '\' specified more than once. Specification: '
264 + option)
264 + option)
265
265
266 # validated. add to optionNames
266 # validated. add to optionNames
267 self.optionNames[alias] = self.tupleIndex
267 self.optionNames[alias] = self.tupleIndex
268 self.tupleIndex = self.tupleIndex + 1
268 self.tupleIndex = self.tupleIndex + 1
269
269
270 # add to optionTuples
270 # add to optionTuples
271 self.optionTuples = self.optionTuples + [oTuple]
271 self.optionTuples = self.optionTuples + [oTuple]
272
272
273 def addOptionConfigurationTuple(self, oTuple):
273 def addOptionConfigurationTuple(self, oTuple):
274 (name, argSpec, realName) = oTuple
274 (name, argSpec, realName) = oTuple
275 if self.ignoreCase:
275 if self.ignoreCase:
276 name = string.lower(name)
276 name = string.lower(name)
277 if realName:
277 if realName:
278 realName = string.lower(realName)
278 realName = string.lower(realName)
279 else:
279 else:
280 realName = name
280 realName = name
281
281
282 oTuple = (name, argSpec, realName)
282 oTuple = (name, argSpec, realName)
283
283
284 # add option
284 # add option
285 self._addOption(oTuple)
285 self._addOption(oTuple)
286
286
287 def addOptionConfigurationTuples(self, oTuple):
287 def addOptionConfigurationTuples(self, oTuple):
288 if type(oTuple) is ListType:
288 if type(oTuple) is ListType:
289 for t in oTuple:
289 for t in oTuple:
290 self.addOptionConfigurationTuple(t)
290 self.addOptionConfigurationTuple(t)
291 else:
291 else:
292 self.addOptionConfigurationTuple(oTuple)
292 self.addOptionConfigurationTuple(oTuple)
293
293
294 def parseConfiguration(self, spec):
294 def parseConfiguration(self, spec):
295 # destroy previous stored information + store raw spec
295 # destroy previous stored information + store raw spec
296 self.spec = spec
296 self.spec = spec
297 self.optionTuples = []
297 self.optionTuples = []
298 self.optionNames = {}
298 self.optionNames = {}
299 self.tupleIndex = 0
299 self.tupleIndex = 0
300
300
301 tupleIndex = 0
301 tupleIndex = 0
302
302
303 # create some regex's for parsing each spec
303 # create some regex's for parsing each spec
304 splitExpr = \
304 splitExpr = \
305 re.compile('(?P<names>\w+[-A-Za-z0-9|]*)?(?P<spec>!|[=:][infs]@?)?')
305 re.compile('(?P<names>\w+[-A-Za-z0-9|]*)?(?P<spec>!|[=:][infs]@?)?')
306 for option in spec:
306 for option in spec:
307 # push to lower case (does not negatively affect
307 # push to lower case (does not negatively affect
308 # specification)
308 # specification)
309 if self.ignoreCase:
309 if self.ignoreCase:
310 option = string.lower(option)
310 option = string.lower(option)
311
311
312 # break into names, specification
312 # break into names, specification
313 match = splitExpr.match(option)
313 match = splitExpr.match(option)
314 if match is None:
314 if match is None:
315 raise SpecificationError('Invalid specification {' + option +
315 raise SpecificationError('Invalid specification {' + option +
316 '}')
316 '}')
317
317
318 names = match.group('names')
318 names = match.group('names')
319 specification = match.group('spec')
319 specification = match.group('spec')
320
320
321 # break name into name, aliases
321 # break name into name, aliases
322 nlist = string.split(names, '|')
322 nlist = string.split(names, '|')
323
323
324 # get name
324 # get name
325 name = nlist[0]
325 name = nlist[0]
326 aliases = nlist[1:]
326 aliases = nlist[1:]
327
327
328 # specificationExpr = regex.symcomp('\(<required>.\)\(<type>.\)\(<multi>@?\)')
328 # specificationExpr = regex.symcomp('\(<required>.\)\(<type>.\)\(<multi>@?\)')
329 if not specification:
329 if not specification:
330 #spec tuple is ('type', 'arg mode', 'default value', 'multiple')
330 #spec tuple is ('type', 'arg mode', 'default value', 'multiple')
331 argType = GenericArgType
331 argType = GenericArgType
332 argMode = None
332 argMode = None
333 argDefault = 1
333 argDefault = 1
334 argMultiple = 0
334 argMultiple = 0
335 elif specification == '!':
335 elif specification == '!':
336 argType = BooleanArgType
336 argType = BooleanArgType
337 argMode = None
337 argMode = None
338 argDefault = 1
338 argDefault = 1
339 argMultiple = 0
339 argMultiple = 0
340 else:
340 else:
341 # parse
341 # parse
342 match = specificationExpr.match(specification)
342 match = specificationExpr.match(specification)
343 if match is None:
343 if match is None:
344 # failed to parse, die
344 # failed to parse, die
345 raise SpecificationError('Invalid configuration for option \''
345 raise SpecificationError('Invalid configuration for option \''
346 + option + '\'')
346 + option + '\'')
347
347
348 # determine mode
348 # determine mode
349 required = match.group('required')
349 required = match.group('required')
350 if required == '=':
350 if required == '=':
351 argMode = ArgRequired
351 argMode = ArgRequired
352 elif required == ':':
352 elif required == ':':
353 argMode = ArgOptional
353 argMode = ArgOptional
354 else:
354 else:
355 raise SpecificationError('Unknown requirement configuration \''
355 raise SpecificationError('Unknown requirement configuration \''
356 + required + '\'')
356 + required + '\'')
357
357
358 # determine type
358 # determine type
359 type = match.group('type')
359 type = match.group('type')
360 if type == 's':
360 if type == 's':
361 argType = StringArgType
361 argType = StringArgType
362 argDefault = ''
362 argDefault = ''
363 elif type == 'i':
363 elif type == 'i':
364 argType = IntegerArgType
364 argType = IntegerArgType
365 argDefault = 1
365 argDefault = 1
366 elif type == 'f' or type == 'n':
366 elif type == 'f' or type == 'n':
367 argType = RealArgType
367 argType = RealArgType
368 argDefault = 1
368 argDefault = 1
369 else:
369 else:
370 raise SpecificationError('Unknown type specifier \'' +
370 raise SpecificationError('Unknown type specifier \'' +
371 type + '\'')
371 type + '\'')
372
372
373 # determine quantity
373 # determine quantity
374 if match.group('multi') == '@':
374 if match.group('multi') == '@':
375 argMultiple = 1
375 argMultiple = 1
376 else:
376 else:
377 argMultiple = 0
377 argMultiple = 0
378 ## end else (of not specification)
378 ## end else (of not specification)
379
379
380 # construct specification tuple
380 # construct specification tuple
381 specTuple = (argType, argMode, argDefault, argMultiple)
381 specTuple = (argType, argMode, argDefault, argMultiple)
382
382
383 # add the option-- option tuple is (name, specTuple, real name)
383 # add the option-- option tuple is (name, specTuple, real name)
384 oTuple = (name, specTuple, name)
384 oTuple = (name, specTuple, name)
385 self._addOption(oTuple)
385 self._addOption(oTuple)
386
386
387 for alias in aliases:
387 for alias in aliases:
388 # drop to all lower (if configured to do so)
388 # drop to all lower (if configured to do so)
389 if self.ignoreCase:
389 if self.ignoreCase:
390 alias = string.lower(alias)
390 alias = string.lower(alias)
391 # create configuration tuple
391 # create configuration tuple
392 oTuple = (alias, specTuple, name)
392 oTuple = (alias, specTuple, name)
393 # add
393 # add
394 self._addOption(oTuple)
394 self._addOption(oTuple)
395
395
396 # successfully parsed....
396 # successfully parsed....
397 self.needsParse = 0
397 self.needsParse = 0
398
398
399 def _getArgTuple(self, argName):
399 def _getArgTuple(self, argName):
400 """
400 """
401 Returns a list containing all the specification tuples that
401 Returns a list containing all the specification tuples that
402 match argName. If none match, None is returned. If one
402 match argName. If none match, None is returned. If one
403 matches, a list with one tuple is returned. If more than one
403 matches, a list with one tuple is returned. If more than one
404 match, a list containing all the tuples that matched is
404 match, a list containing all the tuples that matched is
405 returned.
405 returned.
406
406
407 In other words, this function does not pass judgement upon the
407 In other words, this function does not pass judgement upon the
408 validity of multiple matches.
408 validity of multiple matches.
409 """
409 """
410 # is it in the optionNames dict?
410 # is it in the optionNames dict?
411
411
412 try:
412 try:
413 # sys.stderr.write(argName + string.join(self.optionNames.keys()) + "\n")
413 # sys.stderr.write(argName + string.join(self.optionNames.keys()) + "\n")
414
414
415 # yes, get index
415 # yes, get index
416 tupleIndex = self.optionNames[argName]
416 tupleIndex = self.optionNames[argName]
417 # and return tuple as element of list
417 # and return tuple as element of list
418 return [self.optionTuples[tupleIndex]]
418 return [self.optionTuples[tupleIndex]]
419 except KeyError:
419 except KeyError:
420 # are abbreviations allowed?
420 # are abbreviations allowed?
421 if not self.allowAbbreviations:
421 if not self.allowAbbreviations:
422 # No! terefore, this cannot be valid argument-- nothing found
422 # No! terefore, this cannot be valid argument-- nothing found
423 return None
423 return None
424
424
425 # argName might be an abbreviation (and, abbreviations must
425 # argName might be an abbreviation (and, abbreviations must
426 # be allowed... or this would not have been reached!)
426 # be allowed... or this would not have been reached!)
427
427
428 # create regex for argName
428 # create regex for argName
429 argExpr = re.compile('^' + argName)
429 argExpr = re.compile('^' + argName)
430
430
431 tuples = filter(lambda x, argExpr=argExpr: argExpr.search(x[0]) is not None,
431 tuples = filter(lambda x, argExpr=argExpr: argExpr.search(x[0]) is not None,
432 self.optionTuples)
432 self.optionTuples)
433
433
434 if not len(tuples):
434 if not len(tuples):
435 return None
435 return None
436 else:
436 else:
437 return tuples
437 return tuples
438
438
439 def _isTerminator(self, optionName):
439 def _isTerminator(self, optionName):
440 """
440 """
441 Returns the full name of the terminator if optionName is a valid
441 Returns the full name of the terminator if optionName is a valid
442 terminator. If it is, sets self.terminator to the full name of
442 terminator. If it is, sets self.terminator to the full name of
443 the terminator.
443 the terminator.
444
444
445 If more than one terminator matched, raises a TerminationError with a
445 If more than one terminator matched, raises a TerminationError with a
446 string describing the ambiguity.
446 string describing the ambiguity.
447 """
447 """
448
448
449 # sys.stderr.write(optionName + "\n")
449 # sys.stderr.write(optionName + "\n")
450 # sys.stderr.write(repr(self.terminators))
450 # sys.stderr.write(repr(self.terminators))
451
451
452 if optionName in self.terminators:
452 if optionName in self.terminators:
453 self.terminator = optionName
453 self.terminator = optionName
454 elif not self.allowAbbreviations:
454 elif not self.allowAbbreviations:
455 return None
455 return None
456
456
457 # regex thing in bogus
457 # regex thing in bogus
458 # termExpr = regex.compile('^' + optionName)
458 # termExpr = regex.compile('^' + optionName)
459
459
460 terms = filter(lambda x, on=optionName: string.find(x,on) == 0, self.terminators)
460 terms = filter(lambda x, on=optionName: string.find(x,on) == 0, self.terminators)
461
461
462 if not len(terms):
462 if not len(terms):
463 return None
463 return None
464 elif len(terms) > 1:
464 elif len(terms) > 1:
465 raise TerminationError('Ambiguous terminator \'' + optionName +
465 raise TerminationError('Ambiguous terminator \'' + optionName +
466 '\' matches ' + repr(terms))
466 '\' matches ' + repr(terms))
467
467
468 self.terminator = terms[0]
468 self.terminator = terms[0]
469 return self.terminator
469 return self.terminator
470
470
471 def processArguments(self, args = None):
471 def processArguments(self, args = None):
472 """
472 """
473 Processes args, a list of arguments (including options).
473 Processes args, a list of arguments (including options).
474
474
475 If args is the same as sys.argv, automatically trims the first
475 If args is the same as sys.argv, automatically trims the first
476 argument (the executable name/path).
476 argument (the executable name/path).
477
477
478 If an exception is not raised, the argument list was parsed
478 If an exception is not raised, the argument list was parsed
479 correctly.
479 correctly.
480
480
481 Upon successful completion, the freeValues instance variable
481 Upon successful completion, the freeValues instance variable
482 will contain all the arguments that were not associated with an
482 will contain all the arguments that were not associated with an
483 option in the order they were encountered. optionValues is a
483 option in the order they were encountered. optionValues is a
484 dictionary containing the value of each option-- the method
484 dictionary containing the value of each option-- the method
485 valueForOption() can be used to query this dictionary.
485 valueForOption() can be used to query this dictionary.
486 terminator will contain the argument encountered that terminated
486 terminator will contain the argument encountered that terminated
487 option processing (or None, if a terminator was never
487 option processing (or None, if a terminator was never
488 encountered) and termValues will contain all of the options that
488 encountered) and termValues will contain all of the options that
489 appeared after the Terminator (or an empty list).
489 appeared after the Terminator (or an empty list).
490 """
490 """
491
491
492 if hasattr(sys, "argv") and args == sys.argv:
492 if hasattr(sys, "argv") and args == sys.argv:
493 args = sys.argv[1:]
493 args = sys.argv[1:]
494
494
495 max = len(args) # maximum index + 1
495 max = len(args) # maximum index + 1
496 self.freeValues = [] # array to hold return values
496 self.freeValues = [] # array to hold return values
497 self.optionValues= {}
497 self.optionValues= {}
498 index = 0 # initial index
498 index = 0 # initial index
499 self.terminator = None
499 self.terminator = None
500 self.termValues = []
500 self.termValues = []
501
501
502 while index < max:
502 while index < max:
503 # obtain argument
503 # obtain argument
504 arg = args[index]
504 arg = args[index]
505 # increment index -- REMEMBER; it is NOW incremented
505 # increment index -- REMEMBER; it is NOW incremented
506 index = index + 1
506 index = index + 1
507
507
508 # terminate immediately if option terminator encountered
508 # terminate immediately if option terminator encountered
509 if self._isTerminator(arg):
509 if self._isTerminator(arg):
510 self.freeValues = self.freeValues + args[index:]
510 self.freeValues = self.freeValues + args[index:]
511 self.termValues = args[index:]
511 self.termValues = args[index:]
512 return
512 return
513
513
514 # is this possibly an option?
514 # is this possibly an option?
515 match = self.optionStartExpr.match(arg)
515 match = self.optionStartExpr.match(arg)
516 if match is None:
516 if match is None:
517 # not an option-- add to freeValues
517 # not an option-- add to freeValues
518 self.freeValues = self.freeValues + [arg]
518 self.freeValues = self.freeValues + [arg]
519 if not self.orderMixed:
519 if not self.orderMixed:
520 # mixing not allowed; add rest of args as freeValues
520 # mixing not allowed; add rest of args as freeValues
521 self.freeValues = self.freeValues + args[index:]
521 self.freeValues = self.freeValues + args[index:]
522 # return to caller
522 # return to caller
523 return
523 return
524 else:
524 else:
525 continue
525 continue
526
526
527 # grab name
527 # grab name
528 optName = match.group('option')
528 optName = match.group('option')
529
529
530 # obtain next argument-- index has already been incremented
530 # obtain next argument-- index has already been incremented
531 nextArg = match.group('arg')
531 nextArg = match.group('arg')
532 if nextArg:
532 if nextArg:
533 nextArg = nextArg[1:]
533 nextArg = nextArg[1:]
534 index = index - 1 # put it back
534 index = index - 1 # put it back
535 else:
535 else:
536 try:
536 try:
537 nextArg = args[index]
537 nextArg = args[index]
538 except:
538 except:
539 nextArg = None
539 nextArg = None
540
540
541 # transpose to lower case, if necessary
541 # transpose to lower case, if necessary
542 if self.ignoreCase:
542 if self.ignoreCase:
543 optName = string.lower(optName)
543 optName = string.lower(optName)
544
544
545 # obtain defining tuple
545 # obtain defining tuple
546 tuples = self._getArgTuple(optName)
546 tuples = self._getArgTuple(optName)
547
547
548 if tuples == None:
548 if tuples == None:
549 raise ArgumentError('Illegal option \'' + arg + '\'')
549 raise ArgumentError('Illegal option \'' + arg + '\'')
550 elif len(tuples) > 1:
550 elif len(tuples) > 1:
551 raise ArgumentError('Ambiguous option \'' + arg +
551 raise ArgumentError('Ambiguous option \'' + arg +
552 '\'; matches ' +
552 '\'; matches ' +
553 repr(map(lambda x: x[0], tuples)))
553 repr(map(lambda x: x[0], tuples)))
554 else:
554 else:
555 config = tuples[0]
555 config = tuples[0]
556
556
557 # config is now set to the configuration tuple for the
557 # config is now set to the configuration tuple for the
558 # argument
558 # argument
559 (fullName, spec, realName) = config
559 (fullName, spec, realName) = config
560 (optType, optMode, optDefault, optMultiple) = spec
560 (optType, optMode, optDefault, optMultiple) = spec
561
561
562 # if opt mode required, but nextArg is none, raise an error
562 # if opt mode required, but nextArg is none, raise an error
563 if (optMode == ArgRequired):
563 if (optMode == ArgRequired):
564 if (not nextArg) or self._isTerminator(nextArg):
564 if (not nextArg) or self._isTerminator(nextArg):
565 # print nextArg
565 # print nextArg
566 raise ArgumentError('Option \'' + arg +
566 raise ArgumentError('Option \'' + arg +
567 '\' requires an argument of type ' +
567 '\' requires an argument of type ' +
568 optType)
568 optType)
569
569
570 if (not optMode == None) and nextArg and (not self._isTerminator(nextArg)):
570 if (not optMode == None) and nextArg and (not self._isTerminator(nextArg)):
571 # nextArg defined, option configured to possibly consume arg
571 # nextArg defined, option configured to possibly consume arg
572 try:
572 try:
573 # grab conversion function-- the try is more for internal diagnostics
573 # grab conversion function-- the try is more for internal diagnostics
574 func = ConversionFunctions[optType]
574 func = ConversionFunctions[optType]
575 try:
575 try:
576 optionValue = func(nextArg)
576 optionValue = func(nextArg)
577 index = index + 1
577 index = index + 1
578 except:
578 except:
579 # only raise conversion error if REQUIRED to consume argument
579 # only raise conversion error if REQUIRED to consume argument
580 if optMode == ArgRequired:
580 if optMode == ArgRequired:
581 raise ArgumentError('Invalid argument to option \''
581 raise ArgumentError('Invalid argument to option \''
582 + arg + '\'; should be \'' +
582 + arg + '\'; should be \'' +
583 optType + '\'')
583 optType + '\'')
584 else:
584 else:
585 optionValue = optDefault
585 optionValue = optDefault
586 except ArgumentError:
586 except ArgumentError:
587 raise
587 raise
588 except:
588 except:
589 raise ArgumentError('(' + arg +
589 raise ArgumentError('(' + arg +
590 ') Conversion function for \'' +
590 ') Conversion function for \'' +
591 optType + '\' not found.')
591 optType + '\' not found.')
592 else:
592 else:
593 optionValue = optDefault
593 optionValue = optDefault
594
594
595 # add value to options dictionary
595 # add value to options dictionary
596 if optMultiple:
596 if optMultiple:
597 # can be multiple values
597 # can be multiple values
598 try:
598 try:
599 # try to append element
599 # try to append element
600 self.optionValues[realName] = self.optionValues[realName] + [optionValue]
600 self.optionValues[realName] = self.optionValues[realName] + [optionValue]
601 except:
601 except:
602 # failed-- must not exist; add it
602 # failed-- must not exist; add it
603 self.optionValues[realName] = [optionValue]
603 self.optionValues[realName] = [optionValue]
604 else:
604 else:
605 # only one value per
605 # only one value per
606 if self.isPosixCompliant and self.optionValues.has_key(realName):
606 if self.isPosixCompliant and self.optionValues.has_key(realName):
607 raise ArgumentError('Argument \'' + arg +
607 raise ArgumentError('Argument \'' + arg +
608 '\' occurs multiple times.')
608 '\' occurs multiple times.')
609
609
610 self.optionValues[realName] = optionValue
610 self.optionValues[realName] = optionValue
611
611
612 def valueForOption(self, optionName, defaultValue = None):
612 def valueForOption(self, optionName, defaultValue = None):
613 """
613 """
614 Return the value associated with optionName. If optionName was
614 Return the value associated with optionName. If optionName was
615 not encountered during parsing of the arguments, returns the
615 not encountered during parsing of the arguments, returns the
616 defaultValue (which defaults to None).
616 defaultValue (which defaults to None).
617 """
617 """
618 try:
618 try:
619 optionValue = self.optionValues[optionName]
619 optionValue = self.optionValues[optionName]
620 except:
620 except:
621 optionValue = defaultValue
621 optionValue = defaultValue
622
622
623 return optionValue
623 return optionValue
624
624
625 ##
625 ##
626 ## test/example section
626 ## test/example section
627 ##
627 ##
628 test_error = 'Test Run Amok!'
628 test_error = 'Test Run Amok!'
629 def _test():
629 def _test():
630 """
630 """
631 A relatively complete test suite.
631 A relatively complete test suite.
632 """
632 """
633 try:
633 try:
634 DPyGetOpt(['foo', 'bar=s', 'foo'])
634 DPyGetOpt(['foo', 'bar=s', 'foo'])
635 except Error, exc:
635 except Error, exc:
636 print 'EXCEPTION (should be \'foo\' already used..): %s' % exc
636 print 'EXCEPTION (should be \'foo\' already used..): %s' % exc
637
637
638 try:
638 try:
639 DPyGetOpt(['foo|bar|apple=s@', 'baz|apple!'])
639 DPyGetOpt(['foo|bar|apple=s@', 'baz|apple!'])
640 except Error, exc:
640 except Error, exc:
641 print 'EXCEPTION (should be duplicate alias/name error): %s' % exc
641 print 'EXCEPTION (should be duplicate alias/name error): %s' % exc
642
642
643 x = DPyGetOpt(['apple|atlas=i@', 'application|executable=f@'])
643 x = DPyGetOpt(['apple|atlas=i@', 'application|executable=f@'])
644 try:
644 try:
645 x.processArguments(['-app', '29.3'])
645 x.processArguments(['-app', '29.3'])
646 except Error, exc:
646 except Error, exc:
647 print 'EXCEPTION (should be ambiguous argument): %s' % exc
647 print 'EXCEPTION (should be ambiguous argument): %s' % exc
648
648
649 x = DPyGetOpt(['foo'], ['antigravity', 'antithesis'])
649 x = DPyGetOpt(['foo'], ['antigravity', 'antithesis'])
650 try:
650 try:
651 x.processArguments(['-foo', 'anti'])
651 x.processArguments(['-foo', 'anti'])
652 except Error, exc:
652 except Error, exc:
653 print 'EXCEPTION (should be ambiguous terminator): %s' % exc
653 print 'EXCEPTION (should be ambiguous terminator): %s' % exc
654
654
655 profile = ['plain-option',
655 profile = ['plain-option',
656 'boolean-option!',
656 'boolean-option!',
657 'list-of-integers=i@',
657 'list-of-integers=i@',
658 'list-real-option|list-real-alias|list-real-pseudonym=f@',
658 'list-real-option|list-real-alias|list-real-pseudonym=f@',
659 'optional-string-option:s',
659 'optional-string-option:s',
660 'abbreviated-string-list=s@']
660 'abbreviated-string-list=s@']
661
661
662 terminators = ['terminator']
662 terminators = ['terminator']
663
663
664 args = ['-plain-option',
664 args = ['-plain-option',
665 '+noboolean-option',
665 '+noboolean-option',
666 '--list-of-integers', '1',
666 '--list-of-integers', '1',
667 '+list-of-integers', '2',
667 '+list-of-integers', '2',
668 '-list-of-integers', '3',
668 '-list-of-integers', '3',
669 'freeargone',
669 'freeargone',
670 '-list-real-option', '1.1',
670 '-list-real-option', '1.1',
671 '+list-real-alias', '1.2',
671 '+list-real-alias', '1.2',
672 '--list-real-pseudonym', '1.3',
672 '--list-real-pseudonym', '1.3',
673 'freeargtwo',
673 'freeargtwo',
674 '-abbreviated-string-list', 'String1',
674 '-abbreviated-string-list', 'String1',
675 '--abbreviated-s', 'String2',
675 '--abbreviated-s', 'String2',
676 '-abbrev', 'String3',
676 '-abbrev', 'String3',
677 '-a', 'String4',
677 '-a', 'String4',
678 '-optional-string-option',
678 '-optional-string-option',
679 'term',
679 'term',
680 'next option should look like an invalid arg',
680 'next option should look like an invalid arg',
681 '-a']
681 '-a']
682
682
683
683
684 print 'Using profile: ' + repr(profile)
684 print 'Using profile: ' + repr(profile)
685 print 'With terminator: ' + repr(terminators)
685 print 'With terminator: ' + repr(terminators)
686 print 'Processing arguments: ' + repr(args)
686 print 'Processing arguments: ' + repr(args)
687
687
688 go = DPyGetOpt(profile, terminators)
688 go = DPyGetOpt(profile, terminators)
689 go.processArguments(args)
689 go.processArguments(args)
690
690
691 print 'Options (and values): ' + repr(go.optionValues)
691 print 'Options (and values): ' + repr(go.optionValues)
692 print 'free args: ' + repr(go.freeValues)
692 print 'free args: ' + repr(go.freeValues)
693 print 'term args: ' + repr(go.termValues)
693 print 'term args: ' + repr(go.termValues)
This diff has been collapsed as it changes many lines, (1034 lines changed) Show them Hide them
@@ -1,517 +1,517 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 the command line completion of other programs which include this isn't
6 the command line completion of other programs which include this isn't
7 damaged.
7 damaged.
8
8
9 In the future, this class will be expanded with improvements over the standard
9 In the future, this class will be expanded with improvements over the standard
10 pdb.
10 pdb.
11
11
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 changes. Licensing should therefore be under the standard Python terms. For
13 changes. Licensing should therefore be under the standard Python terms. For
14 details on the PSF (Python Software Foundation) standard license, see:
14 details on the PSF (Python Software Foundation) standard license, see:
15
15
16 http://www.python.org/2.2.3/license.html
16 http://www.python.org/2.2.3/license.html
17
17
18 $Id: Debugger.py 2913 2007-12-31 12:42:14Z vivainio $"""
18 $Id: Debugger.py 2913 2007-12-31 12:42:14Z vivainio $"""
19
19
20 #*****************************************************************************
20 #*****************************************************************************
21 #
21 #
22 # This file is licensed under the PSF license.
22 # This file is licensed under the PSF license.
23 #
23 #
24 # Copyright (C) 2001 Python Software Foundation, www.python.org
24 # Copyright (C) 2001 Python Software Foundation, www.python.org
25 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
25 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
26 #
26 #
27 #
27 #
28 #*****************************************************************************
28 #*****************************************************************************
29
29
30 from IPython import Release
30 from IPython import Release
31 __author__ = '%s <%s>' % Release.authors['Fernando']
31 __author__ = '%s <%s>' % Release.authors['Fernando']
32 __license__ = 'Python'
32 __license__ = 'Python'
33
33
34 import bdb
34 import bdb
35 import cmd
35 import cmd
36 import linecache
36 import linecache
37 import os
37 import os
38 import sys
38 import sys
39
39
40 from IPython import PyColorize, ColorANSI, ipapi
40 from IPython import PyColorize, ColorANSI, ipapi
41 from IPython.genutils import Term
41 from IPython.genutils import Term
42 from IPython.excolors import ExceptionColors
42 from IPython.excolors import ExceptionColors
43
43
44 # See if we can use pydb.
44 # See if we can use pydb.
45 has_pydb = False
45 has_pydb = False
46 prompt = 'ipdb> '
46 prompt = 'ipdb> '
47 #We have to check this directly from sys.argv, config struct not yet available
47 #We have to check this directly from sys.argv, config struct not yet available
48 if '-pydb' in sys.argv:
48 if '-pydb' in sys.argv:
49 try:
49 try:
50 import pydb
50 import pydb
51 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
51 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
52 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
52 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
53 # better protect against it.
53 # better protect against it.
54 has_pydb = True
54 has_pydb = True
55 except ImportError:
55 except ImportError:
56 print "Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available"
56 print "Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available"
57
57
58 if has_pydb:
58 if has_pydb:
59 from pydb import Pdb as OldPdb
59 from pydb import Pdb as OldPdb
60 #print "Using pydb for %run -d and post-mortem" #dbg
60 #print "Using pydb for %run -d and post-mortem" #dbg
61 prompt = 'ipydb> '
61 prompt = 'ipydb> '
62 else:
62 else:
63 from pdb import Pdb as OldPdb
63 from pdb import Pdb as OldPdb
64
64
65 # Allow the set_trace code to operate outside of an ipython instance, even if
65 # Allow the set_trace code to operate outside of an ipython instance, even if
66 # it does so with some limitations. The rest of this support is implemented in
66 # it does so with some limitations. The rest of this support is implemented in
67 # the Tracer constructor.
67 # the Tracer constructor.
68 def BdbQuit_excepthook(et,ev,tb):
68 def BdbQuit_excepthook(et,ev,tb):
69 if et==bdb.BdbQuit:
69 if et==bdb.BdbQuit:
70 print 'Exiting Debugger.'
70 print 'Exiting Debugger.'
71 else:
71 else:
72 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
72 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
73
73
74 def BdbQuit_IPython_excepthook(self,et,ev,tb):
74 def BdbQuit_IPython_excepthook(self,et,ev,tb):
75 print 'Exiting Debugger.'
75 print 'Exiting Debugger.'
76
76
77 class Tracer(object):
77 class Tracer(object):
78 """Class for local debugging, similar to pdb.set_trace.
78 """Class for local debugging, similar to pdb.set_trace.
79
79
80 Instances of this class, when called, behave like pdb.set_trace, but
80 Instances of this class, when called, behave like pdb.set_trace, but
81 providing IPython's enhanced capabilities.
81 providing IPython's enhanced capabilities.
82
82
83 This is implemented as a class which must be initialized in your own code
83 This is implemented as a class which must be initialized in your own code
84 and not as a standalone function because we need to detect at runtime
84 and not as a standalone function because we need to detect at runtime
85 whether IPython is already active or not. That detection is done in the
85 whether IPython is already active or not. That detection is done in the
86 constructor, ensuring that this code plays nicely with a running IPython,
86 constructor, ensuring that this code plays nicely with a running IPython,
87 while functioning acceptably (though with limitations) if outside of it.
87 while functioning acceptably (though with limitations) if outside of it.
88 """
88 """
89
89
90 def __init__(self,colors=None):
90 def __init__(self,colors=None):
91 """Create a local debugger instance.
91 """Create a local debugger instance.
92
92
93 :Parameters:
93 :Parameters:
94
94
95 - `colors` (None): a string containing the name of the color scheme to
95 - `colors` (None): a string containing the name of the color scheme to
96 use, it must be one of IPython's valid color schemes. If not given, the
96 use, it must be one of IPython's valid color schemes. If not given, the
97 function will default to the current IPython scheme when running inside
97 function will default to the current IPython scheme when running inside
98 IPython, and to 'NoColor' otherwise.
98 IPython, and to 'NoColor' otherwise.
99
99
100 Usage example:
100 Usage example:
101
101
102 from IPython.Debugger import Tracer; debug_here = Tracer()
102 from IPython.Debugger import Tracer; debug_here = Tracer()
103
103
104 ... later in your code
104 ... later in your code
105 debug_here() # -> will open up the debugger at that point.
105 debug_here() # -> will open up the debugger at that point.
106
106
107 Once the debugger activates, you can use all of its regular commands to
107 Once the debugger activates, you can use all of its regular commands to
108 step through code, set breakpoints, etc. See the pdb documentation
108 step through code, set breakpoints, etc. See the pdb documentation
109 from the Python standard library for usage details.
109 from the Python standard library for usage details.
110 """
110 """
111
111
112 global __IPYTHON__
112 global __IPYTHON__
113 try:
113 try:
114 __IPYTHON__
114 __IPYTHON__
115 except NameError:
115 except NameError:
116 # Outside of ipython, we set our own exception hook manually
116 # Outside of ipython, we set our own exception hook manually
117 __IPYTHON__ = ipapi.get(True,False)
117 __IPYTHON__ = ipapi.get(True,False)
118 BdbQuit_excepthook.excepthook_ori = sys.excepthook
118 BdbQuit_excepthook.excepthook_ori = sys.excepthook
119 sys.excepthook = BdbQuit_excepthook
119 sys.excepthook = BdbQuit_excepthook
120 def_colors = 'NoColor'
120 def_colors = 'NoColor'
121 try:
121 try:
122 # Limited tab completion support
122 # Limited tab completion support
123 import rlcompleter,readline
123 import rlcompleter,readline
124 readline.parse_and_bind('tab: complete')
124 readline.parse_and_bind('tab: complete')
125 except ImportError:
125 except ImportError:
126 pass
126 pass
127 else:
127 else:
128 # In ipython, we use its custom exception handler mechanism
128 # In ipython, we use its custom exception handler mechanism
129 ip = ipapi.get()
129 ip = ipapi.get()
130 def_colors = ip.options.colors
130 def_colors = ip.options.colors
131 ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook)
131 ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook)
132
132
133 if colors is None:
133 if colors is None:
134 colors = def_colors
134 colors = def_colors
135 self.debugger = Pdb(colors)
135 self.debugger = Pdb(colors)
136
136
137 def __call__(self):
137 def __call__(self):
138 """Starts an interactive debugger at the point where called.
138 """Starts an interactive debugger at the point where called.
139
139
140 This is similar to the pdb.set_trace() function from the std lib, but
140 This is similar to the pdb.set_trace() function from the std lib, but
141 using IPython's enhanced debugger."""
141 using IPython's enhanced debugger."""
142
142
143 self.debugger.set_trace(sys._getframe().f_back)
143 self.debugger.set_trace(sys._getframe().f_back)
144
144
145 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
145 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
146 """Make new_fn have old_fn's doc string. This is particularly useful
146 """Make new_fn have old_fn's doc string. This is particularly useful
147 for the do_... commands that hook into the help system.
147 for the do_... commands that hook into the help system.
148 Adapted from from a comp.lang.python posting
148 Adapted from from a comp.lang.python posting
149 by Duncan Booth."""
149 by Duncan Booth."""
150 def wrapper(*args, **kw):
150 def wrapper(*args, **kw):
151 return new_fn(*args, **kw)
151 return new_fn(*args, **kw)
152 if old_fn.__doc__:
152 if old_fn.__doc__:
153 wrapper.__doc__ = old_fn.__doc__ + additional_text
153 wrapper.__doc__ = old_fn.__doc__ + additional_text
154 return wrapper
154 return wrapper
155
155
156 def _file_lines(fname):
156 def _file_lines(fname):
157 """Return the contents of a named file as a list of lines.
157 """Return the contents of a named file as a list of lines.
158
158
159 This function never raises an IOError exception: if the file can't be
159 This function never raises an IOError exception: if the file can't be
160 read, it simply returns an empty list."""
160 read, it simply returns an empty list."""
161
161
162 try:
162 try:
163 outfile = open(fname)
163 outfile = open(fname)
164 except IOError:
164 except IOError:
165 return []
165 return []
166 else:
166 else:
167 out = outfile.readlines()
167 out = outfile.readlines()
168 outfile.close()
168 outfile.close()
169 return out
169 return out
170
170
171 class Pdb(OldPdb):
171 class Pdb(OldPdb):
172 """Modified Pdb class, does not load readline."""
172 """Modified Pdb class, does not load readline."""
173
173
174 if sys.version[:3] >= '2.5' or has_pydb:
174 if sys.version[:3] >= '2.5' or has_pydb:
175 def __init__(self,color_scheme='NoColor',completekey=None,
175 def __init__(self,color_scheme='NoColor',completekey=None,
176 stdin=None, stdout=None):
176 stdin=None, stdout=None):
177
177
178 # Parent constructor:
178 # Parent constructor:
179 if has_pydb and completekey is None:
179 if has_pydb and completekey is None:
180 OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)
180 OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)
181 else:
181 else:
182 OldPdb.__init__(self,completekey,stdin,stdout)
182 OldPdb.__init__(self,completekey,stdin,stdout)
183
183
184 self.prompt = prompt # The default prompt is '(Pdb)'
184 self.prompt = prompt # The default prompt is '(Pdb)'
185
185
186 # IPython changes...
186 # IPython changes...
187 self.is_pydb = has_pydb
187 self.is_pydb = has_pydb
188
188
189 if self.is_pydb:
189 if self.is_pydb:
190
190
191 # iplib.py's ipalias seems to want pdb's checkline
191 # iplib.py's ipalias seems to want pdb's checkline
192 # which located in pydb.fn
192 # which located in pydb.fn
193 import pydb.fns
193 import pydb.fns
194 self.checkline = lambda filename, lineno: \
194 self.checkline = lambda filename, lineno: \
195 pydb.fns.checkline(self, filename, lineno)
195 pydb.fns.checkline(self, filename, lineno)
196
196
197 self.curframe = None
197 self.curframe = None
198 self.do_restart = self.new_do_restart
198 self.do_restart = self.new_do_restart
199
199
200 self.old_all_completions = __IPYTHON__.Completer.all_completions
200 self.old_all_completions = __IPYTHON__.Completer.all_completions
201 __IPYTHON__.Completer.all_completions=self.all_completions
201 __IPYTHON__.Completer.all_completions=self.all_completions
202
202
203 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
203 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
204 OldPdb.do_list)
204 OldPdb.do_list)
205 self.do_l = self.do_list
205 self.do_l = self.do_list
206 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
206 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
207 OldPdb.do_frame)
207 OldPdb.do_frame)
208
208
209 self.aliases = {}
209 self.aliases = {}
210
210
211 # Create color table: we copy the default one from the traceback
211 # Create color table: we copy the default one from the traceback
212 # module and add a few attributes needed for debugging
212 # module and add a few attributes needed for debugging
213 self.color_scheme_table = ExceptionColors.copy()
213 self.color_scheme_table = ExceptionColors.copy()
214
214
215 # shorthands
215 # shorthands
216 C = ColorANSI.TermColors
216 C = ColorANSI.TermColors
217 cst = self.color_scheme_table
217 cst = self.color_scheme_table
218
218
219 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
219 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
220 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
220 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
221
221
222 cst['Linux'].colors.breakpoint_enabled = C.LightRed
222 cst['Linux'].colors.breakpoint_enabled = C.LightRed
223 cst['Linux'].colors.breakpoint_disabled = C.Red
223 cst['Linux'].colors.breakpoint_disabled = C.Red
224
224
225 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
225 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
226 cst['LightBG'].colors.breakpoint_disabled = C.Red
226 cst['LightBG'].colors.breakpoint_disabled = C.Red
227
227
228 self.set_colors(color_scheme)
228 self.set_colors(color_scheme)
229
229
230 # Add a python parser so we can syntax highlight source while
230 # Add a python parser so we can syntax highlight source while
231 # debugging.
231 # debugging.
232 self.parser = PyColorize.Parser()
232 self.parser = PyColorize.Parser()
233
233
234
234
235 else:
235 else:
236 # Ugly hack: for Python 2.3-2.4, we can't call the parent constructor,
236 # Ugly hack: for Python 2.3-2.4, we can't call the parent constructor,
237 # because it binds readline and breaks tab-completion. This means we
237 # because it binds readline and breaks tab-completion. This means we
238 # have to COPY the constructor here.
238 # have to COPY the constructor here.
239 def __init__(self,color_scheme='NoColor'):
239 def __init__(self,color_scheme='NoColor'):
240 bdb.Bdb.__init__(self)
240 bdb.Bdb.__init__(self)
241 cmd.Cmd.__init__(self,completekey=None) # don't load readline
241 cmd.Cmd.__init__(self,completekey=None) # don't load readline
242 self.prompt = 'ipdb> ' # The default prompt is '(Pdb)'
242 self.prompt = 'ipdb> ' # The default prompt is '(Pdb)'
243 self.aliases = {}
243 self.aliases = {}
244
244
245 # These two lines are part of the py2.4 constructor, let's put them
245 # These two lines are part of the py2.4 constructor, let's put them
246 # unconditionally here as they won't cause any problems in 2.3.
246 # unconditionally here as they won't cause any problems in 2.3.
247 self.mainpyfile = ''
247 self.mainpyfile = ''
248 self._wait_for_mainpyfile = 0
248 self._wait_for_mainpyfile = 0
249
249
250 # Read $HOME/.pdbrc and ./.pdbrc
250 # Read $HOME/.pdbrc and ./.pdbrc
251 try:
251 try:
252 self.rcLines = _file_lines(os.path.join(os.environ['HOME'],
252 self.rcLines = _file_lines(os.path.join(os.environ['HOME'],
253 ".pdbrc"))
253 ".pdbrc"))
254 except KeyError:
254 except KeyError:
255 self.rcLines = []
255 self.rcLines = []
256 self.rcLines.extend(_file_lines(".pdbrc"))
256 self.rcLines.extend(_file_lines(".pdbrc"))
257
257
258 # Create color table: we copy the default one from the traceback
258 # Create color table: we copy the default one from the traceback
259 # module and add a few attributes needed for debugging
259 # module and add a few attributes needed for debugging
260 ExceptionColors.set_active_scheme(color_scheme)
260 ExceptionColors.set_active_scheme(color_scheme)
261 self.color_scheme_table = ExceptionColors.copy()
261 self.color_scheme_table = ExceptionColors.copy()
262
262
263 # shorthands
263 # shorthands
264 C = ColorANSI.TermColors
264 C = ColorANSI.TermColors
265 cst = self.color_scheme_table
265 cst = self.color_scheme_table
266
266
267 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
267 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
268 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
268 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
269
269
270 cst['Linux'].colors.breakpoint_enabled = C.LightRed
270 cst['Linux'].colors.breakpoint_enabled = C.LightRed
271 cst['Linux'].colors.breakpoint_disabled = C.Red
271 cst['Linux'].colors.breakpoint_disabled = C.Red
272
272
273 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
273 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
274 cst['LightBG'].colors.breakpoint_disabled = C.Red
274 cst['LightBG'].colors.breakpoint_disabled = C.Red
275
275
276 self.set_colors(color_scheme)
276 self.set_colors(color_scheme)
277
277
278 # Add a python parser so we can syntax highlight source while
278 # Add a python parser so we can syntax highlight source while
279 # debugging.
279 # debugging.
280 self.parser = PyColorize.Parser()
280 self.parser = PyColorize.Parser()
281
281
282 def set_colors(self, scheme):
282 def set_colors(self, scheme):
283 """Shorthand access to the color table scheme selector method."""
283 """Shorthand access to the color table scheme selector method."""
284 self.color_scheme_table.set_active_scheme(scheme)
284 self.color_scheme_table.set_active_scheme(scheme)
285
285
286 def interaction(self, frame, traceback):
286 def interaction(self, frame, traceback):
287 __IPYTHON__.set_completer_frame(frame)
287 __IPYTHON__.set_completer_frame(frame)
288 OldPdb.interaction(self, frame, traceback)
288 OldPdb.interaction(self, frame, traceback)
289
289
290 def new_do_up(self, arg):
290 def new_do_up(self, arg):
291 OldPdb.do_up(self, arg)
291 OldPdb.do_up(self, arg)
292 __IPYTHON__.set_completer_frame(self.curframe)
292 __IPYTHON__.set_completer_frame(self.curframe)
293 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
293 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
294
294
295 def new_do_down(self, arg):
295 def new_do_down(self, arg):
296 OldPdb.do_down(self, arg)
296 OldPdb.do_down(self, arg)
297 __IPYTHON__.set_completer_frame(self.curframe)
297 __IPYTHON__.set_completer_frame(self.curframe)
298
298
299 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
299 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
300
300
301 def new_do_frame(self, arg):
301 def new_do_frame(self, arg):
302 OldPdb.do_frame(self, arg)
302 OldPdb.do_frame(self, arg)
303 __IPYTHON__.set_completer_frame(self.curframe)
303 __IPYTHON__.set_completer_frame(self.curframe)
304
304
305 def new_do_quit(self, arg):
305 def new_do_quit(self, arg):
306
306
307 if hasattr(self, 'old_all_completions'):
307 if hasattr(self, 'old_all_completions'):
308 __IPYTHON__.Completer.all_completions=self.old_all_completions
308 __IPYTHON__.Completer.all_completions=self.old_all_completions
309
309
310
310
311 return OldPdb.do_quit(self, arg)
311 return OldPdb.do_quit(self, arg)
312
312
313 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
313 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
314
314
315 def new_do_restart(self, arg):
315 def new_do_restart(self, arg):
316 """Restart command. In the context of ipython this is exactly the same
316 """Restart command. In the context of ipython this is exactly the same
317 thing as 'quit'."""
317 thing as 'quit'."""
318 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
318 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
319 return self.do_quit(arg)
319 return self.do_quit(arg)
320
320
321 def postloop(self):
321 def postloop(self):
322 __IPYTHON__.set_completer_frame(None)
322 __IPYTHON__.set_completer_frame(None)
323
323
324 def print_stack_trace(self):
324 def print_stack_trace(self):
325 try:
325 try:
326 for frame_lineno in self.stack:
326 for frame_lineno in self.stack:
327 self.print_stack_entry(frame_lineno, context = 5)
327 self.print_stack_entry(frame_lineno, context = 5)
328 except KeyboardInterrupt:
328 except KeyboardInterrupt:
329 pass
329 pass
330
330
331 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
331 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
332 context = 3):
332 context = 3):
333 #frame, lineno = frame_lineno
333 #frame, lineno = frame_lineno
334 print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
334 print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
335
335
336 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
336 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
337 import linecache, repr
337 import linecache, repr
338
338
339 ret = []
339 ret = []
340
340
341 Colors = self.color_scheme_table.active_colors
341 Colors = self.color_scheme_table.active_colors
342 ColorsNormal = Colors.Normal
342 ColorsNormal = Colors.Normal
343 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
343 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
344 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
344 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
345 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
345 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
346 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
346 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
347 ColorsNormal)
347 ColorsNormal)
348
348
349 frame, lineno = frame_lineno
349 frame, lineno = frame_lineno
350
350
351 return_value = ''
351 return_value = ''
352 if '__return__' in frame.f_locals:
352 if '__return__' in frame.f_locals:
353 rv = frame.f_locals['__return__']
353 rv = frame.f_locals['__return__']
354 #return_value += '->'
354 #return_value += '->'
355 return_value += repr.repr(rv) + '\n'
355 return_value += repr.repr(rv) + '\n'
356 ret.append(return_value)
356 ret.append(return_value)
357
357
358 #s = filename + '(' + `lineno` + ')'
358 #s = filename + '(' + `lineno` + ')'
359 filename = self.canonic(frame.f_code.co_filename)
359 filename = self.canonic(frame.f_code.co_filename)
360 link = tpl_link % filename
360 link = tpl_link % filename
361
361
362 if frame.f_code.co_name:
362 if frame.f_code.co_name:
363 func = frame.f_code.co_name
363 func = frame.f_code.co_name
364 else:
364 else:
365 func = "<lambda>"
365 func = "<lambda>"
366
366
367 call = ''
367 call = ''
368 if func != '?':
368 if func != '?':
369 if '__args__' in frame.f_locals:
369 if '__args__' in frame.f_locals:
370 args = repr.repr(frame.f_locals['__args__'])
370 args = repr.repr(frame.f_locals['__args__'])
371 else:
371 else:
372 args = '()'
372 args = '()'
373 call = tpl_call % (func, args)
373 call = tpl_call % (func, args)
374
374
375 # The level info should be generated in the same format pdb uses, to
375 # The level info should be generated in the same format pdb uses, to
376 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
376 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
377 if frame is self.curframe:
377 if frame is self.curframe:
378 ret.append('> ')
378 ret.append('> ')
379 else:
379 else:
380 ret.append(' ')
380 ret.append(' ')
381 ret.append('%s(%s)%s\n' % (link,lineno,call))
381 ret.append('%s(%s)%s\n' % (link,lineno,call))
382
382
383 start = lineno - 1 - context//2
383 start = lineno - 1 - context//2
384 lines = linecache.getlines(filename)
384 lines = linecache.getlines(filename)
385 start = max(start, 0)
385 start = max(start, 0)
386 start = min(start, len(lines) - context)
386 start = min(start, len(lines) - context)
387 lines = lines[start : start + context]
387 lines = lines[start : start + context]
388
388
389 for i,line in enumerate(lines):
389 for i,line in enumerate(lines):
390 show_arrow = (start + 1 + i == lineno)
390 show_arrow = (start + 1 + i == lineno)
391 linetpl = (frame is self.curframe or show_arrow) \
391 linetpl = (frame is self.curframe or show_arrow) \
392 and tpl_line_em \
392 and tpl_line_em \
393 or tpl_line
393 or tpl_line
394 ret.append(self.__format_line(linetpl, filename,
394 ret.append(self.__format_line(linetpl, filename,
395 start + 1 + i, line,
395 start + 1 + i, line,
396 arrow = show_arrow) )
396 arrow = show_arrow) )
397
397
398 return ''.join(ret)
398 return ''.join(ret)
399
399
400 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
400 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
401 bp_mark = ""
401 bp_mark = ""
402 bp_mark_color = ""
402 bp_mark_color = ""
403
403
404 scheme = self.color_scheme_table.active_scheme_name
404 scheme = self.color_scheme_table.active_scheme_name
405 new_line, err = self.parser.format2(line, 'str', scheme)
405 new_line, err = self.parser.format2(line, 'str', scheme)
406 if not err: line = new_line
406 if not err: line = new_line
407
407
408 bp = None
408 bp = None
409 if lineno in self.get_file_breaks(filename):
409 if lineno in self.get_file_breaks(filename):
410 bps = self.get_breaks(filename, lineno)
410 bps = self.get_breaks(filename, lineno)
411 bp = bps[-1]
411 bp = bps[-1]
412
412
413 if bp:
413 if bp:
414 Colors = self.color_scheme_table.active_colors
414 Colors = self.color_scheme_table.active_colors
415 bp_mark = str(bp.number)
415 bp_mark = str(bp.number)
416 bp_mark_color = Colors.breakpoint_enabled
416 bp_mark_color = Colors.breakpoint_enabled
417 if not bp.enabled:
417 if not bp.enabled:
418 bp_mark_color = Colors.breakpoint_disabled
418 bp_mark_color = Colors.breakpoint_disabled
419
419
420 numbers_width = 7
420 numbers_width = 7
421 if arrow:
421 if arrow:
422 # This is the line with the error
422 # This is the line with the error
423 pad = numbers_width - len(str(lineno)) - len(bp_mark)
423 pad = numbers_width - len(str(lineno)) - len(bp_mark)
424 if pad >= 3:
424 if pad >= 3:
425 marker = '-'*(pad-3) + '-> '
425 marker = '-'*(pad-3) + '-> '
426 elif pad == 2:
426 elif pad == 2:
427 marker = '> '
427 marker = '> '
428 elif pad == 1:
428 elif pad == 1:
429 marker = '>'
429 marker = '>'
430 else:
430 else:
431 marker = ''
431 marker = ''
432 num = '%s%s' % (marker, str(lineno))
432 num = '%s%s' % (marker, str(lineno))
433 line = tpl_line % (bp_mark_color + bp_mark, num, line)
433 line = tpl_line % (bp_mark_color + bp_mark, num, line)
434 else:
434 else:
435 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
435 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
436 line = tpl_line % (bp_mark_color + bp_mark, num, line)
436 line = tpl_line % (bp_mark_color + bp_mark, num, line)
437
437
438 return line
438 return line
439
439
440 def list_command_pydb(self, arg):
440 def list_command_pydb(self, arg):
441 """List command to use if we have a newer pydb installed"""
441 """List command to use if we have a newer pydb installed"""
442 filename, first, last = OldPdb.parse_list_cmd(self, arg)
442 filename, first, last = OldPdb.parse_list_cmd(self, arg)
443 if filename is not None:
443 if filename is not None:
444 self.print_list_lines(filename, first, last)
444 self.print_list_lines(filename, first, last)
445
445
446 def print_list_lines(self, filename, first, last):
446 def print_list_lines(self, filename, first, last):
447 """The printing (as opposed to the parsing part of a 'list'
447 """The printing (as opposed to the parsing part of a 'list'
448 command."""
448 command."""
449 try:
449 try:
450 Colors = self.color_scheme_table.active_colors
450 Colors = self.color_scheme_table.active_colors
451 ColorsNormal = Colors.Normal
451 ColorsNormal = Colors.Normal
452 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
452 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
453 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
453 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
454 src = []
454 src = []
455 for lineno in range(first, last+1):
455 for lineno in range(first, last+1):
456 line = linecache.getline(filename, lineno)
456 line = linecache.getline(filename, lineno)
457 if not line:
457 if not line:
458 break
458 break
459
459
460 if lineno == self.curframe.f_lineno:
460 if lineno == self.curframe.f_lineno:
461 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
461 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
462 else:
462 else:
463 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
463 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
464
464
465 src.append(line)
465 src.append(line)
466 self.lineno = lineno
466 self.lineno = lineno
467
467
468 print >>Term.cout, ''.join(src)
468 print >>Term.cout, ''.join(src)
469
469
470 except KeyboardInterrupt:
470 except KeyboardInterrupt:
471 pass
471 pass
472
472
473 def do_list(self, arg):
473 def do_list(self, arg):
474 self.lastcmd = 'list'
474 self.lastcmd = 'list'
475 last = None
475 last = None
476 if arg:
476 if arg:
477 try:
477 try:
478 x = eval(arg, {}, {})
478 x = eval(arg, {}, {})
479 if type(x) == type(()):
479 if type(x) == type(()):
480 first, last = x
480 first, last = x
481 first = int(first)
481 first = int(first)
482 last = int(last)
482 last = int(last)
483 if last < first:
483 if last < first:
484 # Assume it's a count
484 # Assume it's a count
485 last = first + last
485 last = first + last
486 else:
486 else:
487 first = max(1, int(x) - 5)
487 first = max(1, int(x) - 5)
488 except:
488 except:
489 print '*** Error in argument:', `arg`
489 print '*** Error in argument:', `arg`
490 return
490 return
491 elif self.lineno is None:
491 elif self.lineno is None:
492 first = max(1, self.curframe.f_lineno - 5)
492 first = max(1, self.curframe.f_lineno - 5)
493 else:
493 else:
494 first = self.lineno + 1
494 first = self.lineno + 1
495 if last is None:
495 if last is None:
496 last = first + 10
496 last = first + 10
497 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
497 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
498
498
499 do_l = do_list
499 do_l = do_list
500
500
501 def do_pdef(self, arg):
501 def do_pdef(self, arg):
502 """The debugger interface to magic_pdef"""
502 """The debugger interface to magic_pdef"""
503 namespaces = [('Locals', self.curframe.f_locals),
503 namespaces = [('Locals', self.curframe.f_locals),
504 ('Globals', self.curframe.f_globals)]
504 ('Globals', self.curframe.f_globals)]
505 __IPYTHON__.magic_pdef(arg, namespaces=namespaces)
505 __IPYTHON__.magic_pdef(arg, namespaces=namespaces)
506
506
507 def do_pdoc(self, arg):
507 def do_pdoc(self, arg):
508 """The debugger interface to magic_pdoc"""
508 """The debugger interface to magic_pdoc"""
509 namespaces = [('Locals', self.curframe.f_locals),
509 namespaces = [('Locals', self.curframe.f_locals),
510 ('Globals', self.curframe.f_globals)]
510 ('Globals', self.curframe.f_globals)]
511 __IPYTHON__.magic_pdoc(arg, namespaces=namespaces)
511 __IPYTHON__.magic_pdoc(arg, namespaces=namespaces)
512
512
513 def do_pinfo(self, arg):
513 def do_pinfo(self, arg):
514 """The debugger equivalant of ?obj"""
514 """The debugger equivalant of ?obj"""
515 namespaces = [('Locals', self.curframe.f_locals),
515 namespaces = [('Locals', self.curframe.f_locals),
516 ('Globals', self.curframe.f_globals)]
516 ('Globals', self.curframe.f_globals)]
517 __IPYTHON__.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
517 __IPYTHON__.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
This diff has been collapsed as it changes many lines, (518 lines changed) Show them Hide them
@@ -1,259 +1,259 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Modified input prompt for executing files.
2 """Modified input prompt for executing files.
3
3
4 We define a special input line filter to allow typing lines which begin with
4 We define a special input line filter to allow typing lines which begin with
5 '~', '/' or '.'. If one of those strings is encountered, it is automatically
5 '~', '/' or '.'. If one of those strings is encountered, it is automatically
6 executed.
6 executed.
7
7
8 $Id: InterpreterExec.py 2724 2007-09-07 08:05:38Z fperez $"""
8 $Id: InterpreterExec.py 2724 2007-09-07 08:05:38Z fperez $"""
9
9
10 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2004 W.J. van der Laan <gnufnork@hetdigitalegat.nl>
11 # Copyright (C) 2004 W.J. van der Laan <gnufnork@hetdigitalegat.nl>
12 # Copyright (C) 2004-2006 Fernando Perez <fperez@colorado.edu>
12 # Copyright (C) 2004-2006 Fernando Perez <fperez@colorado.edu>
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #*****************************************************************************
16 #*****************************************************************************
17
17
18 from IPython import Release
18 from IPython import Release
19 __author__ = 'W.J. van der Laan <gnufnork@hetdigitalegat.nl>, '\
19 __author__ = 'W.J. van der Laan <gnufnork@hetdigitalegat.nl>, '\
20 '%s <%s>' % Release.authors['Fernando']
20 '%s <%s>' % Release.authors['Fernando']
21 __license__ = Release.license
21 __license__ = Release.license
22
22
23 # TODO: deprecated
23 # TODO: deprecated
24 def prefilter_shell(self,line,continuation):
24 def prefilter_shell(self,line,continuation):
25 """Alternate prefilter, modified for shell-like functionality.
25 """Alternate prefilter, modified for shell-like functionality.
26
26
27 - Execute all lines beginning with '~', '/' or '.'
27 - Execute all lines beginning with '~', '/' or '.'
28 - $var=cmd <=> %sc var=cmd
28 - $var=cmd <=> %sc var=cmd
29 - $$var=cmd <=> %sc -l var=cmd
29 - $$var=cmd <=> %sc -l var=cmd
30 """
30 """
31
31
32 if line:
32 if line:
33 l0 = line[0]
33 l0 = line[0]
34 if l0 in '~/.':
34 if l0 in '~/.':
35 return self._prefilter("!%s"%line,continuation)
35 return self._prefilter("!%s"%line,continuation)
36 elif l0=='$':
36 elif l0=='$':
37 lrest = line[1:]
37 lrest = line[1:]
38 if lrest.startswith('$'):
38 if lrest.startswith('$'):
39 # $$var=cmd <=> %sc -l var=cmd
39 # $$var=cmd <=> %sc -l var=cmd
40 return self._prefilter("%ssc -l %s" % (self.ESC_MAGIC,lrest[1:]),
40 return self._prefilter("%ssc -l %s" % (self.ESC_MAGIC,lrest[1:]),
41 continuation)
41 continuation)
42 else:
42 else:
43 # $var=cmd <=> %sc var=cmd
43 # $var=cmd <=> %sc var=cmd
44 return self._prefilter("%ssc %s" % (self.ESC_MAGIC,lrest),
44 return self._prefilter("%ssc %s" % (self.ESC_MAGIC,lrest),
45 continuation)
45 continuation)
46 else:
46 else:
47 return self._prefilter(line,continuation)
47 return self._prefilter(line,continuation)
48 else:
48 else:
49 return self._prefilter(line,continuation)
49 return self._prefilter(line,continuation)
50
50
51 # Rebind this to be the new IPython prefilter:
51 # Rebind this to be the new IPython prefilter:
52 from IPython.iplib import InteractiveShell
52 from IPython.iplib import InteractiveShell
53 InteractiveShell.prefilter = prefilter_shell
53 InteractiveShell.prefilter = prefilter_shell
54 # Clean up the namespace.
54 # Clean up the namespace.
55 del InteractiveShell,prefilter_shell
55 del InteractiveShell,prefilter_shell
56
56
57 # Provide pysh and further shell-oriented services
57 # Provide pysh and further shell-oriented services
58 import os,sys,shutil
58 import os,sys,shutil
59 from IPython.genutils import system,shell,getoutput,getoutputerror
59 from IPython.genutils import system,shell,getoutput,getoutputerror
60
60
61 # Short aliases for getting shell output as a string and a list
61 # Short aliases for getting shell output as a string and a list
62 sout = getoutput
62 sout = getoutput
63 lout = lambda cmd: getoutput(cmd,split=1)
63 lout = lambda cmd: getoutput(cmd,split=1)
64
64
65 # Empty function, meant as a docstring holder so help(pysh) works.
65 # Empty function, meant as a docstring holder so help(pysh) works.
66 def pysh():
66 def pysh():
67 """Pysh is a set of modules and extensions to IPython which make shell-like
67 """Pysh is a set of modules and extensions to IPython which make shell-like
68 usage with Python syntax more convenient. Keep in mind that pysh is NOT a
68 usage with Python syntax more convenient. Keep in mind that pysh is NOT a
69 full-blown shell, so don't try to make it your /etc/passwd entry!
69 full-blown shell, so don't try to make it your /etc/passwd entry!
70
70
71 In particular, it has no job control, so if you type Ctrl-Z (under Unix),
71 In particular, it has no job control, so if you type Ctrl-Z (under Unix),
72 you'll suspend pysh itself, not the process you just started.
72 you'll suspend pysh itself, not the process you just started.
73
73
74 Since pysh is really nothing but a customized IPython, you should
74 Since pysh is really nothing but a customized IPython, you should
75 familiarize yourself with IPython's features. This brief help mainly
75 familiarize yourself with IPython's features. This brief help mainly
76 documents areas in which pysh differs from the normal IPython.
76 documents areas in which pysh differs from the normal IPython.
77
77
78 ALIASES
78 ALIASES
79 -------
79 -------
80 All of your $PATH has been loaded as IPython aliases, so you should be
80 All of your $PATH has been loaded as IPython aliases, so you should be
81 able to type any normal system command and have it executed. See %alias?
81 able to type any normal system command and have it executed. See %alias?
82 and %unalias? for details on the alias facilities.
82 and %unalias? for details on the alias facilities.
83
83
84 SPECIAL SYNTAX
84 SPECIAL SYNTAX
85 --------------
85 --------------
86 Any lines which begin with '~', '/' and '.' will be executed as shell
86 Any lines which begin with '~', '/' and '.' will be executed as shell
87 commands instead of as Python code. The special escapes below are also
87 commands instead of as Python code. The special escapes below are also
88 recognized. !cmd is valid in single or multi-line input, all others are
88 recognized. !cmd is valid in single or multi-line input, all others are
89 only valid in single-line input:
89 only valid in single-line input:
90
90
91 !cmd - pass 'cmd' directly to the shell
91 !cmd - pass 'cmd' directly to the shell
92 !!cmd - execute 'cmd' and return output as a list (split on '\\n')
92 !!cmd - execute 'cmd' and return output as a list (split on '\\n')
93 $var=cmd - capture output of cmd into var, as a string
93 $var=cmd - capture output of cmd into var, as a string
94 $$var=cmd - capture output of cmd into var, as a list (split on '\\n')
94 $$var=cmd - capture output of cmd into var, as a list (split on '\\n')
95
95
96 The $/$$ syntaxes make Python variables from system output, which you can
96 The $/$$ syntaxes make Python variables from system output, which you can
97 later use for further scripting. The converse is also possible: when
97 later use for further scripting. The converse is also possible: when
98 executing an alias or calling to the system via !/!!, you can expand any
98 executing an alias or calling to the system via !/!!, you can expand any
99 python variable or expression by prepending it with $. Full details of
99 python variable or expression by prepending it with $. Full details of
100 the allowed syntax can be found in Python's PEP 215.
100 the allowed syntax can be found in Python's PEP 215.
101
101
102 A few brief examples will illustrate these:
102 A few brief examples will illustrate these:
103
103
104 fperez[~/test]|3> !ls *s.py
104 fperez[~/test]|3> !ls *s.py
105 scopes.py strings.py
105 scopes.py strings.py
106
106
107 ls is an internal alias, so there's no need to use !:
107 ls is an internal alias, so there's no need to use !:
108 fperez[~/test]|4> ls *s.py
108 fperez[~/test]|4> ls *s.py
109 scopes.py* strings.py
109 scopes.py* strings.py
110
110
111 !!ls will return the output into a Python variable:
111 !!ls will return the output into a Python variable:
112 fperez[~/test]|5> !!ls *s.py
112 fperez[~/test]|5> !!ls *s.py
113 <5> ['scopes.py', 'strings.py']
113 <5> ['scopes.py', 'strings.py']
114 fperez[~/test]|6> print _5
114 fperez[~/test]|6> print _5
115 ['scopes.py', 'strings.py']
115 ['scopes.py', 'strings.py']
116
116
117 $ and $$ allow direct capture to named variables:
117 $ and $$ allow direct capture to named variables:
118 fperez[~/test]|7> $astr = ls *s.py
118 fperez[~/test]|7> $astr = ls *s.py
119 fperez[~/test]|8> astr
119 fperez[~/test]|8> astr
120 <8> 'scopes.py\\nstrings.py'
120 <8> 'scopes.py\\nstrings.py'
121
121
122 fperez[~/test]|9> $$alist = ls *s.py
122 fperez[~/test]|9> $$alist = ls *s.py
123 fperez[~/test]|10> alist
123 fperez[~/test]|10> alist
124 <10> ['scopes.py', 'strings.py']
124 <10> ['scopes.py', 'strings.py']
125
125
126 alist is now a normal python list you can loop over. Using $ will expand
126 alist is now a normal python list you can loop over. Using $ will expand
127 back the python values when alias calls are made:
127 back the python values when alias calls are made:
128 fperez[~/test]|11> for f in alist:
128 fperez[~/test]|11> for f in alist:
129 |..> print 'file',f,
129 |..> print 'file',f,
130 |..> wc -l $f
130 |..> wc -l $f
131 |..>
131 |..>
132 file scopes.py 13 scopes.py
132 file scopes.py 13 scopes.py
133 file strings.py 4 strings.py
133 file strings.py 4 strings.py
134
134
135 Note that you may need to protect your variables with braces if you want
135 Note that you may need to protect your variables with braces if you want
136 to append strings to their names. To copy all files in alist to .bak
136 to append strings to their names. To copy all files in alist to .bak
137 extensions, you must use:
137 extensions, you must use:
138 fperez[~/test]|12> for f in alist:
138 fperez[~/test]|12> for f in alist:
139 |..> cp $f ${f}.bak
139 |..> cp $f ${f}.bak
140
140
141 If you try using $f.bak, you'll get an AttributeError exception saying
141 If you try using $f.bak, you'll get an AttributeError exception saying
142 that your string object doesn't have a .bak attribute. This is because
142 that your string object doesn't have a .bak attribute. This is because
143 the $ expansion mechanism allows you to expand full Python expressions:
143 the $ expansion mechanism allows you to expand full Python expressions:
144 fperez[~/test]|13> echo "sys.platform is: $sys.platform"
144 fperez[~/test]|13> echo "sys.platform is: $sys.platform"
145 sys.platform is: linux2
145 sys.platform is: linux2
146
146
147 IPython's input history handling is still active, which allows you to
147 IPython's input history handling is still active, which allows you to
148 rerun a single block of multi-line input by simply using exec:
148 rerun a single block of multi-line input by simply using exec:
149 fperez[~/test]|14> $$alist = ls *.eps
149 fperez[~/test]|14> $$alist = ls *.eps
150 fperez[~/test]|15> exec _i11
150 fperez[~/test]|15> exec _i11
151 file image2.eps 921 image2.eps
151 file image2.eps 921 image2.eps
152 file image.eps 921 image.eps
152 file image.eps 921 image.eps
153
153
154 While these are new special-case syntaxes, they are designed to allow very
154 While these are new special-case syntaxes, they are designed to allow very
155 efficient use of the shell with minimal typing. At an interactive shell
155 efficient use of the shell with minimal typing. At an interactive shell
156 prompt, conciseness of expression wins over readability.
156 prompt, conciseness of expression wins over readability.
157
157
158 USEFUL FUNCTIONS AND MODULES
158 USEFUL FUNCTIONS AND MODULES
159 ----------------------------
159 ----------------------------
160 The os, sys and shutil modules from the Python standard library are
160 The os, sys and shutil modules from the Python standard library are
161 automatically loaded. Some additional functions, useful for shell usage,
161 automatically loaded. Some additional functions, useful for shell usage,
162 are listed below. You can request more help about them with '?'.
162 are listed below. You can request more help about them with '?'.
163
163
164 shell - execute a command in the underlying system shell
164 shell - execute a command in the underlying system shell
165 system - like shell(), but return the exit status of the command
165 system - like shell(), but return the exit status of the command
166 sout - capture the output of a command as a string
166 sout - capture the output of a command as a string
167 lout - capture the output of a command as a list (split on '\\n')
167 lout - capture the output of a command as a list (split on '\\n')
168 getoutputerror - capture (output,error) of a shell command
168 getoutputerror - capture (output,error) of a shell command
169
169
170 sout/lout are the functional equivalents of $/$$. They are provided to
170 sout/lout are the functional equivalents of $/$$. They are provided to
171 allow you to capture system output in the middle of true python code,
171 allow you to capture system output in the middle of true python code,
172 function definitions, etc (where $ and $$ are invalid).
172 function definitions, etc (where $ and $$ are invalid).
173
173
174 DIRECTORY MANAGEMENT
174 DIRECTORY MANAGEMENT
175 --------------------
175 --------------------
176 Since each command passed by pysh to the underlying system is executed in
176 Since each command passed by pysh to the underlying system is executed in
177 a subshell which exits immediately, you can NOT use !cd to navigate the
177 a subshell which exits immediately, you can NOT use !cd to navigate the
178 filesystem.
178 filesystem.
179
179
180 Pysh provides its own builtin '%cd' magic command to move in the
180 Pysh provides its own builtin '%cd' magic command to move in the
181 filesystem (the % is not required with automagic on). It also maintains a
181 filesystem (the % is not required with automagic on). It also maintains a
182 list of visited directories (use %dhist to see it) and allows direct
182 list of visited directories (use %dhist to see it) and allows direct
183 switching to any of them. Type 'cd?' for more details.
183 switching to any of them. Type 'cd?' for more details.
184
184
185 %pushd, %popd and %dirs are provided for directory stack handling.
185 %pushd, %popd and %dirs are provided for directory stack handling.
186
186
187 PROMPT CUSTOMIZATION
187 PROMPT CUSTOMIZATION
188 --------------------
188 --------------------
189
189
190 The supplied ipythonrc-pysh profile comes with an example of a very
190 The supplied ipythonrc-pysh profile comes with an example of a very
191 colored and detailed prompt, mainly to serve as an illustration. The
191 colored and detailed prompt, mainly to serve as an illustration. The
192 valid escape sequences, besides color names, are:
192 valid escape sequences, besides color names, are:
193
193
194 \\# - Prompt number.
194 \\# - Prompt number.
195 \\D - Dots, as many as there are digits in \\# (so they align).
195 \\D - Dots, as many as there are digits in \\# (so they align).
196 \\w - Current working directory (cwd).
196 \\w - Current working directory (cwd).
197 \\W - Basename of current working directory.
197 \\W - Basename of current working directory.
198 \\XN - Where N=0..5. N terms of the cwd, with $HOME written as ~.
198 \\XN - Where N=0..5. N terms of the cwd, with $HOME written as ~.
199 \\YN - Where N=0..5. Like XN, but if ~ is term N+1 it's also shown.
199 \\YN - Where N=0..5. Like XN, but if ~ is term N+1 it's also shown.
200 \\u - Username.
200 \\u - Username.
201 \\H - Full hostname.
201 \\H - Full hostname.
202 \\h - Hostname up to first '.'
202 \\h - Hostname up to first '.'
203 \\$ - Root symbol ($ or #).
203 \\$ - Root symbol ($ or #).
204 \\t - Current time, in H:M:S format.
204 \\t - Current time, in H:M:S format.
205 \\v - IPython release version.
205 \\v - IPython release version.
206 \\n - Newline.
206 \\n - Newline.
207 \\r - Carriage return.
207 \\r - Carriage return.
208 \\\\ - An explicitly escaped '\\'.
208 \\\\ - An explicitly escaped '\\'.
209
209
210 You can configure your prompt colors using any ANSI color escape. Each
210 You can configure your prompt colors using any ANSI color escape. Each
211 color escape sets the color for any subsequent text, until another escape
211 color escape sets the color for any subsequent text, until another escape
212 comes in and changes things. The valid color escapes are:
212 comes in and changes things. The valid color escapes are:
213
213
214 \\C_Black
214 \\C_Black
215 \\C_Blue
215 \\C_Blue
216 \\C_Brown
216 \\C_Brown
217 \\C_Cyan
217 \\C_Cyan
218 \\C_DarkGray
218 \\C_DarkGray
219 \\C_Green
219 \\C_Green
220 \\C_LightBlue
220 \\C_LightBlue
221 \\C_LightCyan
221 \\C_LightCyan
222 \\C_LightGray
222 \\C_LightGray
223 \\C_LightGreen
223 \\C_LightGreen
224 \\C_LightPurple
224 \\C_LightPurple
225 \\C_LightRed
225 \\C_LightRed
226 \\C_Purple
226 \\C_Purple
227 \\C_Red
227 \\C_Red
228 \\C_White
228 \\C_White
229 \\C_Yellow
229 \\C_Yellow
230 \\C_Normal - Stop coloring, defaults to your terminal settings.
230 \\C_Normal - Stop coloring, defaults to your terminal settings.
231 """
231 """
232 pass
232 pass
233
233
234 # Configure a few things. Much of this is fairly hackish, since IPython
234 # Configure a few things. Much of this is fairly hackish, since IPython
235 # doesn't really expose a clean API for it. Be careful if you start making
235 # doesn't really expose a clean API for it. Be careful if you start making
236 # many modifications here.
236 # many modifications here.
237
237
238
238
239 # Set the 'cd' command to quiet mode, a more shell-like behavior
239 # Set the 'cd' command to quiet mode, a more shell-like behavior
240 __IPYTHON__.default_option('cd','-q')
240 __IPYTHON__.default_option('cd','-q')
241
241
242 # This is redundant, ipy_user_conf.py will determine this
242 # This is redundant, ipy_user_conf.py will determine this
243 # Load all of $PATH as aliases
243 # Load all of $PATH as aliases
244 __IPYTHON__.magic_rehashx()
244 __IPYTHON__.magic_rehashx()
245
245
246 # Remove %sc,%sx if present as aliases
246 # Remove %sc,%sx if present as aliases
247 __IPYTHON__.magic_unalias('sc')
247 __IPYTHON__.magic_unalias('sc')
248 __IPYTHON__.magic_unalias('sx')
248 __IPYTHON__.magic_unalias('sx')
249
249
250 # We need different criteria for line-splitting, so that aliases such as
250 # We need different criteria for line-splitting, so that aliases such as
251 # 'gnome-terminal' are interpreted as a single alias instead of variable
251 # 'gnome-terminal' are interpreted as a single alias instead of variable
252 # 'gnome' minus variable 'terminal'.
252 # 'gnome' minus variable 'terminal'.
253 import re
253 import re
254 __IPYTHON__.line_split = re.compile(r'^([\s*,;/])'
254 __IPYTHON__.line_split = re.compile(r'^([\s*,;/])'
255 r'([\?\w\.\-\+]+\w*\s*)'
255 r'([\?\w\.\-\+]+\w*\s*)'
256 r'(\(?.*$)')
256 r'(\(?.*$)')
257
257
258 # Namespace cleanup
258 # Namespace cleanup
259 del re
259 del re
@@ -1,122 +1,122 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Modified input prompt for entering text with >>> or ... at the start.
2 """Modified input prompt for entering text with >>> or ... at the start.
3
3
4 We define a special input line filter to allow typing lines which begin with
4 We define a special input line filter to allow typing lines which begin with
5 '>>> ' or '... '. These two strings, if present at the start of the input
5 '>>> ' or '... '. These two strings, if present at the start of the input
6 line, are stripped. This allows for direct pasting of code from examples such
6 line, are stripped. This allows for direct pasting of code from examples such
7 as those available in the standard Python tutorial.
7 as those available in the standard Python tutorial.
8
8
9 Normally pasting such code is one chunk is impossible because of the
9 Normally pasting such code is one chunk is impossible because of the
10 extraneous >>> and ..., requiring one to do a line by line paste with careful
10 extraneous >>> and ..., requiring one to do a line by line paste with careful
11 removal of those characters. This module allows pasting that kind of
11 removal of those characters. This module allows pasting that kind of
12 multi-line examples in one pass.
12 multi-line examples in one pass.
13
13
14 Here is an 'screenshot' of a section of the tutorial pasted into IPython with
14 Here is an 'screenshot' of a section of the tutorial pasted into IPython with
15 this feature enabled:
15 this feature enabled:
16
16
17 In [1]: >>> def fib2(n): # return Fibonacci series up to n
17 In [1]: >>> def fib2(n): # return Fibonacci series up to n
18 ...: ... '''Return a list containing the Fibonacci series up to n.'''
18 ...: ... '''Return a list containing the Fibonacci series up to n.'''
19 ...: ... result = []
19 ...: ... result = []
20 ...: ... a, b = 0, 1
20 ...: ... a, b = 0, 1
21 ...: ... while b < n:
21 ...: ... while b < n:
22 ...: ... result.append(b) # see below
22 ...: ... result.append(b) # see below
23 ...: ... a, b = b, a+b
23 ...: ... a, b = b, a+b
24 ...: ... return result
24 ...: ... return result
25 ...:
25 ...:
26
26
27 In [2]: fib2(10)
27 In [2]: fib2(10)
28 Out[2]: [1, 1, 2, 3, 5, 8]
28 Out[2]: [1, 1, 2, 3, 5, 8]
29
29
30 The >>> and ... are stripped from the input so that the python interpreter
30 The >>> and ... are stripped from the input so that the python interpreter
31 only sees the real part of the code.
31 only sees the real part of the code.
32
32
33 All other input is processed normally.
33 All other input is processed normally.
34
34
35 Notes
35 Notes
36 =====
36 =====
37
37
38 * You can even paste code that has extra initial spaces, such as is common in
38 * You can even paste code that has extra initial spaces, such as is common in
39 doctests:
39 doctests:
40
40
41 In [3]: >>> a = ['Mary', 'had', 'a', 'little', 'lamb']
41 In [3]: >>> a = ['Mary', 'had', 'a', 'little', 'lamb']
42
42
43 In [4]: >>> for i in range(len(a)):
43 In [4]: >>> for i in range(len(a)):
44 ...: ... print i, a[i]
44 ...: ... print i, a[i]
45 ...: ...
45 ...: ...
46 0 Mary
46 0 Mary
47 1 had
47 1 had
48 2 a
48 2 a
49 3 little
49 3 little
50 4 lamb
50 4 lamb
51 """
51 """
52
52
53 #*****************************************************************************
53 #*****************************************************************************
54 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
54 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
55 #
55 #
56 # Distributed under the terms of the BSD License. The full license is in
56 # Distributed under the terms of the BSD License. The full license is in
57 # the file COPYING, distributed as part of this software.
57 # the file COPYING, distributed as part of this software.
58 #*****************************************************************************
58 #*****************************************************************************
59
59
60 from IPython import Release
60 from IPython import Release
61 __author__ = '%s <%s>' % Release.authors['Fernando']
61 __author__ = '%s <%s>' % Release.authors['Fernando']
62 __license__ = Release.license
62 __license__ = Release.license
63
63
64 # This file is an example of how to modify IPython's line-processing behavior
64 # This file is an example of how to modify IPython's line-processing behavior
65 # without touching the internal code. We'll define an alternate pre-processing
65 # without touching the internal code. We'll define an alternate pre-processing
66 # stage which allows a special form of input (which is invalid Python syntax)
66 # stage which allows a special form of input (which is invalid Python syntax)
67 # for certain quantities, rewrites a line of proper Python in those cases, and
67 # for certain quantities, rewrites a line of proper Python in those cases, and
68 # then passes it off to IPython's normal processor for further work.
68 # then passes it off to IPython's normal processor for further work.
69
69
70 # With this kind of customization, IPython can be adapted for many
70 # With this kind of customization, IPython can be adapted for many
71 # special-purpose scenarios providing alternate input syntaxes.
71 # special-purpose scenarios providing alternate input syntaxes.
72
72
73 # This file can be imported like a regular module.
73 # This file can be imported like a regular module.
74
74
75 # IPython has a prefilter() function that analyzes each input line. We redefine
75 # IPython has a prefilter() function that analyzes each input line. We redefine
76 # it here to first pre-process certain forms of input
76 # it here to first pre-process certain forms of input
77
77
78 # The prototype of any alternate prefilter must be like this one (the name
78 # The prototype of any alternate prefilter must be like this one (the name
79 # doesn't matter):
79 # doesn't matter):
80 # - line is a string containing the user input line.
80 # - line is a string containing the user input line.
81 # - continuation is a parameter which tells us if we are processing a first
81 # - continuation is a parameter which tells us if we are processing a first
82 # line of user input or the second or higher of a multi-line statement.
82 # line of user input or the second or higher of a multi-line statement.
83
83
84 import re
84 import re
85
85
86 from IPython.iplib import InteractiveShell
86 from IPython.iplib import InteractiveShell
87
87
88 PROMPT_RE = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
88 PROMPT_RE = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
89
89
90 def prefilter_paste(self,line,continuation):
90 def prefilter_paste(self,line,continuation):
91 """Alternate prefilter for input of pasted code from an interpreter.
91 """Alternate prefilter for input of pasted code from an interpreter.
92 """
92 """
93 if not line:
93 if not line:
94 return ''
94 return ''
95 m = PROMPT_RE.match(line)
95 m = PROMPT_RE.match(line)
96 if m:
96 if m:
97 # In the end, always call the default IPython _prefilter() function.
97 # In the end, always call the default IPython _prefilter() function.
98 # Note that self must be passed explicitly, b/c we're calling the
98 # Note that self must be passed explicitly, b/c we're calling the
99 # unbound class method (since this method will overwrite the instance
99 # unbound class method (since this method will overwrite the instance
100 # prefilter())
100 # prefilter())
101 return self._prefilter(line[len(m.group(0)):],continuation)
101 return self._prefilter(line[len(m.group(0)):],continuation)
102 elif line.strip() == '...':
102 elif line.strip() == '...':
103 return self._prefilter('',continuation)
103 return self._prefilter('',continuation)
104 elif line.isspace():
104 elif line.isspace():
105 # This allows us to recognize multiple input prompts separated by blank
105 # This allows us to recognize multiple input prompts separated by blank
106 # lines and pasted in a single chunk, very common when pasting doctests
106 # lines and pasted in a single chunk, very common when pasting doctests
107 # or long tutorial passages.
107 # or long tutorial passages.
108 return ''
108 return ''
109 else:
109 else:
110 return self._prefilter(line,continuation)
110 return self._prefilter(line,continuation)
111
111
112 def activate_prefilter():
112 def activate_prefilter():
113 """Rebind the input-pasting filter to be the new IPython prefilter"""
113 """Rebind the input-pasting filter to be the new IPython prefilter"""
114 InteractiveShell.prefilter = prefilter_paste
114 InteractiveShell.prefilter = prefilter_paste
115
115
116 def deactivate_prefilter():
116 def deactivate_prefilter():
117 """Reset the filter."""
117 """Reset the filter."""
118 InteractiveShell.prefilter = InteractiveShell._prefilter
118 InteractiveShell.prefilter = InteractiveShell._prefilter
119
119
120 # Just a heads up at the console
120 # Just a heads up at the console
121 activate_prefilter()
121 activate_prefilter()
122 print '*** Pasting of code with ">>>" or "..." has been enabled.'
122 print '*** Pasting of code with ">>>" or "..." has been enabled.'
@@ -1,83 +1,83 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Modified input prompt for entering quantities with units.
2 """Modified input prompt for entering quantities with units.
3
3
4 Modify the behavior of the interactive interpreter to allow direct input of
4 Modify the behavior of the interactive interpreter to allow direct input of
5 quantities with units without having to make a function call.
5 quantities with units without having to make a function call.
6
6
7 Now the following forms are accepted:
7 Now the following forms are accepted:
8
8
9 x = 4 m
9 x = 4 m
10 y = -.45e3 m/s
10 y = -.45e3 m/s
11 g = 9.8 m/s**2
11 g = 9.8 m/s**2
12 a = 2.3 m/s^2 # ^ -> ** automatically
12 a = 2.3 m/s^2 # ^ -> ** automatically
13
13
14 All other input is processed normally.
14 All other input is processed normally.
15 """
15 """
16 #*****************************************************************************
16 #*****************************************************************************
17 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
17 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
18 #
18 #
19 # Distributed under the terms of the BSD License. The full license is in
19 # Distributed under the terms of the BSD License. The full license is in
20 # the file COPYING, distributed as part of this software.
20 # the file COPYING, distributed as part of this software.
21 #*****************************************************************************
21 #*****************************************************************************
22
22
23 from IPython import Release
23 from IPython import Release
24 __author__ = '%s <%s>' % Release.authors['Fernando']
24 __author__ = '%s <%s>' % Release.authors['Fernando']
25 __license__ = Release.license
25 __license__ = Release.license
26
26
27 # This file is an example of how to modify IPython's line-processing behavior
27 # This file is an example of how to modify IPython's line-processing behavior
28 # without touching the internal code. We'll define an alternate pre-processing
28 # without touching the internal code. We'll define an alternate pre-processing
29 # stage which allows a special form of input (which is invalid Python syntax)
29 # stage which allows a special form of input (which is invalid Python syntax)
30 # for certain quantities, rewrites a line of proper Python in those cases, and
30 # for certain quantities, rewrites a line of proper Python in those cases, and
31 # then passes it off to IPython's normal processor for further work.
31 # then passes it off to IPython's normal processor for further work.
32
32
33 # With this kind of customization, IPython can be adapted for many
33 # With this kind of customization, IPython can be adapted for many
34 # special-purpose scenarios providing alternate input syntaxes.
34 # special-purpose scenarios providing alternate input syntaxes.
35
35
36 # This file can be imported like a regular module.
36 # This file can be imported like a regular module.
37
37
38 # IPython has a prefilter() function that analyzes each input line. We redefine
38 # IPython has a prefilter() function that analyzes each input line. We redefine
39 # it here to first pre-process certain forms of input
39 # it here to first pre-process certain forms of input
40
40
41 # The prototype of any alternate prefilter must be like this one (the name
41 # The prototype of any alternate prefilter must be like this one (the name
42 # doesn't matter):
42 # doesn't matter):
43 # - line is a string containing the user input line.
43 # - line is a string containing the user input line.
44 # - continuation is a parameter which tells us if we are processing a first line of
44 # - continuation is a parameter which tells us if we are processing a first line of
45 # user input or the second or higher of a multi-line statement.
45 # user input or the second or higher of a multi-line statement.
46
46
47 def prefilter_PQ(self,line,continuation):
47 def prefilter_PQ(self,line,continuation):
48 """Alternate prefilter for input of PhysicalQuantityInteractive objects.
48 """Alternate prefilter for input of PhysicalQuantityInteractive objects.
49
49
50 This assumes that the function PhysicalQuantityInteractive() has been
50 This assumes that the function PhysicalQuantityInteractive() has been
51 imported."""
51 imported."""
52
52
53 from re import match
53 from re import match
54 from IPython.iplib import InteractiveShell
54 from IPython.iplib import InteractiveShell
55
55
56 # This regexp is what does the real work
56 # This regexp is what does the real work
57 unit_split = match(r'\s*(\w+)\s*=\s*(-?\d*\.?\d*[eE]?-?\d*)\s+([a-zA-Z].*)',
57 unit_split = match(r'\s*(\w+)\s*=\s*(-?\d*\.?\d*[eE]?-?\d*)\s+([a-zA-Z].*)',
58 line)
58 line)
59
59
60 # If special input was ecnountered, process it:
60 # If special input was ecnountered, process it:
61 if unit_split:
61 if unit_split:
62 var,val,units = unit_split.groups()
62 var,val,units = unit_split.groups()
63 if var and val and units:
63 if var and val and units:
64 units = units.replace('^','**')
64 units = units.replace('^','**')
65 # Now a valid line needs to be constructed for IPython to process:
65 # Now a valid line needs to be constructed for IPython to process:
66 line = var +" = PhysicalQuantityInteractive(" + val + ", '" + \
66 line = var +" = PhysicalQuantityInteractive(" + val + ", '" + \
67 units + "')"
67 units + "')"
68 #print 'New line:',line # dbg
68 #print 'New line:',line # dbg
69
69
70 # In the end, always call the default IPython _prefilter() function. Note
70 # In the end, always call the default IPython _prefilter() function. Note
71 # that self must be passed explicitly, b/c we're calling the unbound class
71 # that self must be passed explicitly, b/c we're calling the unbound class
72 # method (since this method will overwrite the instance prefilter())
72 # method (since this method will overwrite the instance prefilter())
73 return InteractiveShell._prefilter(self,line,continuation)
73 return InteractiveShell._prefilter(self,line,continuation)
74
74
75 # Rebind this to be the new IPython prefilter:
75 # Rebind this to be the new IPython prefilter:
76 from IPython.iplib import InteractiveShell
76 from IPython.iplib import InteractiveShell
77 InteractiveShell.prefilter = prefilter_PQ
77 InteractiveShell.prefilter = prefilter_PQ
78
78
79 # Clean up the namespace.
79 # Clean up the namespace.
80 del InteractiveShell,prefilter_PQ
80 del InteractiveShell,prefilter_PQ
81
81
82 # Just a heads up at the console
82 # Just a heads up at the console
83 print '*** Simplified input for physical quantities enabled.'
83 print '*** Simplified input for physical quantities enabled.'
@@ -1,88 +1,88 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Modify the PhysicalQuantities class for more convenient interactive use.
2 """Modify the PhysicalQuantities class for more convenient interactive use.
3
3
4 Also redefine some math functions to operate on PhysQties with no need for
4 Also redefine some math functions to operate on PhysQties with no need for
5 special method syntax. This just means moving them out to the global
5 special method syntax. This just means moving them out to the global
6 namespace.
6 namespace.
7
7
8 This module should always be loaded *after* math or Numeric, so it can
8 This module should always be loaded *after* math or Numeric, so it can
9 overwrite math functions with the versions that handle units."""
9 overwrite math functions with the versions that handle units."""
10
10
11 #*****************************************************************************
11 #*****************************************************************************
12 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
12 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #*****************************************************************************
16 #*****************************************************************************
17
17
18 from IPython import Release
18 from IPython import Release
19 __author__ = '%s <%s>' % Release.authors['Fernando']
19 __author__ = '%s <%s>' % Release.authors['Fernando']
20 __license__ = Release.license
20 __license__ = Release.license
21
21
22 from Scientific.Physics.PhysicalQuantities import PhysicalQuantity
22 from Scientific.Physics.PhysicalQuantities import PhysicalQuantity
23
23
24 # This code can be set up to work with Numeric or with math for providing the
24 # This code can be set up to work with Numeric or with math for providing the
25 # mathematical functions. Uncomment the one you prefer to use below.
25 # mathematical functions. Uncomment the one you prefer to use below.
26
26
27 # If you use math, sin(x) won't work for x an array, only float or PhysQty
27 # If you use math, sin(x) won't work for x an array, only float or PhysQty
28 import math
28 import math
29
29
30 # If you use Numeric, sin(x) works for x a float, PhysQty an array.
30 # If you use Numeric, sin(x) works for x a float, PhysQty an array.
31 #import Numeric as math
31 #import Numeric as math
32
32
33 class PhysicalQuantityFunction:
33 class PhysicalQuantityFunction:
34 """Generic function wrapper for PhysicalQuantity instances.
34 """Generic function wrapper for PhysicalQuantity instances.
35
35
36 Calls functions from either the math library or the instance's methods as
36 Calls functions from either the math library or the instance's methods as
37 required. Allows using sin(theta) or sqrt(v**2) syntax irrespective of
37 required. Allows using sin(theta) or sqrt(v**2) syntax irrespective of
38 whether theta is a pure number or a PhysicalQuantity.
38 whether theta is a pure number or a PhysicalQuantity.
39
39
40 This is *slow*. It's meant for convenient interactive use, not for
40 This is *slow*. It's meant for convenient interactive use, not for
41 speed."""
41 speed."""
42
42
43 def __init__(self,name):
43 def __init__(self,name):
44 self.name = name
44 self.name = name
45
45
46 def __call__(self,x):
46 def __call__(self,x):
47 if isinstance(x,PhysicalQuantity):
47 if isinstance(x,PhysicalQuantity):
48 return PhysicalQuantity.__dict__[self.name](x)
48 return PhysicalQuantity.__dict__[self.name](x)
49 else:
49 else:
50 return math.__dict__[self.name](x)
50 return math.__dict__[self.name](x)
51
51
52 class PhysicalQuantityInteractive(PhysicalQuantity):
52 class PhysicalQuantityInteractive(PhysicalQuantity):
53 """Physical quantity with units - modified for Interactive use.
53 """Physical quantity with units - modified for Interactive use.
54
54
55 Basically, the __str__ and __repr__ methods have been swapped for more
55 Basically, the __str__ and __repr__ methods have been swapped for more
56 convenient interactive use. Powers are shown as ^ instead of ** and only 4
56 convenient interactive use. Powers are shown as ^ instead of ** and only 4
57 significant figures are shown.
57 significant figures are shown.
58
58
59 Also adds the following aliases for commonly used methods:
59 Also adds the following aliases for commonly used methods:
60 b = PhysicalQuantity.inBaseUnits
60 b = PhysicalQuantity.inBaseUnits
61 u = PhysicalQuantity.inUnitsOf
61 u = PhysicalQuantity.inUnitsOf
62
62
63 These are useful when doing a lot of interactive calculations.
63 These are useful when doing a lot of interactive calculations.
64 """
64 """
65
65
66 # shorthands for the most useful unit conversions
66 # shorthands for the most useful unit conversions
67 b = PhysicalQuantity.inBaseUnits # so you can just type x.b to get base units
67 b = PhysicalQuantity.inBaseUnits # so you can just type x.b to get base units
68 u = PhysicalQuantity.inUnitsOf
68 u = PhysicalQuantity.inUnitsOf
69
69
70 # This can be done, but it can get dangerous when coupled with IPython's
70 # This can be done, but it can get dangerous when coupled with IPython's
71 # auto-calling. Everything ends up shown in baseunits and things like x*2
71 # auto-calling. Everything ends up shown in baseunits and things like x*2
72 # get automatically converted to k(*2), which doesn't work.
72 # get automatically converted to k(*2), which doesn't work.
73 # Probably not a good idea in general...
73 # Probably not a good idea in general...
74 #__call__ = b
74 #__call__ = b
75
75
76 def __str__(self):
76 def __str__(self):
77 return PhysicalQuantity.__repr__(self)
77 return PhysicalQuantity.__repr__(self)
78
78
79 def __repr__(self):
79 def __repr__(self):
80 value = '%.4G' % self.value
80 value = '%.4G' % self.value
81 units = self.unit.name().replace('**','^')
81 units = self.unit.name().replace('**','^')
82 return value + ' ' + units
82 return value + ' ' + units
83
83
84 # implement the methods defined in PhysicalQuantity as PhysicalQuantityFunctions
84 # implement the methods defined in PhysicalQuantity as PhysicalQuantityFunctions
85 sin = PhysicalQuantityFunction('sin')
85 sin = PhysicalQuantityFunction('sin')
86 cos = PhysicalQuantityFunction('cos')
86 cos = PhysicalQuantityFunction('cos')
87 tan = PhysicalQuantityFunction('tan')
87 tan = PhysicalQuantityFunction('tan')
88 sqrt = PhysicalQuantityFunction('sqrt')
88 sqrt = PhysicalQuantityFunction('sqrt')
@@ -1,13 +1,13 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """This directory is meant for special-purpose extensions to IPython.
2 """This directory is meant for special-purpose extensions to IPython.
3
3
4 This can include things which alter the syntax processing stage (see
4 This can include things which alter the syntax processing stage (see
5 PhysicalQ_Input for an example of how to do this).
5 PhysicalQ_Input for an example of how to do this).
6
6
7 Any file located here can be called with an 'execfile =' option as
7 Any file located here can be called with an 'execfile =' option as
8
8
9 execfile = Extensions/filename.py
9 execfile = Extensions/filename.py
10
10
11 since the IPython directory itself is already part of the search path for
11 since the IPython directory itself is already part of the search path for
12 files listed as 'execfile ='.
12 files listed as 'execfile ='.
13 """
13 """
@@ -1,86 +1,86 b''
1 <?xml version='1.0' encoding='iso-8859-1'?>
1 <?xml version='1.0' encoding='iso-8859-1'?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html>
3 <html>
4 <head>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
6 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
6 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
7 <title>igrid help</title>
7 <title>igrid help</title>
8 </head>
8 </head>
9 <body>
9 <body>
10 <h1>igrid help</h1>
10 <h1>igrid help</h1>
11
11
12
12
13 <h2>Commands</h2>
13 <h2>Commands</h2>
14
14
15
15
16 <h3>pick (P)</h3>
16 <h3>pick (P)</h3>
17 <p>Pick the whole row (object is available as "_")</p>
17 <p>Pick the whole row (object is available as "_")</p>
18
18
19 <h3>pickattr (Shift-P)</h3>
19 <h3>pickattr (Shift-P)</h3>
20 <p>Pick the attribute under the cursor</p>
20 <p>Pick the attribute under the cursor</p>
21
21
22 <h3>pickallattrs (Shift-C)</h3>
22 <h3>pickallattrs (Shift-C)</h3>
23 <p>Pick' the complete column under the cursor (i.e. the attribute under the
23 <p>Pick' the complete column under the cursor (i.e. the attribute under the
24 cursor) from all currently fetched objects. These attributes will be returned
24 cursor) from all currently fetched objects. These attributes will be returned
25 as a list.</p>
25 as a list.</p>
26
26
27 <h3>enter (E)</h3>
27 <h3>enter (E)</h3>
28 <p>Enter the object under the cursor. (what this mean depends on the object
28 <p>Enter the object under the cursor. (what this mean depends on the object
29 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
29 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
30
30
31 <h3>enterattr (Shift-E)</h3>
31 <h3>enterattr (Shift-E)</h3>
32 <p>Enter the attribute under the cursor.</p>
32 <p>Enter the attribute under the cursor.</p>
33
33
34 <h3>detail (D)</h3>
34 <h3>detail (D)</h3>
35 <p>Show a detail view of the object under the cursor. This shows the name,
35 <p>Show a detail view of the object under the cursor. This shows the name,
36 type, doc string and value of the object attributes (and it might show more
36 type, doc string and value of the object attributes (and it might show more
37 attributes than in the list view, depending on the object).</p>
37 attributes than in the list view, depending on the object).</p>
38
38
39 <h3>detailattr (Shift-D)</h3>
39 <h3>detailattr (Shift-D)</h3>
40 <p>Show a detail view of the attribute under the cursor.</p>
40 <p>Show a detail view of the attribute under the cursor.</p>
41
41
42 <h3>pickrows (M)</h3>
42 <h3>pickrows (M)</h3>
43 <p>Pick multiple selected rows (M)</p>
43 <p>Pick multiple selected rows (M)</p>
44
44
45 <h3>pickrowsattr (CTRL-M)</h3>
45 <h3>pickrowsattr (CTRL-M)</h3>
46 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
46 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
47
47
48 <h3>find (CTRL-F)</h3>
48 <h3>find (CTRL-F)</h3>
49 <p>Find text</p>
49 <p>Find text</p>
50
50
51 <h3>find_next (F3)</h3>
51 <h3>find_next (F3)</h3>
52 <p>Find next occurrence of the searchtext</p>
52 <p>Find next occurrence of the searchtext</p>
53
53
54 <h3>find_previous (Shift-F3)</h3>
54 <h3>find_previous (Shift-F3)</h3>
55 <p>Find previous occurrence of the searchtext </p>
55 <p>Find previous occurrence of the searchtext </p>
56
56
57 <h3>sortattrasc (V)</h3>
57 <h3>sortattrasc (V)</h3>
58 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
58 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
59
59
60 <h3>sortattrdesc (Shift-V)</h3>
60 <h3>sortattrdesc (Shift-V)</h3>
61 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
61 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
62
62
63 <h3>leave (Backspace, DEL, X)</h3>
63 <h3>leave (Backspace, DEL, X)</h3>
64 <p>Close current tab (and all the tabs to the right of the current one).</h3>
64 <p>Close current tab (and all the tabs to the right of the current one).</h3>
65
65
66 <h3>quit (ESC,Q)</h3>
66 <h3>quit (ESC,Q)</h3>
67 <p>Quit igrid and return to the IPython prompt.</p>
67 <p>Quit igrid and return to the IPython prompt.</p>
68
68
69
69
70 <h2>Navigation</h2>
70 <h2>Navigation</h2>
71
71
72
72
73 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
73 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
74
74
75 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
75 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
76
76
77 <h3>Move the cursor one column to the left (&lt;)</h3>
77 <h3>Move the cursor one column to the left (&lt;)</h3>
78
78
79 <h3>Move the cursor one column to the right (&gt;)</h3>
79 <h3>Move the cursor one column to the right (&gt;)</h3>
80
80
81 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
81 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
82
82
83 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
83 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
84
84
85 </body>
85 </body>
86 </html>
86 </html>
This diff has been collapsed as it changes many lines, (1150 lines changed) Show them Hide them
@@ -1,575 +1,575 b''
1 """ ILeo - Leo plugin for IPython
1 """ ILeo - Leo plugin for IPython
2
2
3
3
4 """
4 """
5 import IPython.ipapi
5 import IPython.ipapi
6 import IPython.genutils
6 import IPython.genutils
7 import IPython.generics
7 import IPython.generics
8 from IPython.hooks import CommandChainDispatcher
8 from IPython.hooks import CommandChainDispatcher
9 import re
9 import re
10 import UserDict
10 import UserDict
11 from IPython.ipapi import TryNext
11 from IPython.ipapi import TryNext
12 import IPython.macro
12 import IPython.macro
13
13
14 def init_ipython(ipy):
14 def init_ipython(ipy):
15 """ This will be run by _ip.load('ipy_leo')
15 """ This will be run by _ip.load('ipy_leo')
16
16
17 Leo still needs to run update_commander() after this.
17 Leo still needs to run update_commander() after this.
18
18
19 """
19 """
20 global ip
20 global ip
21 ip = ipy
21 ip = ipy
22 ip.set_hook('complete_command', mb_completer, str_key = '%mb')
22 ip.set_hook('complete_command', mb_completer, str_key = '%mb')
23 ip.expose_magic('mb',mb_f)
23 ip.expose_magic('mb',mb_f)
24 ip.expose_magic('lee',lee_f)
24 ip.expose_magic('lee',lee_f)
25 ip.expose_magic('leoref',leoref_f)
25 ip.expose_magic('leoref',leoref_f)
26 expose_ileo_push(push_cl_node,100)
26 expose_ileo_push(push_cl_node,100)
27 # this should be the LAST one that will be executed, and it will never raise TryNext
27 # this should be the LAST one that will be executed, and it will never raise TryNext
28 expose_ileo_push(push_ipython_script, 1000)
28 expose_ileo_push(push_ipython_script, 1000)
29 expose_ileo_push(push_plain_python, 100)
29 expose_ileo_push(push_plain_python, 100)
30 expose_ileo_push(push_ev_node, 100)
30 expose_ileo_push(push_ev_node, 100)
31 global wb
31 global wb
32 wb = LeoWorkbook()
32 wb = LeoWorkbook()
33 ip.user_ns['wb'] = wb
33 ip.user_ns['wb'] = wb
34
34
35 show_welcome()
35 show_welcome()
36
36
37
37
38 def update_commander(new_leox):
38 def update_commander(new_leox):
39 """ Set the Leo commander to use
39 """ Set the Leo commander to use
40
40
41 This will be run every time Leo does ipython-launch; basically,
41 This will be run every time Leo does ipython-launch; basically,
42 when the user switches the document he is focusing on, he should do
42 when the user switches the document he is focusing on, he should do
43 ipython-launch to tell ILeo what document the commands apply to.
43 ipython-launch to tell ILeo what document the commands apply to.
44
44
45 """
45 """
46
46
47 global c,g
47 global c,g
48 c,g = new_leox.c, new_leox.g
48 c,g = new_leox.c, new_leox.g
49 print "Set Leo Commander:",c.frame.getTitle()
49 print "Set Leo Commander:",c.frame.getTitle()
50
50
51 # will probably be overwritten by user, but handy for experimentation early on
51 # will probably be overwritten by user, but handy for experimentation early on
52 ip.user_ns['c'] = c
52 ip.user_ns['c'] = c
53 ip.user_ns['g'] = g
53 ip.user_ns['g'] = g
54 ip.user_ns['_leo'] = new_leox
54 ip.user_ns['_leo'] = new_leox
55
55
56 new_leox.push = push_position_from_leo
56 new_leox.push = push_position_from_leo
57 run_leo_startup_node()
57 run_leo_startup_node()
58
58
59 from IPython.external.simplegeneric import generic
59 from IPython.external.simplegeneric import generic
60 import pprint
60 import pprint
61
61
62 def es(s):
62 def es(s):
63 g.es(s, tabName = 'IPython')
63 g.es(s, tabName = 'IPython')
64 pass
64 pass
65
65
66 @generic
66 @generic
67 def format_for_leo(obj):
67 def format_for_leo(obj):
68 """ Convert obj to string representiation (for editing in Leo)"""
68 """ Convert obj to string representiation (for editing in Leo)"""
69 return pprint.pformat(obj)
69 return pprint.pformat(obj)
70
70
71 @format_for_leo.when_type(list)
71 @format_for_leo.when_type(list)
72 def format_list(obj):
72 def format_list(obj):
73 return "\n".join(str(s) for s in obj)
73 return "\n".join(str(s) for s in obj)
74
74
75
75
76 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
76 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
77 def valid_attribute(s):
77 def valid_attribute(s):
78 return attribute_re.match(s)
78 return attribute_re.match(s)
79
79
80 _rootnode = None
80 _rootnode = None
81 def rootnode():
81 def rootnode():
82 """ Get ileo root node (@ipy-root)
82 """ Get ileo root node (@ipy-root)
83
83
84 if node has become invalid or has not been set, return None
84 if node has become invalid or has not been set, return None
85
85
86 Note that the root is the *first* @ipy-root item found
86 Note that the root is the *first* @ipy-root item found
87 """
87 """
88 global _rootnode
88 global _rootnode
89 if _rootnode is None:
89 if _rootnode is None:
90 return None
90 return None
91 if c.positionExists(_rootnode.p):
91 if c.positionExists(_rootnode.p):
92 return _rootnode
92 return _rootnode
93 _rootnode = None
93 _rootnode = None
94 return None
94 return None
95
95
96 def all_cells():
96 def all_cells():
97 global _rootnode
97 global _rootnode
98 d = {}
98 d = {}
99 r = rootnode()
99 r = rootnode()
100 if r is not None:
100 if r is not None:
101 nodes = r.p.children_iter()
101 nodes = r.p.children_iter()
102 else:
102 else:
103 nodes = c.allNodes_iter()
103 nodes = c.allNodes_iter()
104
104
105 for p in nodes:
105 for p in nodes:
106 h = p.headString()
106 h = p.headString()
107 if h.strip() == '@ipy-root':
107 if h.strip() == '@ipy-root':
108 # update root node (found it for the first time)
108 # update root node (found it for the first time)
109 _rootnode = LeoNode(p)
109 _rootnode = LeoNode(p)
110 # the next recursive call will use the children of new root
110 # the next recursive call will use the children of new root
111 return all_cells()
111 return all_cells()
112
112
113 if h.startswith('@a '):
113 if h.startswith('@a '):
114 d[h.lstrip('@a ').strip()] = p.parent().copy()
114 d[h.lstrip('@a ').strip()] = p.parent().copy()
115 elif not valid_attribute(h):
115 elif not valid_attribute(h):
116 continue
116 continue
117 d[h] = p.copy()
117 d[h] = p.copy()
118 return d
118 return d
119
119
120 def eval_node(n):
120 def eval_node(n):
121 body = n.b
121 body = n.b
122 if not body.startswith('@cl'):
122 if not body.startswith('@cl'):
123 # plain python repr node, just eval it
123 # plain python repr node, just eval it
124 return ip.ev(n.b)
124 return ip.ev(n.b)
125 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
125 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
126 first, rest = body.split('\n',1)
126 first, rest = body.split('\n',1)
127 tup = first.split(None, 1)
127 tup = first.split(None, 1)
128 # @cl alone SPECIAL USE-> dump var to user_ns
128 # @cl alone SPECIAL USE-> dump var to user_ns
129 if len(tup) == 1:
129 if len(tup) == 1:
130 val = ip.ev(rest)
130 val = ip.ev(rest)
131 ip.user_ns[n.h] = val
131 ip.user_ns[n.h] = val
132 es("%s = %s" % (n.h, repr(val)[:20] ))
132 es("%s = %s" % (n.h, repr(val)[:20] ))
133 return val
133 return val
134
134
135 cl, hd = tup
135 cl, hd = tup
136
136
137 xformer = ip.ev(hd.strip())
137 xformer = ip.ev(hd.strip())
138 es('Transform w/ %s' % repr(xformer))
138 es('Transform w/ %s' % repr(xformer))
139 return xformer(rest, n)
139 return xformer(rest, n)
140
140
141 class LeoNode(object, UserDict.DictMixin):
141 class LeoNode(object, UserDict.DictMixin):
142 """ Node in Leo outline
142 """ Node in Leo outline
143
143
144 Most important attributes (getters/setters available:
144 Most important attributes (getters/setters available:
145 .v - evaluate node, can also be alligned
145 .v - evaluate node, can also be alligned
146 .b, .h - body string, headline string
146 .b, .h - body string, headline string
147 .l - value as string list
147 .l - value as string list
148
148
149 Also supports iteration,
149 Also supports iteration,
150
150
151 setitem / getitem (indexing):
151 setitem / getitem (indexing):
152 wb.foo['key'] = 12
152 wb.foo['key'] = 12
153 assert wb.foo['key'].v == 12
153 assert wb.foo['key'].v == 12
154
154
155 Note the asymmetry on setitem and getitem! Also other
155 Note the asymmetry on setitem and getitem! Also other
156 dict methods are available.
156 dict methods are available.
157
157
158 .ipush() - run push-to-ipython
158 .ipush() - run push-to-ipython
159
159
160 Minibuffer command access (tab completion works):
160 Minibuffer command access (tab completion works):
161
161
162 mb save-to-file
162 mb save-to-file
163
163
164 """
164 """
165 def __init__(self,p):
165 def __init__(self,p):
166 self.p = p.copy()
166 self.p = p.copy()
167
167
168 def __str__(self):
168 def __str__(self):
169 return "<LeoNode %s>" % str(self.p)
169 return "<LeoNode %s>" % str(self.p)
170
170
171 __repr__ = __str__
171 __repr__ = __str__
172
172
173 def __get_h(self): return self.p.headString()
173 def __get_h(self): return self.p.headString()
174 def __set_h(self,val):
174 def __set_h(self,val):
175 print "set head",val
175 print "set head",val
176 c.beginUpdate()
176 c.beginUpdate()
177 try:
177 try:
178 c.setHeadString(self.p,val)
178 c.setHeadString(self.p,val)
179 finally:
179 finally:
180 c.endUpdate()
180 c.endUpdate()
181
181
182 h = property( __get_h, __set_h, doc = "Node headline string")
182 h = property( __get_h, __set_h, doc = "Node headline string")
183
183
184 def __get_b(self): return self.p.bodyString()
184 def __get_b(self): return self.p.bodyString()
185 def __set_b(self,val):
185 def __set_b(self,val):
186 print "set body",val
186 print "set body",val
187 c.beginUpdate()
187 c.beginUpdate()
188 try:
188 try:
189 c.setBodyString(self.p, val)
189 c.setBodyString(self.p, val)
190 finally:
190 finally:
191 c.endUpdate()
191 c.endUpdate()
192
192
193 b = property(__get_b, __set_b, doc = "Nody body string")
193 b = property(__get_b, __set_b, doc = "Nody body string")
194
194
195 def __set_val(self, val):
195 def __set_val(self, val):
196 self.b = format_for_leo(val)
196 self.b = format_for_leo(val)
197
197
198 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
198 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
199
199
200 def __set_l(self,val):
200 def __set_l(self,val):
201 self.b = '\n'.join(val )
201 self.b = '\n'.join(val )
202 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
202 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
203 __set_l, doc = "Node value as string list")
203 __set_l, doc = "Node value as string list")
204
204
205 def __iter__(self):
205 def __iter__(self):
206 """ Iterate through nodes direct children """
206 """ Iterate through nodes direct children """
207
207
208 return (LeoNode(p) for p in self.p.children_iter())
208 return (LeoNode(p) for p in self.p.children_iter())
209
209
210 def __children(self):
210 def __children(self):
211 d = {}
211 d = {}
212 for child in self:
212 for child in self:
213 head = child.h
213 head = child.h
214 tup = head.split(None,1)
214 tup = head.split(None,1)
215 if len(tup) > 1 and tup[0] == '@k':
215 if len(tup) > 1 and tup[0] == '@k':
216 d[tup[1]] = child
216 d[tup[1]] = child
217 continue
217 continue
218
218
219 if not valid_attribute(head):
219 if not valid_attribute(head):
220 d[head] = child
220 d[head] = child
221 continue
221 continue
222 return d
222 return d
223 def keys(self):
223 def keys(self):
224 d = self.__children()
224 d = self.__children()
225 return d.keys()
225 return d.keys()
226 def __getitem__(self, key):
226 def __getitem__(self, key):
227 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
227 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
228
228
229 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
229 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
230 """
230 """
231 key = str(key)
231 key = str(key)
232 d = self.__children()
232 d = self.__children()
233 return d[key]
233 return d[key]
234 def __setitem__(self, key, val):
234 def __setitem__(self, key, val):
235 """ You can do wb.foo['My Stuff'] = 12 to create children
235 """ You can do wb.foo['My Stuff'] = 12 to create children
236
236
237 This will create 'My Stuff' as a child of foo (if it does not exist), and
237 This will create 'My Stuff' as a child of foo (if it does not exist), and
238 do .v = 12 assignment.
238 do .v = 12 assignment.
239
239
240 Exception:
240 Exception:
241
241
242 wb.foo['bar'] = 12
242 wb.foo['bar'] = 12
243
243
244 will create a child with headline '@k bar', because bar is a valid python name
244 will create a child with headline '@k bar', because bar is a valid python name
245 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
245 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
246 """
246 """
247 key = str(key)
247 key = str(key)
248 d = self.__children()
248 d = self.__children()
249 if key in d:
249 if key in d:
250 d[key].v = val
250 d[key].v = val
251 return
251 return
252
252
253 if not valid_attribute(key):
253 if not valid_attribute(key):
254 head = key
254 head = key
255 else:
255 else:
256 head = '@k ' + key
256 head = '@k ' + key
257 p = c.createLastChildNode(self.p, head, '')
257 p = c.createLastChildNode(self.p, head, '')
258 LeoNode(p).v = val
258 LeoNode(p).v = val
259
259
260 def ipush(self):
260 def ipush(self):
261 """ Does push-to-ipython on the node """
261 """ Does push-to-ipython on the node """
262 push_from_leo(self)
262 push_from_leo(self)
263
263
264 def go(self):
264 def go(self):
265 """ Set node as current node (to quickly see it in Outline) """
265 """ Set node as current node (to quickly see it in Outline) """
266 c.beginUpdate()
266 c.beginUpdate()
267 try:
267 try:
268 c.setCurrentPosition(self.p)
268 c.setCurrentPosition(self.p)
269 finally:
269 finally:
270 c.endUpdate()
270 c.endUpdate()
271
271
272 def script(self):
272 def script(self):
273 """ Method to get the 'tangled' contents of the node
273 """ Method to get the 'tangled' contents of the node
274
274
275 (parse @others, << section >> references etc.)
275 (parse @others, << section >> references etc.)
276 """
276 """
277 return g.getScript(c,self.p,useSelectedText=False,useSentinels=False)
277 return g.getScript(c,self.p,useSelectedText=False,useSentinels=False)
278
278
279 def __get_uA(self):
279 def __get_uA(self):
280 p = self.p
280 p = self.p
281 # Create the uA if necessary.
281 # Create the uA if necessary.
282 if not hasattr(p.v.t,'unknownAttributes'):
282 if not hasattr(p.v.t,'unknownAttributes'):
283 p.v.t.unknownAttributes = {}
283 p.v.t.unknownAttributes = {}
284
284
285 d = p.v.t.unknownAttributes.setdefault('ipython', {})
285 d = p.v.t.unknownAttributes.setdefault('ipython', {})
286 return d
286 return d
287
287
288 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
288 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
289
289
290
290
291 class LeoWorkbook:
291 class LeoWorkbook:
292 """ class for 'advanced' node access
292 """ class for 'advanced' node access
293
293
294 Has attributes for all "discoverable" nodes. Node is discoverable if it
294 Has attributes for all "discoverable" nodes. Node is discoverable if it
295 either
295 either
296
296
297 - has a valid python name (Foo, bar_12)
297 - has a valid python name (Foo, bar_12)
298 - is a parent of an anchor node (if it has a child '@a foo', it is visible as foo)
298 - is a parent of an anchor node (if it has a child '@a foo', it is visible as foo)
299
299
300 """
300 """
301 def __getattr__(self, key):
301 def __getattr__(self, key):
302 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
302 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
303 raise AttributeError
303 raise AttributeError
304 cells = all_cells()
304 cells = all_cells()
305 p = cells.get(key, None)
305 p = cells.get(key, None)
306 if p is None:
306 if p is None:
307 return add_var(key)
307 return add_var(key)
308
308
309 return LeoNode(p)
309 return LeoNode(p)
310
310
311 def __str__(self):
311 def __str__(self):
312 return "<LeoWorkbook>"
312 return "<LeoWorkbook>"
313 def __setattr__(self,key, val):
313 def __setattr__(self,key, val):
314 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
314 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
315
315
316 __repr__ = __str__
316 __repr__ = __str__
317
317
318 def __iter__(self):
318 def __iter__(self):
319 """ Iterate all (even non-exposed) nodes """
319 """ Iterate all (even non-exposed) nodes """
320 cells = all_cells()
320 cells = all_cells()
321 return (LeoNode(p) for p in c.allNodes_iter())
321 return (LeoNode(p) for p in c.allNodes_iter())
322
322
323 current = property(lambda self: LeoNode(c.currentPosition()), doc = "Currently selected node")
323 current = property(lambda self: LeoNode(c.currentPosition()), doc = "Currently selected node")
324
324
325 def match_h(self, regex):
325 def match_h(self, regex):
326 cmp = re.compile(regex)
326 cmp = re.compile(regex)
327 for node in self:
327 for node in self:
328 if re.match(cmp, node.h, re.IGNORECASE):
328 if re.match(cmp, node.h, re.IGNORECASE):
329 yield node
329 yield node
330 return
330 return
331
331
332 @IPython.generics.complete_object.when_type(LeoWorkbook)
332 @IPython.generics.complete_object.when_type(LeoWorkbook)
333 def workbook_complete(obj, prev):
333 def workbook_complete(obj, prev):
334 return all_cells().keys() + [s for s in prev if not s.startswith('_')]
334 return all_cells().keys() + [s for s in prev if not s.startswith('_')]
335
335
336
336
337 def add_var(varname):
337 def add_var(varname):
338 c.beginUpdate()
338 c.beginUpdate()
339 r = rootnode()
339 r = rootnode()
340 try:
340 try:
341 if r is None:
341 if r is None:
342 p2 = g.findNodeAnywhere(c,varname)
342 p2 = g.findNodeAnywhere(c,varname)
343 else:
343 else:
344 p2 = g.findNodeInChildren(c, r.p, varname)
344 p2 = g.findNodeInChildren(c, r.p, varname)
345 if p2:
345 if p2:
346 return LeoNode(p2)
346 return LeoNode(p2)
347
347
348 if r is not None:
348 if r is not None:
349 p2 = r.p.insertAsLastChild()
349 p2 = r.p.insertAsLastChild()
350
350
351 else:
351 else:
352 p2 = c.currentPosition().insertAfter()
352 p2 = c.currentPosition().insertAfter()
353
353
354 c.setHeadString(p2,varname)
354 c.setHeadString(p2,varname)
355 return LeoNode(p2)
355 return LeoNode(p2)
356 finally:
356 finally:
357 c.endUpdate()
357 c.endUpdate()
358
358
359 def add_file(self,fname):
359 def add_file(self,fname):
360 p2 = c.currentPosition().insertAfter()
360 p2 = c.currentPosition().insertAfter()
361
361
362 push_from_leo = CommandChainDispatcher()
362 push_from_leo = CommandChainDispatcher()
363
363
364 def expose_ileo_push(f, prio = 0):
364 def expose_ileo_push(f, prio = 0):
365 push_from_leo.add(f, prio)
365 push_from_leo.add(f, prio)
366
366
367 def push_ipython_script(node):
367 def push_ipython_script(node):
368 """ Execute the node body in IPython, as if it was entered in interactive prompt """
368 """ Execute the node body in IPython, as if it was entered in interactive prompt """
369 c.beginUpdate()
369 c.beginUpdate()
370 try:
370 try:
371 ohist = ip.IP.output_hist
371 ohist = ip.IP.output_hist
372 hstart = len(ip.IP.input_hist)
372 hstart = len(ip.IP.input_hist)
373 script = node.script()
373 script = node.script()
374
374
375 script = g.splitLines(script + '\n')
375 script = g.splitLines(script + '\n')
376 ip.user_ns['_p'] = node
376 ip.user_ns['_p'] = node
377 ip.runlines(script)
377 ip.runlines(script)
378 ip.user_ns.pop('_p',None)
378 ip.user_ns.pop('_p',None)
379
379
380 has_output = False
380 has_output = False
381 for idx in range(hstart,len(ip.IP.input_hist)):
381 for idx in range(hstart,len(ip.IP.input_hist)):
382 val = ohist.get(idx,None)
382 val = ohist.get(idx,None)
383 if val is None:
383 if val is None:
384 continue
384 continue
385 has_output = True
385 has_output = True
386 inp = ip.IP.input_hist[idx]
386 inp = ip.IP.input_hist[idx]
387 if inp.strip():
387 if inp.strip():
388 es('In: %s' % (inp[:40], ))
388 es('In: %s' % (inp[:40], ))
389
389
390 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
390 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
391
391
392 if not has_output:
392 if not has_output:
393 es('ipy run: %s (%d LL)' %( node.h,len(script)))
393 es('ipy run: %s (%d LL)' %( node.h,len(script)))
394 finally:
394 finally:
395 c.endUpdate()
395 c.endUpdate()
396
396
397
397
398 def eval_body(body):
398 def eval_body(body):
399 try:
399 try:
400 val = ip.ev(body)
400 val = ip.ev(body)
401 except:
401 except:
402 # just use stringlist if it's not completely legal python expression
402 # just use stringlist if it's not completely legal python expression
403 val = IPython.genutils.SList(body.splitlines())
403 val = IPython.genutils.SList(body.splitlines())
404 return val
404 return val
405
405
406 def push_plain_python(node):
406 def push_plain_python(node):
407 if not node.h.endswith('P'):
407 if not node.h.endswith('P'):
408 raise TryNext
408 raise TryNext
409 script = node.script()
409 script = node.script()
410 lines = script.count('\n')
410 lines = script.count('\n')
411 try:
411 try:
412 exec script in ip.user_ns
412 exec script in ip.user_ns
413 except:
413 except:
414 print " -- Exception in script:\n"+script + "\n --"
414 print " -- Exception in script:\n"+script + "\n --"
415 raise
415 raise
416 es('ipy plain: %s (%d LL)' % (node.h,lines))
416 es('ipy plain: %s (%d LL)' % (node.h,lines))
417
417
418
418
419 def push_cl_node(node):
419 def push_cl_node(node):
420 """ If node starts with @cl, eval it
420 """ If node starts with @cl, eval it
421
421
422 The result is put as last child of @ipy-results node, if it exists
422 The result is put as last child of @ipy-results node, if it exists
423 """
423 """
424 if not node.b.startswith('@cl'):
424 if not node.b.startswith('@cl'):
425 raise TryNext
425 raise TryNext
426
426
427 p2 = g.findNodeAnywhere(c,'@ipy-results')
427 p2 = g.findNodeAnywhere(c,'@ipy-results')
428 val = node.v
428 val = node.v
429 if p2:
429 if p2:
430 es("=> @ipy-results")
430 es("=> @ipy-results")
431 LeoNode(p2).v = val
431 LeoNode(p2).v = val
432 es(val)
432 es(val)
433
433
434 def push_ev_node(node):
434 def push_ev_node(node):
435 """ If headline starts with @ev, eval it and put result in body """
435 """ If headline starts with @ev, eval it and put result in body """
436 if not node.h.startswith('@ev '):
436 if not node.h.startswith('@ev '):
437 raise TryNext
437 raise TryNext
438 expr = node.h.lstrip('@ev ')
438 expr = node.h.lstrip('@ev ')
439 es('ipy eval ' + expr)
439 es('ipy eval ' + expr)
440 res = ip.ev(expr)
440 res = ip.ev(expr)
441 node.v = res
441 node.v = res
442
442
443
443
444 def push_position_from_leo(p):
444 def push_position_from_leo(p):
445 push_from_leo(LeoNode(p))
445 push_from_leo(LeoNode(p))
446
446
447 @generic
447 @generic
448 def edit_object_in_leo(obj, varname):
448 def edit_object_in_leo(obj, varname):
449 """ Make it @cl node so it can be pushed back directly by alt+I """
449 """ Make it @cl node so it can be pushed back directly by alt+I """
450 node = add_var(varname)
450 node = add_var(varname)
451 formatted = format_for_leo(obj)
451 formatted = format_for_leo(obj)
452 if not formatted.startswith('@cl'):
452 if not formatted.startswith('@cl'):
453 formatted = '@cl\n' + formatted
453 formatted = '@cl\n' + formatted
454 node.b = formatted
454 node.b = formatted
455 node.go()
455 node.go()
456
456
457 @edit_object_in_leo.when_type(IPython.macro.Macro)
457 @edit_object_in_leo.when_type(IPython.macro.Macro)
458 def edit_macro(obj,varname):
458 def edit_macro(obj,varname):
459 bod = '_ip.defmacro("""\\\n' + obj.value + '""")'
459 bod = '_ip.defmacro("""\\\n' + obj.value + '""")'
460 node = add_var('Macro_' + varname)
460 node = add_var('Macro_' + varname)
461 node.b = bod
461 node.b = bod
462 node.go()
462 node.go()
463
463
464 def get_history(hstart = 0):
464 def get_history(hstart = 0):
465 res = []
465 res = []
466 ohist = ip.IP.output_hist
466 ohist = ip.IP.output_hist
467
467
468 for idx in range(hstart, len(ip.IP.input_hist)):
468 for idx in range(hstart, len(ip.IP.input_hist)):
469 val = ohist.get(idx,None)
469 val = ohist.get(idx,None)
470 has_output = True
470 has_output = True
471 inp = ip.IP.input_hist_raw[idx]
471 inp = ip.IP.input_hist_raw[idx]
472 if inp.strip():
472 if inp.strip():
473 res.append('In [%d]: %s' % (idx, inp))
473 res.append('In [%d]: %s' % (idx, inp))
474 if val:
474 if val:
475 res.append(pprint.pformat(val))
475 res.append(pprint.pformat(val))
476 res.append('\n')
476 res.append('\n')
477 return ''.join(res)
477 return ''.join(res)
478
478
479
479
480 def lee_f(self,s):
480 def lee_f(self,s):
481 """ Open file(s)/objects in Leo
481 """ Open file(s)/objects in Leo
482
482
483 - %lee hist -> open full session history in leo
483 - %lee hist -> open full session history in leo
484 - Takes an object
484 - Takes an object
485 - Takes an mglob pattern, e.g. '%lee *.cpp' or %leo 'rec:*.cpp'
485 - Takes an mglob pattern, e.g. '%lee *.cpp' or %leo 'rec:*.cpp'
486 """
486 """
487 import os
487 import os
488
488
489 c.beginUpdate()
489 c.beginUpdate()
490 try:
490 try:
491 if s == 'hist':
491 if s == 'hist':
492 wb.ipython_history.b = get_history()
492 wb.ipython_history.b = get_history()
493 wb.ipython_history.go()
493 wb.ipython_history.go()
494 return
494 return
495
495
496
496
497
497
498 # try editing the object directly
498 # try editing the object directly
499 obj = ip.user_ns.get(s, None)
499 obj = ip.user_ns.get(s, None)
500 if obj is not None:
500 if obj is not None:
501 edit_object_in_leo(obj,s)
501 edit_object_in_leo(obj,s)
502 return
502 return
503
503
504 # if it's not object, it's a file name / mglob pattern
504 # if it's not object, it's a file name / mglob pattern
505 from IPython.external import mglob
505 from IPython.external import mglob
506
506
507 files = (os.path.abspath(f) for f in mglob.expand(s))
507 files = (os.path.abspath(f) for f in mglob.expand(s))
508 for fname in files:
508 for fname in files:
509 p = g.findNodeAnywhere(c,'@auto ' + fname)
509 p = g.findNodeAnywhere(c,'@auto ' + fname)
510 if not p:
510 if not p:
511 p = c.currentPosition().insertAfter()
511 p = c.currentPosition().insertAfter()
512
512
513 p.setHeadString('@auto ' + fname)
513 p.setHeadString('@auto ' + fname)
514 if os.path.isfile(fname):
514 if os.path.isfile(fname):
515 c.setBodyString(p,open(fname).read())
515 c.setBodyString(p,open(fname).read())
516 c.selectPosition(p)
516 c.selectPosition(p)
517 print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes"
517 print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes"
518 finally:
518 finally:
519 c.endUpdate()
519 c.endUpdate()
520
520
521
521
522
522
523 def leoref_f(self,s):
523 def leoref_f(self,s):
524 """ Quick reference for ILeo """
524 """ Quick reference for ILeo """
525 import textwrap
525 import textwrap
526 print textwrap.dedent("""\
526 print textwrap.dedent("""\
527 %leoe file/object - open file / object in leo
527 %leoe file/object - open file / object in leo
528 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
528 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
529 wb.foo.v = 12 - assign to body of node foo
529 wb.foo.v = 12 - assign to body of node foo
530 wb.foo.b - read or write the body of node foo
530 wb.foo.b - read or write the body of node foo
531 wb.foo.l - body of node foo as string list
531 wb.foo.l - body of node foo as string list
532
532
533 for el in wb.foo:
533 for el in wb.foo:
534 print el.v
534 print el.v
535
535
536 """
536 """
537 )
537 )
538
538
539
539
540
540
541 def mb_f(self, arg):
541 def mb_f(self, arg):
542 """ Execute leo minibuffer commands
542 """ Execute leo minibuffer commands
543
543
544 Example:
544 Example:
545 mb save-to-file
545 mb save-to-file
546 """
546 """
547 c.executeMinibufferCommand(arg)
547 c.executeMinibufferCommand(arg)
548
548
549 def mb_completer(self,event):
549 def mb_completer(self,event):
550 """ Custom completer for minibuffer """
550 """ Custom completer for minibuffer """
551 cmd_param = event.line.split()
551 cmd_param = event.line.split()
552 if event.line.endswith(' '):
552 if event.line.endswith(' '):
553 cmd_param.append('')
553 cmd_param.append('')
554 if len(cmd_param) > 2:
554 if len(cmd_param) > 2:
555 return ip.IP.Completer.file_matches(event.symbol)
555 return ip.IP.Completer.file_matches(event.symbol)
556 cmds = c.commandsDict.keys()
556 cmds = c.commandsDict.keys()
557 cmds.sort()
557 cmds.sort()
558 return cmds
558 return cmds
559
559
560 def show_welcome():
560 def show_welcome():
561 print "------------------"
561 print "------------------"
562 print "Welcome to Leo-enabled IPython session!"
562 print "Welcome to Leo-enabled IPython session!"
563 print "Try %leoref for quick reference."
563 print "Try %leoref for quick reference."
564 import IPython.platutils
564 import IPython.platutils
565 IPython.platutils.set_term_title('ILeo')
565 IPython.platutils.set_term_title('ILeo')
566 IPython.platutils.freeze_term_title()
566 IPython.platutils.freeze_term_title()
567
567
568 def run_leo_startup_node():
568 def run_leo_startup_node():
569 p = g.findNodeAnywhere(c,'@ipy-startup')
569 p = g.findNodeAnywhere(c,'@ipy-startup')
570 if p:
570 if p:
571 print "Running @ipy-startup nodes"
571 print "Running @ipy-startup nodes"
572 for n in LeoNode(p):
572 for n in LeoNode(p):
573 push_from_leo(n)
573 push_from_leo(n)
574
574
575
575
@@ -1,43 +1,43 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Extension for printing Numeric Arrays in flexible ways.
3 Extension for printing Numeric Arrays in flexible ways.
4 """
4 """
5
5
6 from Numeric import ArrayType
6 from Numeric import ArrayType
7
7
8 def num_display(self,arg):
8 def num_display(self,arg):
9 """Display method for printing which treats Numeric arrays specially.
9 """Display method for printing which treats Numeric arrays specially.
10 """
10 """
11
11
12 # Non-numpy variables are printed using the system default
12 # Non-numpy variables are printed using the system default
13 if type(arg) != ArrayType:
13 if type(arg) != ArrayType:
14 self._display(arg)
14 self._display(arg)
15 return
15 return
16 # Otherwise, we do work.
16 # Otherwise, we do work.
17 format = __IPYTHON__.runtime_rc.numarray_print_format
17 format = __IPYTHON__.runtime_rc.numarray_print_format
18 print 'NumPy array, format:',format
18 print 'NumPy array, format:',format
19 # Here is where all the printing logic needs to be implemented
19 # Here is where all the printing logic needs to be implemented
20 print arg # nothing yet :)
20 print arg # nothing yet :)
21
21
22
22
23 def magic_format(self,parameter_s=''):
23 def magic_format(self,parameter_s=''):
24 """Specifies format of numerical output.
24 """Specifies format of numerical output.
25
25
26 This command is similar to Ocave's format command.
26 This command is similar to Ocave's format command.
27 """
27 """
28
28
29 valid_formats = ['long','short']
29 valid_formats = ['long','short']
30
30
31 if parameter_s in valid_formats:
31 if parameter_s in valid_formats:
32 self.runtime_rc.numarray_print_format = parameter_s
32 self.runtime_rc.numarray_print_format = parameter_s
33 print 'Numeric output format is now:',parameter_s
33 print 'Numeric output format is now:',parameter_s
34 else:
34 else:
35 print 'Invalid format:',parameter_s
35 print 'Invalid format:',parameter_s
36 print 'Valid formats:',valid_formats
36 print 'Valid formats:',valid_formats
37
37
38 # setup default format
38 # setup default format
39 __IPYTHON__.runtime_rc.numarray_print_format = 'long'
39 __IPYTHON__.runtime_rc.numarray_print_format = 'long'
40
40
41 # Bind our new functions to the interpreter
41 # Bind our new functions to the interpreter
42 __IPYTHON__.__class__.magic_format = magic_format
42 __IPYTHON__.__class__.magic_format = magic_format
43 __IPYTHON__.hooks.display = num_display
43 __IPYTHON__.hooks.display = num_display
@@ -1,43 +1,43 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Class which mimics a module.
3 Class which mimics a module.
4
4
5 Needed to allow pickle to correctly resolve namespaces during IPython
5 Needed to allow pickle to correctly resolve namespaces during IPython
6 sessions.
6 sessions.
7
7
8 $Id: FakeModule.py 2754 2007-09-09 10:16:59Z fperez $"""
8 $Id: FakeModule.py 2754 2007-09-09 10:16:59Z fperez $"""
9
9
10 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2002-2004 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2002-2004 Fernando Perez. <fperez@colorado.edu>
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #*****************************************************************************
15 #*****************************************************************************
16
16
17 import types
17 import types
18
18
19 class FakeModule(types.ModuleType):
19 class FakeModule(types.ModuleType):
20 """Simple class with attribute access to fake a module.
20 """Simple class with attribute access to fake a module.
21
21
22 This is not meant to replace a module, but to allow inserting a fake
22 This is not meant to replace a module, but to allow inserting a fake
23 module in sys.modules so that systems which rely on run-time module
23 module in sys.modules so that systems which rely on run-time module
24 importing (like shelve and pickle) work correctly in interactive IPython
24 importing (like shelve and pickle) work correctly in interactive IPython
25 sessions.
25 sessions.
26
26
27 Do NOT use this code for anything other than this IPython private hack."""
27 Do NOT use this code for anything other than this IPython private hack."""
28
28
29 def __init__(self,adict=None):
29 def __init__(self,adict=None):
30
30
31 # tmp to force __dict__ instance creation, else self.__dict__ fails
31 # tmp to force __dict__ instance creation, else self.__dict__ fails
32 self.__iptmp = None
32 self.__iptmp = None
33
33
34 # It seems pydoc (and perhaps others) needs any module instance to
34 # It seems pydoc (and perhaps others) needs any module instance to
35 # implement a __nonzero__ method, so we add it if missing:
35 # implement a __nonzero__ method, so we add it if missing:
36 self.__dict__.setdefault('__nonzero__',lambda : True)
36 self.__dict__.setdefault('__nonzero__',lambda : True)
37 self.__dict__.setdefault('__file__',__file__)
37 self.__dict__.setdefault('__file__',__file__)
38
38
39 # cleanup our temp trick
39 # cleanup our temp trick
40 del self.__iptmp
40 del self.__iptmp
41
41
42 if adict is not None:
42 if adict is not None:
43 self.__dict__.update(adict)
43 self.__dict__.update(adict)
This diff has been collapsed as it changes many lines, (1332 lines changed) Show them Hide them
@@ -1,666 +1,666 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Improved replacement for the Gnuplot.Gnuplot class.
2 """Improved replacement for the Gnuplot.Gnuplot class.
3
3
4 This module imports Gnuplot and replaces some of its functionality with
4 This module imports Gnuplot and replaces some of its functionality with
5 improved versions. They add better handling of arrays for plotting and more
5 improved versions. They add better handling of arrays for plotting and more
6 convenient PostScript generation, plus some fixes for hardcopy().
6 convenient PostScript generation, plus some fixes for hardcopy().
7
7
8 It also adds a convenient plot2 method for plotting dictionaries and
8 It also adds a convenient plot2 method for plotting dictionaries and
9 lists/tuples of arrays.
9 lists/tuples of arrays.
10
10
11 This module is meant to be used as a drop-in replacement to the original
11 This module is meant to be used as a drop-in replacement to the original
12 Gnuplot, so it should be safe to do:
12 Gnuplot, so it should be safe to do:
13
13
14 import IPython.Gnuplot2 as Gnuplot
14 import IPython.Gnuplot2 as Gnuplot
15
15
16 $Id: Gnuplot2.py 1210 2006-03-13 01:19:31Z fperez $"""
16 $Id: Gnuplot2.py 1210 2006-03-13 01:19:31Z fperez $"""
17
17
18 import cStringIO
18 import cStringIO
19 import os
19 import os
20 import string
20 import string
21 import sys
21 import sys
22 import tempfile
22 import tempfile
23 import time
23 import time
24 import types
24 import types
25
25
26 import Gnuplot as Gnuplot_ori
26 import Gnuplot as Gnuplot_ori
27 import Numeric
27 import Numeric
28
28
29 from IPython.genutils import popkey,xsys
29 from IPython.genutils import popkey,xsys
30
30
31 # needed by hardcopy():
31 # needed by hardcopy():
32 gp = Gnuplot_ori.gp
32 gp = Gnuplot_ori.gp
33
33
34 # Patch for Gnuplot.py 1.6 compatibility.
34 # Patch for Gnuplot.py 1.6 compatibility.
35 # Thanks to Hayden Callow <h.callow@elec.canterbury.ac.nz>
35 # Thanks to Hayden Callow <h.callow@elec.canterbury.ac.nz>
36 try:
36 try:
37 OptionException = Gnuplot_ori.PlotItems.OptionException
37 OptionException = Gnuplot_ori.PlotItems.OptionException
38 except AttributeError:
38 except AttributeError:
39 OptionException = Gnuplot_ori.Errors.OptionError
39 OptionException = Gnuplot_ori.Errors.OptionError
40
40
41 # exhibit a similar interface to Gnuplot so it can be somewhat drop-in
41 # exhibit a similar interface to Gnuplot so it can be somewhat drop-in
42 Data = Gnuplot_ori.Data
42 Data = Gnuplot_ori.Data
43 Func = Gnuplot_ori.Func
43 Func = Gnuplot_ori.Func
44 GridData = Gnuplot_ori.GridData
44 GridData = Gnuplot_ori.GridData
45 PlotItem = Gnuplot_ori.PlotItem
45 PlotItem = Gnuplot_ori.PlotItem
46 PlotItems = Gnuplot_ori.PlotItems
46 PlotItems = Gnuplot_ori.PlotItems
47
47
48 # Modify some of Gnuplot's functions with improved versions (or bugfixed, in
48 # Modify some of Gnuplot's functions with improved versions (or bugfixed, in
49 # hardcopy's case). In order to preserve the docstrings at runtime, I've
49 # hardcopy's case). In order to preserve the docstrings at runtime, I've
50 # copied them from the original code.
50 # copied them from the original code.
51
51
52 # After some significant changes in v 1.7 of Gnuplot.py, we need to do a bit
52 # After some significant changes in v 1.7 of Gnuplot.py, we need to do a bit
53 # of version checking.
53 # of version checking.
54
54
55 if Gnuplot_ori.__version__ <= '1.6':
55 if Gnuplot_ori.__version__ <= '1.6':
56 _BaseFileItem = PlotItems.File
56 _BaseFileItem = PlotItems.File
57 _BaseTempFileItem = PlotItems.TempFile
57 _BaseTempFileItem = PlotItems.TempFile
58
58
59 # Fix the File class to add the 'index' option for Gnuplot versions < 1.7
59 # Fix the File class to add the 'index' option for Gnuplot versions < 1.7
60 class File(_BaseFileItem):
60 class File(_BaseFileItem):
61
61
62 _option_list = _BaseFileItem._option_list.copy()
62 _option_list = _BaseFileItem._option_list.copy()
63 _option_list.update({
63 _option_list.update({
64 'index' : lambda self, index: self.set_option_index(index),
64 'index' : lambda self, index: self.set_option_index(index),
65 })
65 })
66
66
67 # A new initializer is needed b/c we want to add a modified
67 # A new initializer is needed b/c we want to add a modified
68 # _option_sequence list which includes 'index' in the right place.
68 # _option_sequence list which includes 'index' in the right place.
69 def __init__(self,*args,**kw):
69 def __init__(self,*args,**kw):
70 self._option_sequence = ['binary', 'index', 'using', 'smooth', 'axes',
70 self._option_sequence = ['binary', 'index', 'using', 'smooth', 'axes',
71 'title', 'with']
71 'title', 'with']
72
72
73 _BaseFileItem.__init__(self,*args,**kw)
73 _BaseFileItem.__init__(self,*args,**kw)
74
74
75 # Let's fix the constructor docstring
75 # Let's fix the constructor docstring
76 __newdoc = \
76 __newdoc = \
77 """Additional Keyword arguments added by IPython:
77 """Additional Keyword arguments added by IPython:
78
78
79 'index=<int>' -- similar to the `index` keyword in Gnuplot.
79 'index=<int>' -- similar to the `index` keyword in Gnuplot.
80 This allows only some of the datasets in a file to be
80 This allows only some of the datasets in a file to be
81 plotted. Datasets within a file are assumed to be separated
81 plotted. Datasets within a file are assumed to be separated
82 by _pairs_ of blank lines, and the first one is numbered as
82 by _pairs_ of blank lines, and the first one is numbered as
83 0 (similar to C/Python usage)."""
83 0 (similar to C/Python usage)."""
84 __init__.__doc__ = PlotItems.File.__init__.__doc__ + __newdoc
84 __init__.__doc__ = PlotItems.File.__init__.__doc__ + __newdoc
85
85
86 def set_option_index(self, index):
86 def set_option_index(self, index):
87 if index is None:
87 if index is None:
88 self.clear_option('index')
88 self.clear_option('index')
89 elif type(index) in [type(''), type(1)]:
89 elif type(index) in [type(''), type(1)]:
90 self._options['index'] = (index, 'index %s' % index)
90 self._options['index'] = (index, 'index %s' % index)
91 elif type(index) is type(()):
91 elif type(index) is type(()):
92 self._options['index'] = (index,'index %s' %
92 self._options['index'] = (index,'index %s' %
93 string.join(map(repr, index), ':'))
93 string.join(map(repr, index), ':'))
94 else:
94 else:
95 raise OptionException('index=%s' % (index,))
95 raise OptionException('index=%s' % (index,))
96
96
97 # We need a FileClass with a different name from 'File', which is a
97 # We need a FileClass with a different name from 'File', which is a
98 # factory function in 1.7, so that our String class can subclass FileClass
98 # factory function in 1.7, so that our String class can subclass FileClass
99 # in any version.
99 # in any version.
100 _FileClass = File
100 _FileClass = File
101
101
102 elif Gnuplot_ori.__version__ =='1.7':
102 elif Gnuplot_ori.__version__ =='1.7':
103 _FileClass = _BaseFileItem = PlotItems._FileItem
103 _FileClass = _BaseFileItem = PlotItems._FileItem
104 _BaseTempFileItem = PlotItems._TempFileItem
104 _BaseTempFileItem = PlotItems._TempFileItem
105 File = PlotItems.File
105 File = PlotItems.File
106
106
107 else: # changes in the newer version (svn as of March'06)
107 else: # changes in the newer version (svn as of March'06)
108 _FileClass = _BaseFileItem = PlotItems._FileItem
108 _FileClass = _BaseFileItem = PlotItems._FileItem
109 _BaseTempFileItem = PlotItems._NewFileItem
109 _BaseTempFileItem = PlotItems._NewFileItem
110 File = PlotItems.File
110 File = PlotItems.File
111
111
112
112
113 # Now, we can add our generic code which is version independent
113 # Now, we can add our generic code which is version independent
114
114
115 # First some useful utilities
115 # First some useful utilities
116 def eps_fix_bbox(fname):
116 def eps_fix_bbox(fname):
117 """Fix the bounding box of an eps file by running ps2eps on it.
117 """Fix the bounding box of an eps file by running ps2eps on it.
118
118
119 If its name ends in .eps, the original file is removed.
119 If its name ends in .eps, the original file is removed.
120
120
121 This is particularly useful for plots made by Gnuplot with square aspect
121 This is particularly useful for plots made by Gnuplot with square aspect
122 ratio: there is a bug in Gnuplot which makes it generate a bounding box
122 ratio: there is a bug in Gnuplot which makes it generate a bounding box
123 which is far wider than the actual plot.
123 which is far wider than the actual plot.
124
124
125 This function assumes that ps2eps is installed in your system."""
125 This function assumes that ps2eps is installed in your system."""
126
126
127 # note: ps2ps and eps2eps do NOT work, ONLY ps2eps works correctly. The
127 # note: ps2ps and eps2eps do NOT work, ONLY ps2eps works correctly. The
128 # others make output with bitmapped fonts, which looks horrible.
128 # others make output with bitmapped fonts, which looks horrible.
129 print 'Fixing eps file: <%s>' % fname
129 print 'Fixing eps file: <%s>' % fname
130 xsys('ps2eps -f -q -l %s' % fname)
130 xsys('ps2eps -f -q -l %s' % fname)
131 if fname.endswith('.eps'):
131 if fname.endswith('.eps'):
132 os.rename(fname+'.eps',fname)
132 os.rename(fname+'.eps',fname)
133
133
134 def is_list1d(x,containers = [types.ListType,types.TupleType]):
134 def is_list1d(x,containers = [types.ListType,types.TupleType]):
135 """Returns true if x appears to be a 1d list/tuple/array.
135 """Returns true if x appears to be a 1d list/tuple/array.
136
136
137 The heuristics are: identify Numeric arrays, or lists/tuples whose first
137 The heuristics are: identify Numeric arrays, or lists/tuples whose first
138 element is not itself a list/tuple. This way zipped lists should work like
138 element is not itself a list/tuple. This way zipped lists should work like
139 the original Gnuplot. There's no inexpensive way to know if a list doesn't
139 the original Gnuplot. There's no inexpensive way to know if a list doesn't
140 have a composite object after its first element, so that kind of input
140 have a composite object after its first element, so that kind of input
141 will produce an error. But it should work well in most cases.
141 will produce an error. But it should work well in most cases.
142 """
142 """
143 x_type = type(x)
143 x_type = type(x)
144
144
145 return x_type == Numeric.ArrayType and len(x.shape)==1 or \
145 return x_type == Numeric.ArrayType and len(x.shape)==1 or \
146 (x_type in containers and
146 (x_type in containers and
147 type(x[0]) not in containers + [Numeric.ArrayType])
147 type(x[0]) not in containers + [Numeric.ArrayType])
148
148
149 def zip_items(items,titles=None):
149 def zip_items(items,titles=None):
150 """zip together neighboring 1-d arrays, and zip standalone ones
150 """zip together neighboring 1-d arrays, and zip standalone ones
151 with their index. Leave other plot items alone."""
151 with their index. Leave other plot items alone."""
152
152
153 class StandaloneItem(Exception): pass
153 class StandaloneItem(Exception): pass
154
154
155 def get_titles(titles):
155 def get_titles(titles):
156 """Return the next title and the input titles array.
156 """Return the next title and the input titles array.
157
157
158 The input array may be changed to None when no titles are left to
158 The input array may be changed to None when no titles are left to
159 prevent extra unnecessary calls to this function."""
159 prevent extra unnecessary calls to this function."""
160
160
161 try:
161 try:
162 title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope
162 title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope
163 except IndexError:
163 except IndexError:
164 titles = None # so we don't enter again
164 titles = None # so we don't enter again
165 title = None
165 title = None
166 else:
166 else:
167 tit_ct[0] += 1
167 tit_ct[0] += 1
168 return title,titles
168 return title,titles
169
169
170 new_items = []
170 new_items = []
171
171
172 if titles:
172 if titles:
173 # Initialize counter. It was put in a list as a hack to allow the
173 # Initialize counter. It was put in a list as a hack to allow the
174 # nested get_titles to modify it without raising a NameError.
174 # nested get_titles to modify it without raising a NameError.
175 tit_ct = [0]
175 tit_ct = [0]
176
176
177 n = 0 # this loop needs to be done by hand
177 n = 0 # this loop needs to be done by hand
178 while n < len(items):
178 while n < len(items):
179 item = items[n]
179 item = items[n]
180 try:
180 try:
181 if is_list1d(item):
181 if is_list1d(item):
182 if n==len(items)-1: # last in list
182 if n==len(items)-1: # last in list
183 raise StandaloneItem
183 raise StandaloneItem
184 else: # check the next item and zip together if needed
184 else: # check the next item and zip together if needed
185 next_item = items[n+1]
185 next_item = items[n+1]
186 if next_item is None:
186 if next_item is None:
187 n += 1
187 n += 1
188 raise StandaloneItem
188 raise StandaloneItem
189 elif is_list1d(next_item):
189 elif is_list1d(next_item):
190 # this would be best done with an iterator
190 # this would be best done with an iterator
191 if titles:
191 if titles:
192 title,titles = get_titles(titles)
192 title,titles = get_titles(titles)
193 else:
193 else:
194 title = None
194 title = None
195 new_items.append(Data(zip(item,next_item),
195 new_items.append(Data(zip(item,next_item),
196 title=title))
196 title=title))
197 n += 1 # avoid double-inclusion of next item
197 n += 1 # avoid double-inclusion of next item
198 else: # can't zip with next, zip with own index list
198 else: # can't zip with next, zip with own index list
199 raise StandaloneItem
199 raise StandaloneItem
200 else: # not 1-d array
200 else: # not 1-d array
201 new_items.append(item)
201 new_items.append(item)
202 except StandaloneItem:
202 except StandaloneItem:
203 if titles:
203 if titles:
204 title,titles = get_titles(titles)
204 title,titles = get_titles(titles)
205 else:
205 else:
206 title = None
206 title = None
207 new_items.append(Data(zip(range(len(item)),item),title=title))
207 new_items.append(Data(zip(range(len(item)),item),title=title))
208 except AttributeError:
208 except AttributeError:
209 new_items.append(item)
209 new_items.append(item)
210 n+=1
210 n+=1
211
211
212 return new_items
212 return new_items
213
213
214 # And some classes with enhanced functionality.
214 # And some classes with enhanced functionality.
215 class String(_FileClass):
215 class String(_FileClass):
216 """Make a PlotItem from data in a string with the same format as a File.
216 """Make a PlotItem from data in a string with the same format as a File.
217
217
218 This allows writing data directly inside python scripts using the exact
218 This allows writing data directly inside python scripts using the exact
219 same format and manipulation options which would be used for external
219 same format and manipulation options which would be used for external
220 files."""
220 files."""
221
221
222 def __init__(self, data_str, **keyw):
222 def __init__(self, data_str, **keyw):
223 """Construct a String object.
223 """Construct a String object.
224
224
225 <data_str> is a string formatted exactly like a valid Gnuplot data
225 <data_str> is a string formatted exactly like a valid Gnuplot data
226 file would be. All options from the File constructor are valid here.
226 file would be. All options from the File constructor are valid here.
227
227
228 Warning: when used for interactive plotting in scripts which exit
228 Warning: when used for interactive plotting in scripts which exit
229 immediately, you may get an error because the temporary file used to
229 immediately, you may get an error because the temporary file used to
230 hold the string data was deleted before Gnuplot had a chance to see
230 hold the string data was deleted before Gnuplot had a chance to see
231 it. You can work around this problem by putting a raw_input() call at
231 it. You can work around this problem by putting a raw_input() call at
232 the end of the script.
232 the end of the script.
233
233
234 This problem does not appear when generating PostScript output, only
234 This problem does not appear when generating PostScript output, only
235 with Gnuplot windows."""
235 with Gnuplot windows."""
236
236
237 self.tmpfile = _BaseTempFileItem()
237 self.tmpfile = _BaseTempFileItem()
238 tmpfile = file(self.tmpfile.filename,'w')
238 tmpfile = file(self.tmpfile.filename,'w')
239 tmpfile.write(data_str)
239 tmpfile.write(data_str)
240 _BaseFileItem.__init__(self,self.tmpfile,**keyw)
240 _BaseFileItem.__init__(self,self.tmpfile,**keyw)
241
241
242
242
243 class Gnuplot(Gnuplot_ori.Gnuplot):
243 class Gnuplot(Gnuplot_ori.Gnuplot):
244 """Improved Gnuplot class.
244 """Improved Gnuplot class.
245
245
246 Enhancements: better plot,replot and hardcopy methods. New methods for
246 Enhancements: better plot,replot and hardcopy methods. New methods for
247 quick range setting.
247 quick range setting.
248 """
248 """
249
249
250 def xrange(self,min='*',max='*'):
250 def xrange(self,min='*',max='*'):
251 """Set xrange. If min/max is omitted, it is set to '*' (auto).
251 """Set xrange. If min/max is omitted, it is set to '*' (auto).
252
252
253 Note that this is different from the regular Gnuplot behavior, where
253 Note that this is different from the regular Gnuplot behavior, where
254 an unspecified limit means no change. Here any unspecified limit is
254 an unspecified limit means no change. Here any unspecified limit is
255 set to autoscaling, allowing these functions to be used for full
255 set to autoscaling, allowing these functions to be used for full
256 autoscaling when called with no arguments.
256 autoscaling when called with no arguments.
257
257
258 To preserve one limit's current value while changing the other, an
258 To preserve one limit's current value while changing the other, an
259 explicit '' argument must be given as the limit to be kept.
259 explicit '' argument must be given as the limit to be kept.
260
260
261 Similar functions exist for [y{2}z{2}rtuv]range."""
261 Similar functions exist for [y{2}z{2}rtuv]range."""
262
262
263 self('set xrange [%s:%s]' % (min,max))
263 self('set xrange [%s:%s]' % (min,max))
264
264
265 def yrange(self,min='*',max='*'):
265 def yrange(self,min='*',max='*'):
266 self('set yrange [%s:%s]' % (min,max))
266 self('set yrange [%s:%s]' % (min,max))
267
267
268 def zrange(self,min='*',max='*'):
268 def zrange(self,min='*',max='*'):
269 self('set zrange [%s:%s]' % (min,max))
269 self('set zrange [%s:%s]' % (min,max))
270
270
271 def x2range(self,min='*',max='*'):
271 def x2range(self,min='*',max='*'):
272 self('set xrange [%s:%s]' % (min,max))
272 self('set xrange [%s:%s]' % (min,max))
273
273
274 def y2range(self,min='*',max='*'):
274 def y2range(self,min='*',max='*'):
275 self('set yrange [%s:%s]' % (min,max))
275 self('set yrange [%s:%s]' % (min,max))
276
276
277 def z2range(self,min='*',max='*'):
277 def z2range(self,min='*',max='*'):
278 self('set zrange [%s:%s]' % (min,max))
278 self('set zrange [%s:%s]' % (min,max))
279
279
280 def rrange(self,min='*',max='*'):
280 def rrange(self,min='*',max='*'):
281 self('set rrange [%s:%s]' % (min,max))
281 self('set rrange [%s:%s]' % (min,max))
282
282
283 def trange(self,min='*',max='*'):
283 def trange(self,min='*',max='*'):
284 self('set trange [%s:%s]' % (min,max))
284 self('set trange [%s:%s]' % (min,max))
285
285
286 def urange(self,min='*',max='*'):
286 def urange(self,min='*',max='*'):
287 self('set urange [%s:%s]' % (min,max))
287 self('set urange [%s:%s]' % (min,max))
288
288
289 def vrange(self,min='*',max='*'):
289 def vrange(self,min='*',max='*'):
290 self('set vrange [%s:%s]' % (min,max))
290 self('set vrange [%s:%s]' % (min,max))
291
291
292 def set_ps(self,option):
292 def set_ps(self,option):
293 """Set an option for the PostScript terminal and reset default term."""
293 """Set an option for the PostScript terminal and reset default term."""
294
294
295 self('set terminal postscript %s ' % option)
295 self('set terminal postscript %s ' % option)
296 self('set terminal %s' % gp.GnuplotOpts.default_term)
296 self('set terminal %s' % gp.GnuplotOpts.default_term)
297
297
298 def __plot_ps(self, plot_method,*items, **keyw):
298 def __plot_ps(self, plot_method,*items, **keyw):
299 """Wrapper for plot/splot/replot, with processing of hardcopy options.
299 """Wrapper for plot/splot/replot, with processing of hardcopy options.
300
300
301 For internal use only."""
301 For internal use only."""
302
302
303 # Filter out PostScript options which will crash the normal plot/replot
303 # Filter out PostScript options which will crash the normal plot/replot
304 psargs = {'filename':None,
304 psargs = {'filename':None,
305 'mode':None,
305 'mode':None,
306 'eps':None,
306 'eps':None,
307 'enhanced':None,
307 'enhanced':None,
308 'color':None,
308 'color':None,
309 'solid':None,
309 'solid':None,
310 'duplexing':None,
310 'duplexing':None,
311 'fontname':None,
311 'fontname':None,
312 'fontsize':None,
312 'fontsize':None,
313 'debug':0 }
313 'debug':0 }
314
314
315 for k in psargs.keys():
315 for k in psargs.keys():
316 if keyw.has_key(k):
316 if keyw.has_key(k):
317 psargs[k] = keyw[k]
317 psargs[k] = keyw[k]
318 del keyw[k]
318 del keyw[k]
319
319
320 # Filter out other options the original plot doesn't know
320 # Filter out other options the original plot doesn't know
321 hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None)
321 hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None)
322 titles = popkey(keyw,'titles',0)
322 titles = popkey(keyw,'titles',0)
323
323
324 # the filename keyword should control hardcopy generation, this is an
324 # the filename keyword should control hardcopy generation, this is an
325 # override switch only which needs to be explicitly set to zero
325 # override switch only which needs to be explicitly set to zero
326 if hardcopy:
326 if hardcopy:
327 if psargs['filename'] is None:
327 if psargs['filename'] is None:
328 raise ValueError, \
328 raise ValueError, \
329 'If you request hardcopy, you must give a filename.'
329 'If you request hardcopy, you must give a filename.'
330
330
331 # set null output so nothing goes to screen. hardcopy() restores output
331 # set null output so nothing goes to screen. hardcopy() restores output
332 self('set term dumb')
332 self('set term dumb')
333 # I don't know how to prevent screen output in Windows
333 # I don't know how to prevent screen output in Windows
334 if os.name == 'posix':
334 if os.name == 'posix':
335 self('set output "/dev/null"')
335 self('set output "/dev/null"')
336
336
337 new_items = zip_items(items,titles)
337 new_items = zip_items(items,titles)
338 # plot_method is either plot or replot from the original Gnuplot class:
338 # plot_method is either plot or replot from the original Gnuplot class:
339 plot_method(self,*new_items,**keyw)
339 plot_method(self,*new_items,**keyw)
340
340
341 # Do hardcopy if requested
341 # Do hardcopy if requested
342 if hardcopy:
342 if hardcopy:
343 if psargs['filename'].endswith('.eps'):
343 if psargs['filename'].endswith('.eps'):
344 psargs['eps'] = 1
344 psargs['eps'] = 1
345 self.hardcopy(**psargs)
345 self.hardcopy(**psargs)
346
346
347 def plot(self, *items, **keyw):
347 def plot(self, *items, **keyw):
348 """Draw a new plot.
348 """Draw a new plot.
349
349
350 Clear the current plot and create a new 2-d plot containing
350 Clear the current plot and create a new 2-d plot containing
351 the specified items. Each arguments should be of the
351 the specified items. Each arguments should be of the
352 following types:
352 following types:
353
353
354 'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most
354 'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most
355 flexible way to call plot because the PlotItems can
355 flexible way to call plot because the PlotItems can
356 contain suboptions. Moreover, PlotItems can be saved to
356 contain suboptions. Moreover, PlotItems can be saved to
357 variables so that their lifetime is longer than one plot
357 variables so that their lifetime is longer than one plot
358 command; thus they can be replotted with minimal overhead.
358 command; thus they can be replotted with minimal overhead.
359
359
360 'string' (e.g., 'sin(x)') -- The string is interpreted as
360 'string' (e.g., 'sin(x)') -- The string is interpreted as
361 'Func(string)' (a function that is computed by gnuplot).
361 'Func(string)' (a function that is computed by gnuplot).
362
362
363 Anything else -- The object, which should be convertible to an
363 Anything else -- The object, which should be convertible to an
364 array, is passed to the 'Data' constructor, and thus
364 array, is passed to the 'Data' constructor, and thus
365 plotted as data. If the conversion fails, an exception is
365 plotted as data. If the conversion fails, an exception is
366 raised.
366 raised.
367
367
368
368
369 This is a modified version of plot(). Compared to the original in
369 This is a modified version of plot(). Compared to the original in
370 Gnuplot.py, this version has several enhancements, listed below.
370 Gnuplot.py, this version has several enhancements, listed below.
371
371
372
372
373 Modifications to the input arguments
373 Modifications to the input arguments
374 ------------------------------------
374 ------------------------------------
375
375
376 (1-d array means Numeric array, list or tuple):
376 (1-d array means Numeric array, list or tuple):
377
377
378 (i) Any 1-d array which is NOT followed by another 1-d array, is
378 (i) Any 1-d array which is NOT followed by another 1-d array, is
379 automatically zipped with range(len(array_1d)). Typing g.plot(y) will
379 automatically zipped with range(len(array_1d)). Typing g.plot(y) will
380 plot y against its indices.
380 plot y against its indices.
381
381
382 (ii) If two 1-d arrays are contiguous in the argument list, they are
382 (ii) If two 1-d arrays are contiguous in the argument list, they are
383 automatically zipped together. So g.plot(x,y) plots y vs. x, and
383 automatically zipped together. So g.plot(x,y) plots y vs. x, and
384 g.plot(x1,y1,x2,y2) plots y1 vs. x1 and y2 vs. x2.
384 g.plot(x1,y1,x2,y2) plots y1 vs. x1 and y2 vs. x2.
385
385
386 (iii) Any 1-d array which is followed by None is automatically zipped
386 (iii) Any 1-d array which is followed by None is automatically zipped
387 with range(len(array_1d)). In this form, typing g.plot(y1,None,y2)
387 with range(len(array_1d)). In this form, typing g.plot(y1,None,y2)
388 will plot both y1 and y2 against their respective indices (and NOT
388 will plot both y1 and y2 against their respective indices (and NOT
389 versus one another). The None prevents zipping y1 and y2 together, and
389 versus one another). The None prevents zipping y1 and y2 together, and
390 since y2 is unpaired it is automatically zipped to its indices by (i)
390 since y2 is unpaired it is automatically zipped to its indices by (i)
391
391
392 (iv) Any other arguments which don't match these cases are left alone and
392 (iv) Any other arguments which don't match these cases are left alone and
393 passed to the code below.
393 passed to the code below.
394
394
395 For lists or tuples, the heuristics used to determine whether they are
395 For lists or tuples, the heuristics used to determine whether they are
396 in fact 1-d is fairly simplistic: their first element is checked, and
396 in fact 1-d is fairly simplistic: their first element is checked, and
397 if it is not a list or tuple itself, it is assumed that the whole
397 if it is not a list or tuple itself, it is assumed that the whole
398 object is one-dimensional.
398 object is one-dimensional.
399
399
400 An additional optional keyword 'titles' has been added: it must be a
400 An additional optional keyword 'titles' has been added: it must be a
401 list of strings to be used as labels for the individual plots which
401 list of strings to be used as labels for the individual plots which
402 are NOT PlotItem objects (since those objects carry their own labels
402 are NOT PlotItem objects (since those objects carry their own labels
403 within).
403 within).
404
404
405
405
406 PostScript generation
406 PostScript generation
407 ---------------------
407 ---------------------
408
408
409 This version of plot() also handles automatically the production of
409 This version of plot() also handles automatically the production of
410 PostScript output. The main options are (given as keyword arguments):
410 PostScript output. The main options are (given as keyword arguments):
411
411
412 - filename: a string, typically ending in .eps. If given, the plot is
412 - filename: a string, typically ending in .eps. If given, the plot is
413 sent to this file in PostScript format.
413 sent to this file in PostScript format.
414
414
415 - hardcopy: this can be set to 0 to override 'filename'. It does not
415 - hardcopy: this can be set to 0 to override 'filename'. It does not
416 need to be given to produce PostScript, its purpose is to allow
416 need to be given to produce PostScript, its purpose is to allow
417 switching PostScript output off globally in scripts without having to
417 switching PostScript output off globally in scripts without having to
418 manually change 'filename' values in multiple calls.
418 manually change 'filename' values in multiple calls.
419
419
420 All other keywords accepted by Gnuplot.hardcopy() are transparently
420 All other keywords accepted by Gnuplot.hardcopy() are transparently
421 passed, and safely ignored if output is sent to the screen instead of
421 passed, and safely ignored if output is sent to the screen instead of
422 PostScript.
422 PostScript.
423
423
424 For example:
424 For example:
425
425
426 In [1]: x=frange(0,2*pi,npts=100)
426 In [1]: x=frange(0,2*pi,npts=100)
427
427
428 Generate a plot in file 'sin.eps':
428 Generate a plot in file 'sin.eps':
429
429
430 In [2]: plot(x,sin(x),filename = 'sin.eps')
430 In [2]: plot(x,sin(x),filename = 'sin.eps')
431
431
432 Plot to screen instead, without having to change the filename:
432 Plot to screen instead, without having to change the filename:
433
433
434 In [3]: plot(x,sin(x),filename = 'sin.eps',hardcopy=0)
434 In [3]: plot(x,sin(x),filename = 'sin.eps',hardcopy=0)
435
435
436 Pass the 'color=0' option to hardcopy for monochrome output:
436 Pass the 'color=0' option to hardcopy for monochrome output:
437
437
438 In [4]: plot(x,sin(x),filename = 'sin.eps',color=0)
438 In [4]: plot(x,sin(x),filename = 'sin.eps',color=0)
439
439
440 PostScript generation through plot() is useful mainly for scripting
440 PostScript generation through plot() is useful mainly for scripting
441 uses where you are not interested in interactive plotting. For
441 uses where you are not interested in interactive plotting. For
442 interactive use, the hardcopy() function is typically more convenient:
442 interactive use, the hardcopy() function is typically more convenient:
443
443
444 In [5]: plot(x,sin(x))
444 In [5]: plot(x,sin(x))
445
445
446 In [6]: hardcopy('sin.eps') """
446 In [6]: hardcopy('sin.eps') """
447
447
448 self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw)
448 self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw)
449
449
450 def plot2(self,arg,**kw):
450 def plot2(self,arg,**kw):
451 """Plot the entries of a dictionary or a list/tuple of arrays.
451 """Plot the entries of a dictionary or a list/tuple of arrays.
452
452
453 This simple utility calls plot() with a list of Gnuplot.Data objects
453 This simple utility calls plot() with a list of Gnuplot.Data objects
454 constructed either from the values of the input dictionary, or the entries
454 constructed either from the values of the input dictionary, or the entries
455 in it if it is a tuple or list. Each item gets labeled with the key/index
455 in it if it is a tuple or list. Each item gets labeled with the key/index
456 in the Gnuplot legend.
456 in the Gnuplot legend.
457
457
458 Each item is plotted by zipping it with a list of its indices.
458 Each item is plotted by zipping it with a list of its indices.
459
459
460 Any keywords are passed directly to plot()."""
460 Any keywords are passed directly to plot()."""
461
461
462 if hasattr(arg,'keys'):
462 if hasattr(arg,'keys'):
463 keys = arg.keys()
463 keys = arg.keys()
464 keys.sort()
464 keys.sort()
465 else:
465 else:
466 keys = range(len(arg))
466 keys = range(len(arg))
467
467
468 pitems = [Data(zip(range(len(arg[k])),arg[k]),title=`k`) for k in keys]
468 pitems = [Data(zip(range(len(arg[k])),arg[k]),title=`k`) for k in keys]
469 self.plot(*pitems,**kw)
469 self.plot(*pitems,**kw)
470
470
471 def splot(self, *items, **keyw):
471 def splot(self, *items, **keyw):
472 """Draw a new three-dimensional plot.
472 """Draw a new three-dimensional plot.
473
473
474 Clear the current plot and create a new 3-d plot containing
474 Clear the current plot and create a new 3-d plot containing
475 the specified items. Arguments can be of the following types:
475 the specified items. Arguments can be of the following types:
476
476
477 'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This
477 'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This
478 is the most flexible way to call plot because the
478 is the most flexible way to call plot because the
479 PlotItems can contain suboptions. Moreover, PlotItems can
479 PlotItems can contain suboptions. Moreover, PlotItems can
480 be saved to variables so that their lifetime is longer
480 be saved to variables so that their lifetime is longer
481 than one plot command--thus they can be replotted with
481 than one plot command--thus they can be replotted with
482 minimal overhead.
482 minimal overhead.
483
483
484 'string' (e.g., 'sin(x*y)') -- The string is interpreted as a
484 'string' (e.g., 'sin(x*y)') -- The string is interpreted as a
485 'Func()' (a function that is computed by gnuplot).
485 'Func()' (a function that is computed by gnuplot).
486
486
487 Anything else -- The object is converted to a Data() item, and
487 Anything else -- The object is converted to a Data() item, and
488 thus plotted as data. Note that each data point should
488 thus plotted as data. Note that each data point should
489 normally have at least three values associated with it
489 normally have at least three values associated with it
490 (i.e., x, y, and z). If the conversion fails, an
490 (i.e., x, y, and z). If the conversion fails, an
491 exception is raised.
491 exception is raised.
492
492
493 This is a modified version of splot(). Compared to the original in
493 This is a modified version of splot(). Compared to the original in
494 Gnuplot.py, this version has several enhancements, listed in the
494 Gnuplot.py, this version has several enhancements, listed in the
495 plot() documentation.
495 plot() documentation.
496 """
496 """
497
497
498 self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw)
498 self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw)
499
499
500 def replot(self, *items, **keyw):
500 def replot(self, *items, **keyw):
501 """Replot the data, possibly adding new 'PlotItem's.
501 """Replot the data, possibly adding new 'PlotItem's.
502
502
503 Replot the existing graph, using the items in the current
503 Replot the existing graph, using the items in the current
504 itemlist. If arguments are specified, they are interpreted as
504 itemlist. If arguments are specified, they are interpreted as
505 additional items to be plotted alongside the existing items on
505 additional items to be plotted alongside the existing items on
506 the same graph. See 'plot' for details.
506 the same graph. See 'plot' for details.
507
507
508 If you want to replot to a postscript file, you MUST give the
508 If you want to replot to a postscript file, you MUST give the
509 'filename' keyword argument in each call to replot. The Gnuplot python
509 'filename' keyword argument in each call to replot. The Gnuplot python
510 interface has no way of knowing that your previous call to
510 interface has no way of knowing that your previous call to
511 Gnuplot.plot() was meant for PostScript output."""
511 Gnuplot.plot() was meant for PostScript output."""
512
512
513 self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw)
513 self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw)
514
514
515 # The original hardcopy has a bug. See fix at the end. The rest of the code
515 # The original hardcopy has a bug. See fix at the end. The rest of the code
516 # was lifted verbatim from the original, so that people using IPython get the
516 # was lifted verbatim from the original, so that people using IPython get the
517 # benefits without having to manually patch Gnuplot.py
517 # benefits without having to manually patch Gnuplot.py
518 def hardcopy(self, filename=None,
518 def hardcopy(self, filename=None,
519 mode=None,
519 mode=None,
520 eps=None,
520 eps=None,
521 enhanced=None,
521 enhanced=None,
522 color=None,
522 color=None,
523 solid=None,
523 solid=None,
524 duplexing=None,
524 duplexing=None,
525 fontname=None,
525 fontname=None,
526 fontsize=None,
526 fontsize=None,
527 debug = 0,
527 debug = 0,
528 ):
528 ):
529 """Create a hardcopy of the current plot.
529 """Create a hardcopy of the current plot.
530
530
531 Create a postscript hardcopy of the current plot to the
531 Create a postscript hardcopy of the current plot to the
532 default printer (if configured) or to the specified filename.
532 default printer (if configured) or to the specified filename.
533
533
534 Note that gnuplot remembers the postscript suboptions across
534 Note that gnuplot remembers the postscript suboptions across
535 terminal changes. Therefore if you set, for example, color=1
535 terminal changes. Therefore if you set, for example, color=1
536 for one hardcopy then the next hardcopy will also be color
536 for one hardcopy then the next hardcopy will also be color
537 unless you explicitly choose color=0. Alternately you can
537 unless you explicitly choose color=0. Alternately you can
538 force all of the options to their defaults by setting
538 force all of the options to their defaults by setting
539 mode='default'. I consider this to be a bug in gnuplot.
539 mode='default'. I consider this to be a bug in gnuplot.
540
540
541 Keyword arguments:
541 Keyword arguments:
542
542
543 'filename=<string>' -- if a filename is specified, save the
543 'filename=<string>' -- if a filename is specified, save the
544 output in that file; otherwise print it immediately
544 output in that file; otherwise print it immediately
545 using the 'default_lpr' configuration option. If the
545 using the 'default_lpr' configuration option. If the
546 filename ends in '.eps', EPS mode is automatically
546 filename ends in '.eps', EPS mode is automatically
547 selected (like manually specifying eps=1 or mode='eps').
547 selected (like manually specifying eps=1 or mode='eps').
548
548
549 'mode=<string>' -- set the postscript submode ('landscape',
549 'mode=<string>' -- set the postscript submode ('landscape',
550 'portrait', 'eps', or 'default'). The default is
550 'portrait', 'eps', or 'default'). The default is
551 to leave this option unspecified.
551 to leave this option unspecified.
552
552
553 'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to
553 'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to
554 generate encapsulated postscript.
554 generate encapsulated postscript.
555
555
556 'enhanced=<bool>' -- if set (the default), then generate
556 'enhanced=<bool>' -- if set (the default), then generate
557 enhanced postscript, which allows extra features like
557 enhanced postscript, which allows extra features like
558 font-switching, superscripts, and subscripts in axis
558 font-switching, superscripts, and subscripts in axis
559 labels. (Some old gnuplot versions do not support
559 labels. (Some old gnuplot versions do not support
560 enhanced postscript; if this is the case set
560 enhanced postscript; if this is the case set
561 gp.GnuplotOpts.prefer_enhanced_postscript=None.)
561 gp.GnuplotOpts.prefer_enhanced_postscript=None.)
562
562
563 'color=<bool>' -- if set, create a plot with color. Default
563 'color=<bool>' -- if set, create a plot with color. Default
564 is to leave this option unchanged.
564 is to leave this option unchanged.
565
565
566 'solid=<bool>' -- if set, force lines to be solid (i.e., not
566 'solid=<bool>' -- if set, force lines to be solid (i.e., not
567 dashed).
567 dashed).
568
568
569 'duplexing=<string>' -- set duplexing option ('defaultplex',
569 'duplexing=<string>' -- set duplexing option ('defaultplex',
570 'simplex', or 'duplex'). Only request double-sided
570 'simplex', or 'duplex'). Only request double-sided
571 printing if your printer can handle it. Actually this
571 printing if your printer can handle it. Actually this
572 option is probably meaningless since hardcopy() can only
572 option is probably meaningless since hardcopy() can only
573 print a single plot at a time.
573 print a single plot at a time.
574
574
575 'fontname=<string>' -- set the default font to <string>,
575 'fontname=<string>' -- set the default font to <string>,
576 which must be a valid postscript font. The default is
576 which must be a valid postscript font. The default is
577 to leave this option unspecified.
577 to leave this option unspecified.
578
578
579 'fontsize=<double>' -- set the default font size, in
579 'fontsize=<double>' -- set the default font size, in
580 postscript points.
580 postscript points.
581
581
582 'debug=<bool>' -- print extra debugging information (useful if
582 'debug=<bool>' -- print extra debugging information (useful if
583 your PostScript files are misteriously not being created).
583 your PostScript files are misteriously not being created).
584 """
584 """
585
585
586 if filename is None:
586 if filename is None:
587 assert gp.GnuplotOpts.default_lpr is not None, \
587 assert gp.GnuplotOpts.default_lpr is not None, \
588 OptionException('default_lpr is not set, so you can only '
588 OptionException('default_lpr is not set, so you can only '
589 'print to a file.')
589 'print to a file.')
590 filename = gp.GnuplotOpts.default_lpr
590 filename = gp.GnuplotOpts.default_lpr
591 lpr_output = 1
591 lpr_output = 1
592 else:
592 else:
593 if filename.endswith('.eps'):
593 if filename.endswith('.eps'):
594 eps = 1
594 eps = 1
595 lpr_output = 0
595 lpr_output = 0
596
596
597 # Be careful processing the options. If the user didn't
597 # Be careful processing the options. If the user didn't
598 # request an option explicitly, do not specify it on the 'set
598 # request an option explicitly, do not specify it on the 'set
599 # terminal' line (don't even specify the default value for the
599 # terminal' line (don't even specify the default value for the
600 # option). This is to avoid confusing older versions of
600 # option). This is to avoid confusing older versions of
601 # gnuplot that do not support all of these options. The
601 # gnuplot that do not support all of these options. The
602 # exception is 'enhanced', which is just too useful to have to
602 # exception is 'enhanced', which is just too useful to have to
603 # specify each time!
603 # specify each time!
604
604
605 setterm = ['set', 'terminal', 'postscript']
605 setterm = ['set', 'terminal', 'postscript']
606 if eps:
606 if eps:
607 assert mode is None or mode=='eps', \
607 assert mode is None or mode=='eps', \
608 OptionException('eps option and mode are incompatible')
608 OptionException('eps option and mode are incompatible')
609 setterm.append('eps')
609 setterm.append('eps')
610 else:
610 else:
611 if mode is not None:
611 if mode is not None:
612 assert mode in ['landscape', 'portrait', 'eps', 'default'], \
612 assert mode in ['landscape', 'portrait', 'eps', 'default'], \
613 OptionException('illegal mode "%s"' % mode)
613 OptionException('illegal mode "%s"' % mode)
614 setterm.append(mode)
614 setterm.append(mode)
615 if enhanced is None:
615 if enhanced is None:
616 enhanced = gp.GnuplotOpts.prefer_enhanced_postscript
616 enhanced = gp.GnuplotOpts.prefer_enhanced_postscript
617 if enhanced is not None:
617 if enhanced is not None:
618 if enhanced: setterm.append('enhanced')
618 if enhanced: setterm.append('enhanced')
619 else: setterm.append('noenhanced')
619 else: setterm.append('noenhanced')
620 if color is not None:
620 if color is not None:
621 if color: setterm.append('color')
621 if color: setterm.append('color')
622 else: setterm.append('monochrome')
622 else: setterm.append('monochrome')
623 if solid is not None:
623 if solid is not None:
624 if solid: setterm.append('solid')
624 if solid: setterm.append('solid')
625 else: setterm.append('dashed')
625 else: setterm.append('dashed')
626 if duplexing is not None:
626 if duplexing is not None:
627 assert duplexing in ['defaultplex', 'simplex', 'duplex'], \
627 assert duplexing in ['defaultplex', 'simplex', 'duplex'], \
628 OptionException('illegal duplexing mode "%s"' % duplexing)
628 OptionException('illegal duplexing mode "%s"' % duplexing)
629 setterm.append(duplexing)
629 setterm.append(duplexing)
630 if fontname is not None:
630 if fontname is not None:
631 setterm.append('"%s"' % fontname)
631 setterm.append('"%s"' % fontname)
632 if fontsize is not None:
632 if fontsize is not None:
633 setterm.append('%s' % fontsize)
633 setterm.append('%s' % fontsize)
634
634
635 self(string.join(setterm))
635 self(string.join(setterm))
636 self.set_string('output', filename)
636 self.set_string('output', filename)
637 # replot the current figure (to the printer):
637 # replot the current figure (to the printer):
638 self.refresh()
638 self.refresh()
639
639
640 # fperez. Ugly kludge: often for some reason the file is NOT created
640 # fperez. Ugly kludge: often for some reason the file is NOT created
641 # and we must reissue the creation commands. I have no idea why!
641 # and we must reissue the creation commands. I have no idea why!
642 if not lpr_output:
642 if not lpr_output:
643 #print 'Hardcopy <%s>' % filename # dbg
643 #print 'Hardcopy <%s>' % filename # dbg
644 maxtries = 20
644 maxtries = 20
645 delay = 0.1 # delay (in seconds) between print attempts
645 delay = 0.1 # delay (in seconds) between print attempts
646 for i in range(maxtries):
646 for i in range(maxtries):
647 time.sleep(0.05) # safety, very small delay
647 time.sleep(0.05) # safety, very small delay
648 if os.path.isfile(filename):
648 if os.path.isfile(filename):
649 if debug:
649 if debug:
650 print 'Hardcopy to file <%s> success at attempt #%s.' \
650 print 'Hardcopy to file <%s> success at attempt #%s.' \
651 % (filename,i+1)
651 % (filename,i+1)
652 break
652 break
653 time.sleep(delay)
653 time.sleep(delay)
654 # try again, issue all commands just in case
654 # try again, issue all commands just in case
655 self(string.join(setterm))
655 self(string.join(setterm))
656 self.set_string('output', filename)
656 self.set_string('output', filename)
657 self.refresh()
657 self.refresh()
658 if not os.path.isfile(filename):
658 if not os.path.isfile(filename):
659 print >> sys.stderr,'ERROR: Tried %s times and failed to '\
659 print >> sys.stderr,'ERROR: Tried %s times and failed to '\
660 'create hardcopy file `%s`' % (maxtries,filename)
660 'create hardcopy file `%s`' % (maxtries,filename)
661
661
662 # reset the terminal to its `default' setting:
662 # reset the terminal to its `default' setting:
663 self('set terminal %s' % gp.GnuplotOpts.default_term)
663 self('set terminal %s' % gp.GnuplotOpts.default_term)
664 self.set_string('output')
664 self.set_string('output')
665
665
666 #********************** End of file <Gnuplot2.py> ************************
666 #********************** End of file <Gnuplot2.py> ************************
@@ -1,148 +1,148 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Interactive functions and magic functions for Gnuplot usage.
2 """Interactive functions and magic functions for Gnuplot usage.
3
3
4 This requires the Gnuplot.py module for interfacing python with Gnuplot, which
4 This requires the Gnuplot.py module for interfacing python with Gnuplot, which
5 can be downloaded from:
5 can be downloaded from:
6
6
7 http://gnuplot-py.sourceforge.net/
7 http://gnuplot-py.sourceforge.net/
8
8
9 See gphelp() below for details on the services offered by this module.
9 See gphelp() below for details on the services offered by this module.
10
10
11 Inspired by a suggestion/request from Arnd Baecker.
11 Inspired by a suggestion/request from Arnd Baecker.
12
12
13 $Id: GnuplotInteractive.py 389 2004-10-09 07:59:30Z fperez $"""
13 $Id: GnuplotInteractive.py 389 2004-10-09 07:59:30Z fperez $"""
14
14
15 __all__ = ['Gnuplot','gp','gp_new','plot','plot2','splot','replot',
15 __all__ = ['Gnuplot','gp','gp_new','plot','plot2','splot','replot',
16 'hardcopy','gpdata','gpfile','gpstring','gpfunc','gpgrid',
16 'hardcopy','gpdata','gpfile','gpstring','gpfunc','gpgrid',
17 'gphelp']
17 'gphelp']
18
18
19 import IPython.GnuplotRuntime as GRun
19 import IPython.GnuplotRuntime as GRun
20 from IPython.genutils import page,warn
20 from IPython.genutils import page,warn
21
21
22 # Set global names for interactive use
22 # Set global names for interactive use
23 Gnuplot = GRun.Gnuplot
23 Gnuplot = GRun.Gnuplot
24 gp_new = GRun.gp_new
24 gp_new = GRun.gp_new
25 gp = GRun.gp
25 gp = GRun.gp
26 plot = gp.plot
26 plot = gp.plot
27 plot2 = gp.plot2
27 plot2 = gp.plot2
28 splot = gp.splot
28 splot = gp.splot
29 replot = gp.replot
29 replot = gp.replot
30 hardcopy = gp.hardcopy
30 hardcopy = gp.hardcopy
31
31
32 # Accessors for the main plot object constructors:
32 # Accessors for the main plot object constructors:
33 gpdata = Gnuplot.Data
33 gpdata = Gnuplot.Data
34 gpfile = Gnuplot.File
34 gpfile = Gnuplot.File
35 gpstring = Gnuplot.String
35 gpstring = Gnuplot.String
36 gpfunc = Gnuplot.Func
36 gpfunc = Gnuplot.Func
37 gpgrid = Gnuplot.GridData
37 gpgrid = Gnuplot.GridData
38
38
39 def gphelp():
39 def gphelp():
40 """Print information about the Gnuplot facilities in IPython."""
40 """Print information about the Gnuplot facilities in IPython."""
41
41
42 page("""
42 page("""
43 IPython provides an interface to access the Gnuplot scientific plotting
43 IPython provides an interface to access the Gnuplot scientific plotting
44 system, in an environment similar to that of Mathematica or Matlab.
44 system, in an environment similar to that of Mathematica or Matlab.
45
45
46 New top-level global objects
46 New top-level global objects
47 ----------------------------
47 ----------------------------
48
48
49 Please see their respective docstrings for further details.
49 Please see their respective docstrings for further details.
50
50
51 - gp: a running Gnuplot instance. You can access its methods as
51 - gp: a running Gnuplot instance. You can access its methods as
52 gp.<method>. gp(`a string`) will execute the given string as if it had been
52 gp.<method>. gp(`a string`) will execute the given string as if it had been
53 typed in an interactive gnuplot window.
53 typed in an interactive gnuplot window.
54
54
55 - plot, splot, replot and hardcopy: aliases to the methods of the same name in
55 - plot, splot, replot and hardcopy: aliases to the methods of the same name in
56 the global running Gnuplot instance gp. These allow you to simply type:
56 the global running Gnuplot instance gp. These allow you to simply type:
57
57
58 In [1]: plot(x,sin(x),title='Sin(x)') # assuming x is a Numeric array
58 In [1]: plot(x,sin(x),title='Sin(x)') # assuming x is a Numeric array
59
59
60 and obtain a plot of sin(x) vs x with the title 'Sin(x)'.
60 and obtain a plot of sin(x) vs x with the title 'Sin(x)'.
61
61
62 - gp_new: a function which returns a new Gnuplot instance. This can be used to
62 - gp_new: a function which returns a new Gnuplot instance. This can be used to
63 have multiple Gnuplot instances running in your session to compare different
63 have multiple Gnuplot instances running in your session to compare different
64 plots, each in a separate window.
64 plots, each in a separate window.
65
65
66 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
66 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
67 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
67 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
68 functions with improved versions (Gnuplot2 comes with IPython).
68 functions with improved versions (Gnuplot2 comes with IPython).
69
69
70 - gpdata, gpfile, gpstring, gpfunc, gpgrid: aliases to Gnuplot.Data,
70 - gpdata, gpfile, gpstring, gpfunc, gpgrid: aliases to Gnuplot.Data,
71 Gnuplot.File, Gnuplot.String, Gnuplot.Func and Gnuplot.GridData
71 Gnuplot.File, Gnuplot.String, Gnuplot.Func and Gnuplot.GridData
72 respectively. These functions create objects which can then be passed to the
72 respectively. These functions create objects which can then be passed to the
73 plotting commands. See the Gnuplot.py documentation for details.
73 plotting commands. See the Gnuplot.py documentation for details.
74
74
75 Keep in mind that all commands passed to a Gnuplot instance are executed in
75 Keep in mind that all commands passed to a Gnuplot instance are executed in
76 the Gnuplot namespace, where no Python variables exist. For example, for
76 the Gnuplot namespace, where no Python variables exist. For example, for
77 plotting sin(x) vs x as above, typing
77 plotting sin(x) vs x as above, typing
78
78
79 In [2]: gp('plot x,sin(x)')
79 In [2]: gp('plot x,sin(x)')
80
80
81 would not work. Instead, you would get the plot of BOTH the functions 'x' and
81 would not work. Instead, you would get the plot of BOTH the functions 'x' and
82 'sin(x)', since Gnuplot doesn't know about the 'x' Python array. The plot()
82 'sin(x)', since Gnuplot doesn't know about the 'x' Python array. The plot()
83 method lives in python and does know about these variables.
83 method lives in python and does know about these variables.
84
84
85
85
86 New magic functions
86 New magic functions
87 -------------------
87 -------------------
88
88
89 %gpc: pass one command to Gnuplot and execute it or open a Gnuplot shell where
89 %gpc: pass one command to Gnuplot and execute it or open a Gnuplot shell where
90 each line of input is executed.
90 each line of input is executed.
91
91
92 %gp_set_default: reset the value of IPython's global Gnuplot instance.""")
92 %gp_set_default: reset the value of IPython's global Gnuplot instance.""")
93
93
94 # Code below is all for IPython use
94 # Code below is all for IPython use
95 # Define the magic functions for communicating with the above gnuplot instance.
95 # Define the magic functions for communicating with the above gnuplot instance.
96 def magic_gpc(self,parameter_s=''):
96 def magic_gpc(self,parameter_s=''):
97 """Execute a gnuplot command or open a gnuplot shell.
97 """Execute a gnuplot command or open a gnuplot shell.
98
98
99 Usage (omit the % if automagic is on). There are two ways to use it:
99 Usage (omit the % if automagic is on). There are two ways to use it:
100
100
101 1) %gpc 'command' -> passes 'command' directly to the gnuplot instance.
101 1) %gpc 'command' -> passes 'command' directly to the gnuplot instance.
102
102
103 2) %gpc -> will open up a prompt (gnuplot>>>) which takes input like the
103 2) %gpc -> will open up a prompt (gnuplot>>>) which takes input like the
104 standard gnuplot interactive prompt. If you need to type a multi-line
104 standard gnuplot interactive prompt. If you need to type a multi-line
105 command, use \\ at the end of each intermediate line.
105 command, use \\ at the end of each intermediate line.
106
106
107 Upon exiting of the gnuplot sub-shell, you return to your IPython
107 Upon exiting of the gnuplot sub-shell, you return to your IPython
108 session (the gnuplot sub-shell can be invoked as many times as needed).
108 session (the gnuplot sub-shell can be invoked as many times as needed).
109 """
109 """
110
110
111 if parameter_s.strip():
111 if parameter_s.strip():
112 self.shell.gnuplot(parameter_s)
112 self.shell.gnuplot(parameter_s)
113 else:
113 else:
114 self.shell.gnuplot.interact()
114 self.shell.gnuplot.interact()
115
115
116 def magic_gp_set_default(self,parameter_s=''):
116 def magic_gp_set_default(self,parameter_s=''):
117 """Set the default gnuplot instance accessed by the %gp magic function.
117 """Set the default gnuplot instance accessed by the %gp magic function.
118
118
119 %gp_set_default name
119 %gp_set_default name
120
120
121 Call with the name of the new instance at the command line. If you want to
121 Call with the name of the new instance at the command line. If you want to
122 set this instance in your own code (using an embedded IPython, for
122 set this instance in your own code (using an embedded IPython, for
123 example), simply set the variable __IPYTHON__.gnuplot to your own gnuplot
123 example), simply set the variable __IPYTHON__.gnuplot to your own gnuplot
124 instance object."""
124 instance object."""
125
125
126 gname = parameter_s.strip()
126 gname = parameter_s.strip()
127 G = eval(gname,self.shell.user_ns)
127 G = eval(gname,self.shell.user_ns)
128 self.shell.gnuplot = G
128 self.shell.gnuplot = G
129 self.shell.user_ns.update({'plot':G.plot,'splot':G.splot,'plot2':G.plot2,
129 self.shell.user_ns.update({'plot':G.plot,'splot':G.splot,'plot2':G.plot2,
130 'replot':G.replot,'hardcopy':G.hardcopy})
130 'replot':G.replot,'hardcopy':G.hardcopy})
131
131
132 try:
132 try:
133 __IPYTHON__
133 __IPYTHON__
134 except NameError:
134 except NameError:
135 pass
135 pass
136 else:
136 else:
137 # make the global Gnuplot instance known to IPython
137 # make the global Gnuplot instance known to IPython
138 __IPYTHON__.gnuplot = GRun.gp
138 __IPYTHON__.gnuplot = GRun.gp
139 __IPYTHON__.gnuplot.shell_first_time = 1
139 __IPYTHON__.gnuplot.shell_first_time = 1
140
140
141 print """*** Type `gphelp` for help on the Gnuplot integration features."""
141 print """*** Type `gphelp` for help on the Gnuplot integration features."""
142
142
143 # Add the new magic functions to the class dict
143 # Add the new magic functions to the class dict
144 from IPython.iplib import InteractiveShell
144 from IPython.iplib import InteractiveShell
145 InteractiveShell.magic_gpc = magic_gpc
145 InteractiveShell.magic_gpc = magic_gpc
146 InteractiveShell.magic_gp_set_default = magic_gp_set_default
146 InteractiveShell.magic_gp_set_default = magic_gp_set_default
147
147
148 #********************** End of file <GnuplotInteractive.py> *******************
148 #********************** End of file <GnuplotInteractive.py> *******************
@@ -1,147 +1,147 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Basic Gnuplot functionality for inclusion in other code.
2 """Basic Gnuplot functionality for inclusion in other code.
3
3
4 This module creates a running Gnuplot instance called 'gp' and builds other
4 This module creates a running Gnuplot instance called 'gp' and builds other
5 convenient globals for quick use in running scripts. It is intended to allow
5 convenient globals for quick use in running scripts. It is intended to allow
6 you to script plotting tasks in Python with a minimum of effort. A typical
6 you to script plotting tasks in Python with a minimum of effort. A typical
7 usage would be:
7 usage would be:
8
8
9 import IPython.GnuplotRuntime as GP # or some other short name
9 import IPython.GnuplotRuntime as GP # or some other short name
10 GP.gp.plot(GP.File('your_data.dat'))
10 GP.gp.plot(GP.File('your_data.dat'))
11
11
12
12
13 This module exposes the following objects:
13 This module exposes the following objects:
14
14
15 - gp: a running Gnuplot instance. You can access its methods as
15 - gp: a running Gnuplot instance. You can access its methods as
16 gp.<method>. gp(`a string`) will execute the given string as if it had been
16 gp.<method>. gp(`a string`) will execute the given string as if it had been
17 typed in an interactive gnuplot window.
17 typed in an interactive gnuplot window.
18
18
19 - gp_new: a function which returns a new Gnuplot instance. This can be used to
19 - gp_new: a function which returns a new Gnuplot instance. This can be used to
20 have multiple Gnuplot instances running in your session to compare different
20 have multiple Gnuplot instances running in your session to compare different
21 plots.
21 plots.
22
22
23 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
23 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
24 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
24 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
25 functions with improved versions (Gnuplot2 comes with IPython).
25 functions with improved versions (Gnuplot2 comes with IPython).
26
26
27 - Data: alias to Gnuplot.Data, makes a PlotItem from array data.
27 - Data: alias to Gnuplot.Data, makes a PlotItem from array data.
28
28
29 - File: alias to Gnuplot.File, makes a PlotItem from a file.
29 - File: alias to Gnuplot.File, makes a PlotItem from a file.
30
30
31 - String: alias to Gnuplot.String, makes a PlotItem from a string formatted
31 - String: alias to Gnuplot.String, makes a PlotItem from a string formatted
32 exactly like a file for Gnuplot.File would be.
32 exactly like a file for Gnuplot.File would be.
33
33
34 - Func: alias to Gnuplot.Func, makes a PlotItem from a function string.
34 - Func: alias to Gnuplot.Func, makes a PlotItem from a function string.
35
35
36 - GridData: alias to Gnuplot.GridData, makes a PlotItem from grid data.
36 - GridData: alias to Gnuplot.GridData, makes a PlotItem from grid data.
37
37
38 - pm3d_config: a string with Gnuplot commands to set up the pm3d mode for
38 - pm3d_config: a string with Gnuplot commands to set up the pm3d mode for
39 surface plotting. You can activate it simply by calling gp(pm3d_config).
39 surface plotting. You can activate it simply by calling gp(pm3d_config).
40
40
41 - eps_fix_bbox: A Unix-only function to fix eps files with bad bounding boxes
41 - eps_fix_bbox: A Unix-only function to fix eps files with bad bounding boxes
42 (which Gnuplot generates when the plot size is set to square).
42 (which Gnuplot generates when the plot size is set to square).
43
43
44 This requires the Gnuplot.py module for interfacing Python with Gnuplot, which
44 This requires the Gnuplot.py module for interfacing Python with Gnuplot, which
45 can be downloaded from:
45 can be downloaded from:
46
46
47 http://gnuplot-py.sourceforge.net/
47 http://gnuplot-py.sourceforge.net/
48
48
49 Inspired by a suggestion/request from Arnd Baecker.
49 Inspired by a suggestion/request from Arnd Baecker.
50
50
51 $Id: GnuplotRuntime.py 389 2004-10-09 07:59:30Z fperez $"""
51 $Id: GnuplotRuntime.py 389 2004-10-09 07:59:30Z fperez $"""
52
52
53 __all__ = ['Gnuplot','gp','gp_new','Data','File','Func','GridData',
53 __all__ = ['Gnuplot','gp','gp_new','Data','File','Func','GridData',
54 'pm3d_config','eps_fix_bbox']
54 'pm3d_config','eps_fix_bbox']
55
55
56 import os,tempfile,sys
56 import os,tempfile,sys
57 from IPython.genutils import getoutput
57 from IPython.genutils import getoutput
58
58
59 #---------------------------------------------------------------------------
59 #---------------------------------------------------------------------------
60 # Notes on mouse support for Gnuplot.py
60 # Notes on mouse support for Gnuplot.py
61
61
62 # If you do not have a mouse-enabled gnuplot, set gnuplot_mouse to 0. If you
62 # If you do not have a mouse-enabled gnuplot, set gnuplot_mouse to 0. If you
63 # use gnuplot, you should really grab a recent, mouse enabled copy. It is an
63 # use gnuplot, you should really grab a recent, mouse enabled copy. It is an
64 # extremely useful feature. Mouse support is official as of gnuplot 4.0,
64 # extremely useful feature. Mouse support is official as of gnuplot 4.0,
65 # released in April 2004.
65 # released in April 2004.
66
66
67 # For the mouse features to work correctly, you MUST set your Gnuplot.py
67 # For the mouse features to work correctly, you MUST set your Gnuplot.py
68 # module to use temporary files instead of 'inline data' for data
68 # module to use temporary files instead of 'inline data' for data
69 # communication. Note that this is the default, so unless you've manually
69 # communication. Note that this is the default, so unless you've manually
70 # fiddled with it you should be ok. If you need to make changes, in the
70 # fiddled with it you should be ok. If you need to make changes, in the
71 # Gnuplot module directory, loook for the gp_unix.py file and make sure the
71 # Gnuplot module directory, loook for the gp_unix.py file and make sure the
72 # prefer_inline_data variable is set to 0. If you set it to 1 Gnuplot.py will
72 # prefer_inline_data variable is set to 0. If you set it to 1 Gnuplot.py will
73 # try to pass the data to gnuplot via standard input, which completely
73 # try to pass the data to gnuplot via standard input, which completely
74 # confuses the mouse control system (even though it may be a bit faster than
74 # confuses the mouse control system (even though it may be a bit faster than
75 # using temp files).
75 # using temp files).
76
76
77 # As of Gnuplot.py v1.7, a new option was added to use FIFOs (pipes). This
77 # As of Gnuplot.py v1.7, a new option was added to use FIFOs (pipes). This
78 # mechanism, while fast, also breaks the mouse system. You must therefore set
78 # mechanism, while fast, also breaks the mouse system. You must therefore set
79 # the variable prefer_fifo_data to 0 in gp_unix.py.
79 # the variable prefer_fifo_data to 0 in gp_unix.py.
80
80
81 tmpname = tempfile.mktemp()
81 tmpname = tempfile.mktemp()
82 open(tmpname,'w').write('set mouse')
82 open(tmpname,'w').write('set mouse')
83 gnu_out = getoutput('gnuplot '+ tmpname)
83 gnu_out = getoutput('gnuplot '+ tmpname)
84 os.unlink(tmpname)
84 os.unlink(tmpname)
85 if gnu_out: # Gnuplot won't print anything if it has mouse support
85 if gnu_out: # Gnuplot won't print anything if it has mouse support
86 print "*** Your version of Gnuplot appears not to have mouse support."
86 print "*** Your version of Gnuplot appears not to have mouse support."
87 gnuplot_mouse = 0
87 gnuplot_mouse = 0
88 else:
88 else:
89 gnuplot_mouse = 1
89 gnuplot_mouse = 1
90 del tmpname,gnu_out
90 del tmpname,gnu_out
91
91
92 # Default state for persistence of new gnuplot instances
92 # Default state for persistence of new gnuplot instances
93 if os.name in ['nt','dos'] or sys.platform == 'cygwin':
93 if os.name in ['nt','dos'] or sys.platform == 'cygwin':
94 gnuplot_persist = 0
94 gnuplot_persist = 0
95 else:
95 else:
96 gnuplot_persist = 1
96 gnuplot_persist = 1
97
97
98 import IPython.Gnuplot2 as Gnuplot
98 import IPython.Gnuplot2 as Gnuplot
99
99
100 class NotGiven: pass
100 class NotGiven: pass
101
101
102 def gp_new(mouse=NotGiven,persist=NotGiven):
102 def gp_new(mouse=NotGiven,persist=NotGiven):
103 """Return a new Gnuplot instance.
103 """Return a new Gnuplot instance.
104
104
105 The instance returned uses the improved methods defined in Gnuplot2.
105 The instance returned uses the improved methods defined in Gnuplot2.
106
106
107 Options (boolean):
107 Options (boolean):
108
108
109 - mouse: if unspecified, the module global gnuplot_mouse is used.
109 - mouse: if unspecified, the module global gnuplot_mouse is used.
110
110
111 - persist: if unspecified, the module global gnuplot_persist is used."""
111 - persist: if unspecified, the module global gnuplot_persist is used."""
112
112
113 if mouse is NotGiven:
113 if mouse is NotGiven:
114 mouse = gnuplot_mouse
114 mouse = gnuplot_mouse
115 if persist is NotGiven:
115 if persist is NotGiven:
116 persist = gnuplot_persist
116 persist = gnuplot_persist
117 g = Gnuplot.Gnuplot(persist=persist)
117 g = Gnuplot.Gnuplot(persist=persist)
118 if mouse:
118 if mouse:
119 g('set mouse')
119 g('set mouse')
120 return g
120 return g
121
121
122 # Global-level names.
122 # Global-level names.
123
123
124 # A global Gnuplot instance for interactive use:
124 # A global Gnuplot instance for interactive use:
125 gp = gp_new()
125 gp = gp_new()
126
126
127 # Accessors for the main plot object constructors:
127 # Accessors for the main plot object constructors:
128 Data = Gnuplot.Data
128 Data = Gnuplot.Data
129 File = Gnuplot.File
129 File = Gnuplot.File
130 Func = Gnuplot.Func
130 Func = Gnuplot.Func
131 String = Gnuplot.String
131 String = Gnuplot.String
132 GridData = Gnuplot.GridData
132 GridData = Gnuplot.GridData
133
133
134 # A Unix-only function to fix eps files with bad bounding boxes (which Gnuplot
134 # A Unix-only function to fix eps files with bad bounding boxes (which Gnuplot
135 # generates when the plot size is set to square):
135 # generates when the plot size is set to square):
136 eps_fix_bbox = Gnuplot.eps_fix_bbox
136 eps_fix_bbox = Gnuplot.eps_fix_bbox
137
137
138 # String for configuring pm3d. Simply call g(pm3d_config) to execute it. pm3d
138 # String for configuring pm3d. Simply call g(pm3d_config) to execute it. pm3d
139 # is a very nice mode for plotting colormaps on surfaces. Modify the defaults
139 # is a very nice mode for plotting colormaps on surfaces. Modify the defaults
140 # below to suit your taste.
140 # below to suit your taste.
141 pm3d_config = """
141 pm3d_config = """
142 set pm3d solid
142 set pm3d solid
143 set hidden3d
143 set hidden3d
144 unset surface
144 unset surface
145 set isosamples 50
145 set isosamples 50
146 """
146 """
147 #******************** End of file <GnuplotRuntime.py> ******************
147 #******************** End of file <GnuplotRuntime.py> ******************
This diff has been collapsed as it changes many lines, (568 lines changed) Show them Hide them
@@ -1,284 +1,284 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
2 """String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
3
3
4 This module lets you quickly and conveniently interpolate values into
4 This module lets you quickly and conveniently interpolate values into
5 strings (in the flavour of Perl or Tcl, but with less extraneous
5 strings (in the flavour of Perl or Tcl, but with less extraneous
6 punctuation). You get a bit more power than in the other languages,
6 punctuation). You get a bit more power than in the other languages,
7 because this module allows subscripting, slicing, function calls,
7 because this module allows subscripting, slicing, function calls,
8 attribute lookup, or arbitrary expressions. Variables and expressions
8 attribute lookup, or arbitrary expressions. Variables and expressions
9 are evaluated in the namespace of the caller.
9 are evaluated in the namespace of the caller.
10
10
11 The itpl() function returns the result of interpolating a string, and
11 The itpl() function returns the result of interpolating a string, and
12 printpl() prints out an interpolated string. Here are some examples:
12 printpl() prints out an interpolated string. Here are some examples:
13
13
14 from Itpl import printpl
14 from Itpl import printpl
15 printpl("Here is a $string.")
15 printpl("Here is a $string.")
16 printpl("Here is a $module.member.")
16 printpl("Here is a $module.member.")
17 printpl("Here is an $object.member.")
17 printpl("Here is an $object.member.")
18 printpl("Here is a $functioncall(with, arguments).")
18 printpl("Here is a $functioncall(with, arguments).")
19 printpl("Here is an ${arbitrary + expression}.")
19 printpl("Here is an ${arbitrary + expression}.")
20 printpl("Here is an $array[3] member.")
20 printpl("Here is an $array[3] member.")
21 printpl("Here is a $dictionary['member'].")
21 printpl("Here is a $dictionary['member'].")
22
22
23 The filter() function filters a file object so that output through it
23 The filter() function filters a file object so that output through it
24 is interpolated. This lets you produce the illusion that Python knows
24 is interpolated. This lets you produce the illusion that Python knows
25 how to do interpolation:
25 how to do interpolation:
26
26
27 import Itpl
27 import Itpl
28 sys.stdout = Itpl.filter()
28 sys.stdout = Itpl.filter()
29 f = "fancy"
29 f = "fancy"
30 print "Isn't this $f?"
30 print "Isn't this $f?"
31 print "Standard output has been replaced with a $sys.stdout object."
31 print "Standard output has been replaced with a $sys.stdout object."
32 sys.stdout = Itpl.unfilter()
32 sys.stdout = Itpl.unfilter()
33 print "Okay, back $to $normal."
33 print "Okay, back $to $normal."
34
34
35 Under the hood, the Itpl class represents a string that knows how to
35 Under the hood, the Itpl class represents a string that knows how to
36 interpolate values. An instance of the class parses the string once
36 interpolate values. An instance of the class parses the string once
37 upon initialization; the evaluation and substitution can then be done
37 upon initialization; the evaluation and substitution can then be done
38 each time the instance is evaluated with str(instance). For example:
38 each time the instance is evaluated with str(instance). For example:
39
39
40 from Itpl import Itpl
40 from Itpl import Itpl
41 s = Itpl("Here is $foo.")
41 s = Itpl("Here is $foo.")
42 foo = 5
42 foo = 5
43 print str(s)
43 print str(s)
44 foo = "bar"
44 foo = "bar"
45 print str(s)
45 print str(s)
46
46
47 $Id: Itpl.py 2918 2007-12-31 14:34:47Z vivainio $
47 $Id: Itpl.py 2918 2007-12-31 14:34:47Z vivainio $
48 """ # ' -> close an open quote for stupid emacs
48 """ # ' -> close an open quote for stupid emacs
49
49
50 #*****************************************************************************
50 #*****************************************************************************
51 #
51 #
52 # Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
52 # Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
53 #
53 #
54 #
54 #
55 # Published under the terms of the MIT license, hereby reproduced:
55 # Published under the terms of the MIT license, hereby reproduced:
56 #
56 #
57 # Permission is hereby granted, free of charge, to any person obtaining a copy
57 # Permission is hereby granted, free of charge, to any person obtaining a copy
58 # of this software and associated documentation files (the "Software"), to
58 # of this software and associated documentation files (the "Software"), to
59 # deal in the Software without restriction, including without limitation the
59 # deal in the Software without restriction, including without limitation the
60 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
60 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
61 # sell copies of the Software, and to permit persons to whom the Software is
61 # sell copies of the Software, and to permit persons to whom the Software is
62 # furnished to do so, subject to the following conditions:
62 # furnished to do so, subject to the following conditions:
63 #
63 #
64 # The above copyright notice and this permission notice shall be included in
64 # The above copyright notice and this permission notice shall be included in
65 # all copies or substantial portions of the Software.
65 # all copies or substantial portions of the Software.
66 #
66 #
67 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
71 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
72 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
72 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
73 # IN THE SOFTWARE.
73 # IN THE SOFTWARE.
74 #
74 #
75 #*****************************************************************************
75 #*****************************************************************************
76
76
77 __author__ = 'Ka-Ping Yee <ping@lfw.org>'
77 __author__ = 'Ka-Ping Yee <ping@lfw.org>'
78 __license__ = 'MIT'
78 __license__ = 'MIT'
79
79
80 import string
80 import string
81 import sys
81 import sys
82 from tokenize import tokenprog
82 from tokenize import tokenprog
83 from types import StringType
83 from types import StringType
84
84
85 class ItplError(ValueError):
85 class ItplError(ValueError):
86 def __init__(self, text, pos):
86 def __init__(self, text, pos):
87 self.text = text
87 self.text = text
88 self.pos = pos
88 self.pos = pos
89 def __str__(self):
89 def __str__(self):
90 return "unfinished expression in %s at char %d" % (
90 return "unfinished expression in %s at char %d" % (
91 repr(self.text), self.pos)
91 repr(self.text), self.pos)
92
92
93 def matchorfail(text, pos):
93 def matchorfail(text, pos):
94 match = tokenprog.match(text, pos)
94 match = tokenprog.match(text, pos)
95 if match is None:
95 if match is None:
96 raise ItplError(text, pos)
96 raise ItplError(text, pos)
97 return match, match.end()
97 return match, match.end()
98
98
99 class Itpl:
99 class Itpl:
100 """Class representing a string with interpolation abilities.
100 """Class representing a string with interpolation abilities.
101
101
102 Upon creation, an instance works out what parts of the format
102 Upon creation, an instance works out what parts of the format
103 string are literal and what parts need to be evaluated. The
103 string are literal and what parts need to be evaluated. The
104 evaluation and substitution happens in the namespace of the
104 evaluation and substitution happens in the namespace of the
105 caller when str(instance) is called."""
105 caller when str(instance) is called."""
106
106
107 def __init__(self, format,codec=sys.stdin.encoding,encoding_errors='backslashreplace'):
107 def __init__(self, format,codec=sys.stdin.encoding,encoding_errors='backslashreplace'):
108 """The single mandatory argument to this constructor is a format
108 """The single mandatory argument to this constructor is a format
109 string.
109 string.
110
110
111 The format string is parsed according to the following rules:
111 The format string is parsed according to the following rules:
112
112
113 1. A dollar sign and a name, possibly followed by any of:
113 1. A dollar sign and a name, possibly followed by any of:
114 - an open-paren, and anything up to the matching paren
114 - an open-paren, and anything up to the matching paren
115 - an open-bracket, and anything up to the matching bracket
115 - an open-bracket, and anything up to the matching bracket
116 - a period and a name
116 - a period and a name
117 any number of times, is evaluated as a Python expression.
117 any number of times, is evaluated as a Python expression.
118
118
119 2. A dollar sign immediately followed by an open-brace, and
119 2. A dollar sign immediately followed by an open-brace, and
120 anything up to the matching close-brace, is evaluated as
120 anything up to the matching close-brace, is evaluated as
121 a Python expression.
121 a Python expression.
122
122
123 3. Outside of the expressions described in the above two rules,
123 3. Outside of the expressions described in the above two rules,
124 two dollar signs in a row give you one literal dollar sign.
124 two dollar signs in a row give you one literal dollar sign.
125
125
126 Optional arguments:
126 Optional arguments:
127
127
128 - codec('utf_8'): a string containing the name of a valid Python
128 - codec('utf_8'): a string containing the name of a valid Python
129 codec.
129 codec.
130
130
131 - encoding_errors('backslashreplace'): a string with a valid error handling
131 - encoding_errors('backslashreplace'): a string with a valid error handling
132 policy. See the codecs module documentation for details.
132 policy. See the codecs module documentation for details.
133
133
134 These are used to encode the format string if a call to str() fails on
134 These are used to encode the format string if a call to str() fails on
135 the expanded result."""
135 the expanded result."""
136
136
137 if not isinstance(format,basestring):
137 if not isinstance(format,basestring):
138 raise TypeError, "needs string initializer"
138 raise TypeError, "needs string initializer"
139 self.format = format
139 self.format = format
140 self.codec = codec
140 self.codec = codec
141 self.encoding_errors = encoding_errors
141 self.encoding_errors = encoding_errors
142
142
143 namechars = "abcdefghijklmnopqrstuvwxyz" \
143 namechars = "abcdefghijklmnopqrstuvwxyz" \
144 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
144 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
145 chunks = []
145 chunks = []
146 pos = 0
146 pos = 0
147
147
148 while 1:
148 while 1:
149 dollar = string.find(format, "$", pos)
149 dollar = string.find(format, "$", pos)
150 if dollar < 0: break
150 if dollar < 0: break
151 nextchar = format[dollar+1]
151 nextchar = format[dollar+1]
152
152
153 if nextchar == "{":
153 if nextchar == "{":
154 chunks.append((0, format[pos:dollar]))
154 chunks.append((0, format[pos:dollar]))
155 pos, level = dollar+2, 1
155 pos, level = dollar+2, 1
156 while level:
156 while level:
157 match, pos = matchorfail(format, pos)
157 match, pos = matchorfail(format, pos)
158 tstart, tend = match.regs[3]
158 tstart, tend = match.regs[3]
159 token = format[tstart:tend]
159 token = format[tstart:tend]
160 if token == "{": level = level+1
160 if token == "{": level = level+1
161 elif token == "}": level = level-1
161 elif token == "}": level = level-1
162 chunks.append((1, format[dollar+2:pos-1]))
162 chunks.append((1, format[dollar+2:pos-1]))
163
163
164 elif nextchar in namechars:
164 elif nextchar in namechars:
165 chunks.append((0, format[pos:dollar]))
165 chunks.append((0, format[pos:dollar]))
166 match, pos = matchorfail(format, dollar+1)
166 match, pos = matchorfail(format, dollar+1)
167 while pos < len(format):
167 while pos < len(format):
168 if format[pos] == "." and \
168 if format[pos] == "." and \
169 pos+1 < len(format) and format[pos+1] in namechars:
169 pos+1 < len(format) and format[pos+1] in namechars:
170 match, pos = matchorfail(format, pos+1)
170 match, pos = matchorfail(format, pos+1)
171 elif format[pos] in "([":
171 elif format[pos] in "([":
172 pos, level = pos+1, 1
172 pos, level = pos+1, 1
173 while level:
173 while level:
174 match, pos = matchorfail(format, pos)
174 match, pos = matchorfail(format, pos)
175 tstart, tend = match.regs[3]
175 tstart, tend = match.regs[3]
176 token = format[tstart:tend]
176 token = format[tstart:tend]
177 if token[0] in "([": level = level+1
177 if token[0] in "([": level = level+1
178 elif token[0] in ")]": level = level-1
178 elif token[0] in ")]": level = level-1
179 else: break
179 else: break
180 chunks.append((1, format[dollar+1:pos]))
180 chunks.append((1, format[dollar+1:pos]))
181
181
182 else:
182 else:
183 chunks.append((0, format[pos:dollar+1]))
183 chunks.append((0, format[pos:dollar+1]))
184 pos = dollar + 1 + (nextchar == "$")
184 pos = dollar + 1 + (nextchar == "$")
185
185
186 if pos < len(format): chunks.append((0, format[pos:]))
186 if pos < len(format): chunks.append((0, format[pos:]))
187 self.chunks = chunks
187 self.chunks = chunks
188
188
189 def __repr__(self):
189 def __repr__(self):
190 return "<Itpl %s >" % repr(self.format)
190 return "<Itpl %s >" % repr(self.format)
191
191
192 def _str(self,glob,loc):
192 def _str(self,glob,loc):
193 """Evaluate to a string in the given globals/locals.
193 """Evaluate to a string in the given globals/locals.
194
194
195 The final output is built by calling str(), but if this fails, the
195 The final output is built by calling str(), but if this fails, the
196 result is encoded with the instance's codec and error handling policy,
196 result is encoded with the instance's codec and error handling policy,
197 via a call to out.encode(self.codec,self.encoding_errors)"""
197 via a call to out.encode(self.codec,self.encoding_errors)"""
198 result = []
198 result = []
199 app = result.append
199 app = result.append
200 for live, chunk in self.chunks:
200 for live, chunk in self.chunks:
201 if live:
201 if live:
202 val = eval(chunk,glob,loc)
202 val = eval(chunk,glob,loc)
203 try:
203 try:
204 app(str(val))
204 app(str(val))
205 except UnicodeEncodeError:
205 except UnicodeEncodeError:
206 app(unicode(val))
206 app(unicode(val))
207
207
208 else: app(chunk)
208 else: app(chunk)
209 out = ''.join(result)
209 out = ''.join(result)
210 try:
210 try:
211 return str(out)
211 return str(out)
212 except UnicodeError:
212 except UnicodeError:
213 return out.encode(self.codec,self.encoding_errors)
213 return out.encode(self.codec,self.encoding_errors)
214
214
215 def __str__(self):
215 def __str__(self):
216 """Evaluate and substitute the appropriate parts of the string."""
216 """Evaluate and substitute the appropriate parts of the string."""
217
217
218 # We need to skip enough frames to get to the actual caller outside of
218 # We need to skip enough frames to get to the actual caller outside of
219 # Itpl.
219 # Itpl.
220 frame = sys._getframe(1)
220 frame = sys._getframe(1)
221 while frame.f_globals["__name__"] == __name__: frame = frame.f_back
221 while frame.f_globals["__name__"] == __name__: frame = frame.f_back
222 loc, glob = frame.f_locals, frame.f_globals
222 loc, glob = frame.f_locals, frame.f_globals
223
223
224 return self._str(glob,loc)
224 return self._str(glob,loc)
225
225
226 class ItplNS(Itpl):
226 class ItplNS(Itpl):
227 """Class representing a string with interpolation abilities.
227 """Class representing a string with interpolation abilities.
228
228
229 This inherits from Itpl, but at creation time a namespace is provided
229 This inherits from Itpl, but at creation time a namespace is provided
230 where the evaluation will occur. The interpolation becomes a bit more
230 where the evaluation will occur. The interpolation becomes a bit more
231 efficient, as no traceback needs to be extracte. It also allows the
231 efficient, as no traceback needs to be extracte. It also allows the
232 caller to supply a different namespace for the interpolation to occur than
232 caller to supply a different namespace for the interpolation to occur than
233 its own."""
233 its own."""
234
234
235 def __init__(self, format,globals,locals=None,
235 def __init__(self, format,globals,locals=None,
236 codec='utf_8',encoding_errors='backslashreplace'):
236 codec='utf_8',encoding_errors='backslashreplace'):
237 """ItplNS(format,globals[,locals]) -> interpolating string instance.
237 """ItplNS(format,globals[,locals]) -> interpolating string instance.
238
238
239 This constructor, besides a format string, takes a globals dictionary
239 This constructor, besides a format string, takes a globals dictionary
240 and optionally a locals (which defaults to globals if not provided).
240 and optionally a locals (which defaults to globals if not provided).
241
241
242 For further details, see the Itpl constructor."""
242 For further details, see the Itpl constructor."""
243
243
244 if locals is None:
244 if locals is None:
245 locals = globals
245 locals = globals
246 self.globals = globals
246 self.globals = globals
247 self.locals = locals
247 self.locals = locals
248 Itpl.__init__(self,format,codec,encoding_errors)
248 Itpl.__init__(self,format,codec,encoding_errors)
249
249
250 def __str__(self):
250 def __str__(self):
251 """Evaluate and substitute the appropriate parts of the string."""
251 """Evaluate and substitute the appropriate parts of the string."""
252 return self._str(self.globals,self.locals)
252 return self._str(self.globals,self.locals)
253
253
254 def __repr__(self):
254 def __repr__(self):
255 return "<ItplNS %s >" % repr(self.format)
255 return "<ItplNS %s >" % repr(self.format)
256
256
257 # utilities for fast printing
257 # utilities for fast printing
258 def itpl(text): return str(Itpl(text))
258 def itpl(text): return str(Itpl(text))
259 def printpl(text): print itpl(text)
259 def printpl(text): print itpl(text)
260 # versions with namespace
260 # versions with namespace
261 def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
261 def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
262 def printplns(text,globals,locals=None): print itplns(text,globals,locals)
262 def printplns(text,globals,locals=None): print itplns(text,globals,locals)
263
263
264 class ItplFile:
264 class ItplFile:
265 """A file object that filters each write() through an interpolator."""
265 """A file object that filters each write() through an interpolator."""
266 def __init__(self, file): self.file = file
266 def __init__(self, file): self.file = file
267 def __repr__(self): return "<interpolated " + repr(self.file) + ">"
267 def __repr__(self): return "<interpolated " + repr(self.file) + ">"
268 def __getattr__(self, attr): return getattr(self.file, attr)
268 def __getattr__(self, attr): return getattr(self.file, attr)
269 def write(self, text): self.file.write(str(Itpl(text)))
269 def write(self, text): self.file.write(str(Itpl(text)))
270
270
271 def filter(file=sys.stdout):
271 def filter(file=sys.stdout):
272 """Return an ItplFile that filters writes to the given file object.
272 """Return an ItplFile that filters writes to the given file object.
273
273
274 'file = filter(file)' replaces 'file' with a filtered object that
274 'file = filter(file)' replaces 'file' with a filtered object that
275 has a write() method. When called with no argument, this creates
275 has a write() method. When called with no argument, this creates
276 a filter to sys.stdout."""
276 a filter to sys.stdout."""
277 return ItplFile(file)
277 return ItplFile(file)
278
278
279 def unfilter(ifile=None):
279 def unfilter(ifile=None):
280 """Return the original file that corresponds to the given ItplFile.
280 """Return the original file that corresponds to the given ItplFile.
281
281
282 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
282 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
283 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
283 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
284 return ifile and ifile.file or sys.stdout.file
284 return ifile and ifile.file or sys.stdout.file
This diff has been collapsed as it changes many lines, (540 lines changed) Show them Hide them
@@ -1,270 +1,270 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Logger class for IPython's logging facilities.
3 Logger class for IPython's logging facilities.
4
4
5 $Id: Logger.py 2875 2007-11-26 08:37:39Z fperez $
5 $Id: Logger.py 2875 2007-11-26 08:37:39Z fperez $
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
9 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
10 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
10 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #*****************************************************************************
14 #*****************************************************************************
15
15
16 #****************************************************************************
16 #****************************************************************************
17 # Modules and globals
17 # Modules and globals
18
18
19 from IPython import Release
19 from IPython import Release
20 __author__ = '%s <%s>\n%s <%s>' % \
20 __author__ = '%s <%s>\n%s <%s>' % \
21 ( Release.authors['Janko'] + Release.authors['Fernando'] )
21 ( Release.authors['Janko'] + Release.authors['Fernando'] )
22 __license__ = Release.license
22 __license__ = Release.license
23
23
24 # Python standard modules
24 # Python standard modules
25 import glob
25 import glob
26 import os
26 import os
27 import time
27 import time
28
28
29 #****************************************************************************
29 #****************************************************************************
30 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
30 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
31 # ipython and does input cache management. Finish cleanup later...
31 # ipython and does input cache management. Finish cleanup later...
32
32
33 class Logger(object):
33 class Logger(object):
34 """A Logfile class with different policies for file creation"""
34 """A Logfile class with different policies for file creation"""
35
35
36 def __init__(self,shell,logfname='Logger.log',loghead='',logmode='over'):
36 def __init__(self,shell,logfname='Logger.log',loghead='',logmode='over'):
37
37
38 self._i00,self._i,self._ii,self._iii = '','','',''
38 self._i00,self._i,self._ii,self._iii = '','','',''
39
39
40 # this is the full ipython instance, we need some attributes from it
40 # this is the full ipython instance, we need some attributes from it
41 # which won't exist until later. What a mess, clean up later...
41 # which won't exist until later. What a mess, clean up later...
42 self.shell = shell
42 self.shell = shell
43
43
44 self.logfname = logfname
44 self.logfname = logfname
45 self.loghead = loghead
45 self.loghead = loghead
46 self.logmode = logmode
46 self.logmode = logmode
47 self.logfile = None
47 self.logfile = None
48
48
49 # Whether to log raw or processed input
49 # Whether to log raw or processed input
50 self.log_raw_input = False
50 self.log_raw_input = False
51
51
52 # whether to also log output
52 # whether to also log output
53 self.log_output = False
53 self.log_output = False
54
54
55 # whether to put timestamps before each log entry
55 # whether to put timestamps before each log entry
56 self.timestamp = False
56 self.timestamp = False
57
57
58 # activity control flags
58 # activity control flags
59 self.log_active = False
59 self.log_active = False
60
60
61 # logmode is a validated property
61 # logmode is a validated property
62 def _set_mode(self,mode):
62 def _set_mode(self,mode):
63 if mode not in ['append','backup','global','over','rotate']:
63 if mode not in ['append','backup','global','over','rotate']:
64 raise ValueError,'invalid log mode %s given' % mode
64 raise ValueError,'invalid log mode %s given' % mode
65 self._logmode = mode
65 self._logmode = mode
66
66
67 def _get_mode(self):
67 def _get_mode(self):
68 return self._logmode
68 return self._logmode
69
69
70 logmode = property(_get_mode,_set_mode)
70 logmode = property(_get_mode,_set_mode)
71
71
72 def logstart(self,logfname=None,loghead=None,logmode=None,
72 def logstart(self,logfname=None,loghead=None,logmode=None,
73 log_output=False,timestamp=False,log_raw_input=False):
73 log_output=False,timestamp=False,log_raw_input=False):
74 """Generate a new log-file with a default header.
74 """Generate a new log-file with a default header.
75
75
76 Raises RuntimeError if the log has already been started"""
76 Raises RuntimeError if the log has already been started"""
77
77
78 if self.logfile is not None:
78 if self.logfile is not None:
79 raise RuntimeError('Log file is already active: %s' %
79 raise RuntimeError('Log file is already active: %s' %
80 self.logfname)
80 self.logfname)
81
81
82 self.log_active = True
82 self.log_active = True
83
83
84 # The parameters can override constructor defaults
84 # The parameters can override constructor defaults
85 if logfname is not None: self.logfname = logfname
85 if logfname is not None: self.logfname = logfname
86 if loghead is not None: self.loghead = loghead
86 if loghead is not None: self.loghead = loghead
87 if logmode is not None: self.logmode = logmode
87 if logmode is not None: self.logmode = logmode
88
88
89 # Parameters not part of the constructor
89 # Parameters not part of the constructor
90 self.timestamp = timestamp
90 self.timestamp = timestamp
91 self.log_output = log_output
91 self.log_output = log_output
92 self.log_raw_input = log_raw_input
92 self.log_raw_input = log_raw_input
93
93
94 # init depending on the log mode requested
94 # init depending on the log mode requested
95 isfile = os.path.isfile
95 isfile = os.path.isfile
96 logmode = self.logmode
96 logmode = self.logmode
97
97
98 if logmode == 'append':
98 if logmode == 'append':
99 self.logfile = open(self.logfname,'a')
99 self.logfile = open(self.logfname,'a')
100
100
101 elif logmode == 'backup':
101 elif logmode == 'backup':
102 if isfile(self.logfname):
102 if isfile(self.logfname):
103 backup_logname = self.logfname+'~'
103 backup_logname = self.logfname+'~'
104 # Manually remove any old backup, since os.rename may fail
104 # Manually remove any old backup, since os.rename may fail
105 # under Windows.
105 # under Windows.
106 if isfile(backup_logname):
106 if isfile(backup_logname):
107 os.remove(backup_logname)
107 os.remove(backup_logname)
108 os.rename(self.logfname,backup_logname)
108 os.rename(self.logfname,backup_logname)
109 self.logfile = open(self.logfname,'w')
109 self.logfile = open(self.logfname,'w')
110
110
111 elif logmode == 'global':
111 elif logmode == 'global':
112 self.logfname = os.path.join(self.shell.home_dir,self.logfname)
112 self.logfname = os.path.join(self.shell.home_dir,self.logfname)
113 self.logfile = open(self.logfname, 'a')
113 self.logfile = open(self.logfname, 'a')
114
114
115 elif logmode == 'over':
115 elif logmode == 'over':
116 if isfile(self.logfname):
116 if isfile(self.logfname):
117 os.remove(self.logfname)
117 os.remove(self.logfname)
118 self.logfile = open(self.logfname,'w')
118 self.logfile = open(self.logfname,'w')
119
119
120 elif logmode == 'rotate':
120 elif logmode == 'rotate':
121 if isfile(self.logfname):
121 if isfile(self.logfname):
122 if isfile(self.logfname+'.001~'):
122 if isfile(self.logfname+'.001~'):
123 old = glob.glob(self.logfname+'.*~')
123 old = glob.glob(self.logfname+'.*~')
124 old.sort()
124 old.sort()
125 old.reverse()
125 old.reverse()
126 for f in old:
126 for f in old:
127 root, ext = os.path.splitext(f)
127 root, ext = os.path.splitext(f)
128 num = int(ext[1:-1])+1
128 num = int(ext[1:-1])+1
129 os.rename(f, root+'.'+`num`.zfill(3)+'~')
129 os.rename(f, root+'.'+`num`.zfill(3)+'~')
130 os.rename(self.logfname, self.logfname+'.001~')
130 os.rename(self.logfname, self.logfname+'.001~')
131 self.logfile = open(self.logfname,'w')
131 self.logfile = open(self.logfname,'w')
132
132
133 if logmode != 'append':
133 if logmode != 'append':
134 self.logfile.write(self.loghead)
134 self.logfile.write(self.loghead)
135
135
136 self.logfile.flush()
136 self.logfile.flush()
137
137
138 def switch_log(self,val):
138 def switch_log(self,val):
139 """Switch logging on/off. val should be ONLY a boolean."""
139 """Switch logging on/off. val should be ONLY a boolean."""
140
140
141 if val not in [False,True,0,1]:
141 if val not in [False,True,0,1]:
142 raise ValueError, \
142 raise ValueError, \
143 'Call switch_log ONLY with a boolean argument, not with:',val
143 'Call switch_log ONLY with a boolean argument, not with:',val
144
144
145 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
145 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
146
146
147 if self.logfile is None:
147 if self.logfile is None:
148 print """
148 print """
149 Logging hasn't been started yet (use logstart for that).
149 Logging hasn't been started yet (use logstart for that).
150
150
151 %logon/%logoff are for temporarily starting and stopping logging for a logfile
151 %logon/%logoff are for temporarily starting and stopping logging for a logfile
152 which already exists. But you must first start the logging process with
152 which already exists. But you must first start the logging process with
153 %logstart (optionally giving a logfile name)."""
153 %logstart (optionally giving a logfile name)."""
154
154
155 else:
155 else:
156 if self.log_active == val:
156 if self.log_active == val:
157 print 'Logging is already',label[val]
157 print 'Logging is already',label[val]
158 else:
158 else:
159 print 'Switching logging',label[val]
159 print 'Switching logging',label[val]
160 self.log_active = not self.log_active
160 self.log_active = not self.log_active
161 self.log_active_out = self.log_active
161 self.log_active_out = self.log_active
162
162
163 def logstate(self):
163 def logstate(self):
164 """Print a status message about the logger."""
164 """Print a status message about the logger."""
165 if self.logfile is None:
165 if self.logfile is None:
166 print 'Logging has not been activated.'
166 print 'Logging has not been activated.'
167 else:
167 else:
168 state = self.log_active and 'active' or 'temporarily suspended'
168 state = self.log_active and 'active' or 'temporarily suspended'
169 print 'Filename :',self.logfname
169 print 'Filename :',self.logfname
170 print 'Mode :',self.logmode
170 print 'Mode :',self.logmode
171 print 'Output logging :',self.log_output
171 print 'Output logging :',self.log_output
172 print 'Raw input log :',self.log_raw_input
172 print 'Raw input log :',self.log_raw_input
173 print 'Timestamping :',self.timestamp
173 print 'Timestamping :',self.timestamp
174 print 'State :',state
174 print 'State :',state
175
175
176 def log(self,line_ori,line_mod,continuation=None):
176 def log(self,line_ori,line_mod,continuation=None):
177 """Write the line to a log and create input cache variables _i*.
177 """Write the line to a log and create input cache variables _i*.
178
178
179 Inputs:
179 Inputs:
180
180
181 - line_ori: unmodified input line from the user. This is not
181 - line_ori: unmodified input line from the user. This is not
182 necessarily valid Python.
182 necessarily valid Python.
183
183
184 - line_mod: possibly modified input, such as the transformations made
184 - line_mod: possibly modified input, such as the transformations made
185 by input prefilters or input handlers of various kinds. This should
185 by input prefilters or input handlers of various kinds. This should
186 always be valid Python.
186 always be valid Python.
187
187
188 - continuation: if True, indicates this is part of multi-line input."""
188 - continuation: if True, indicates this is part of multi-line input."""
189
189
190 # update the auto _i tables
190 # update the auto _i tables
191 #print '***logging line',line_mod # dbg
191 #print '***logging line',line_mod # dbg
192 #print '***cache_count', self.shell.outputcache.prompt_count # dbg
192 #print '***cache_count', self.shell.outputcache.prompt_count # dbg
193 try:
193 try:
194 input_hist = self.shell.user_ns['_ih']
194 input_hist = self.shell.user_ns['_ih']
195 except:
195 except:
196 print 'userns:',self.shell.user_ns.keys()
196 print 'userns:',self.shell.user_ns.keys()
197 return
197 return
198
198
199 out_cache = self.shell.outputcache
199 out_cache = self.shell.outputcache
200
200
201 # add blank lines if the input cache fell out of sync.
201 # add blank lines if the input cache fell out of sync.
202 if out_cache.do_full_cache and \
202 if out_cache.do_full_cache and \
203 out_cache.prompt_count +1 > len(input_hist):
203 out_cache.prompt_count +1 > len(input_hist):
204 input_hist.extend(['\n'] * (out_cache.prompt_count - len(input_hist)))
204 input_hist.extend(['\n'] * (out_cache.prompt_count - len(input_hist)))
205
205
206 if not continuation and line_mod:
206 if not continuation and line_mod:
207 self._iii = self._ii
207 self._iii = self._ii
208 self._ii = self._i
208 self._ii = self._i
209 self._i = self._i00
209 self._i = self._i00
210 # put back the final \n of every input line
210 # put back the final \n of every input line
211 self._i00 = line_mod+'\n'
211 self._i00 = line_mod+'\n'
212 #print 'Logging input:<%s>' % line_mod # dbg
212 #print 'Logging input:<%s>' % line_mod # dbg
213 input_hist.append(self._i00)
213 input_hist.append(self._i00)
214 #print '---[%s]' % (len(input_hist)-1,) # dbg
214 #print '---[%s]' % (len(input_hist)-1,) # dbg
215
215
216 # hackish access to top-level namespace to create _i1,_i2... dynamically
216 # hackish access to top-level namespace to create _i1,_i2... dynamically
217 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
217 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
218 if self.shell.outputcache.do_full_cache:
218 if self.shell.outputcache.do_full_cache:
219 in_num = self.shell.outputcache.prompt_count
219 in_num = self.shell.outputcache.prompt_count
220
220
221 # but if the opposite is true (a macro can produce multiple inputs
221 # but if the opposite is true (a macro can produce multiple inputs
222 # with no output display called), then bring the output counter in
222 # with no output display called), then bring the output counter in
223 # sync:
223 # sync:
224 last_num = len(input_hist)-1
224 last_num = len(input_hist)-1
225 if in_num != last_num:
225 if in_num != last_num:
226 in_num = self.shell.outputcache.prompt_count = last_num
226 in_num = self.shell.outputcache.prompt_count = last_num
227 new_i = '_i%s' % in_num
227 new_i = '_i%s' % in_num
228 if continuation:
228 if continuation:
229 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
229 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
230 input_hist[in_num] = self._i00
230 input_hist[in_num] = self._i00
231 to_main[new_i] = self._i00
231 to_main[new_i] = self._i00
232 self.shell.user_ns.update(to_main)
232 self.shell.user_ns.update(to_main)
233
233
234 # Write the log line, but decide which one according to the
234 # Write the log line, but decide which one according to the
235 # log_raw_input flag, set when the log is started.
235 # log_raw_input flag, set when the log is started.
236 if self.log_raw_input:
236 if self.log_raw_input:
237 self.log_write(line_ori)
237 self.log_write(line_ori)
238 else:
238 else:
239 self.log_write(line_mod)
239 self.log_write(line_mod)
240
240
241 def log_write(self,data,kind='input'):
241 def log_write(self,data,kind='input'):
242 """Write data to the log file, if active"""
242 """Write data to the log file, if active"""
243
243
244 #print 'data: %r' % data # dbg
244 #print 'data: %r' % data # dbg
245 if self.log_active and data:
245 if self.log_active and data:
246 write = self.logfile.write
246 write = self.logfile.write
247 if kind=='input':
247 if kind=='input':
248 if self.timestamp:
248 if self.timestamp:
249 write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
249 write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
250 time.localtime()))
250 time.localtime()))
251 write('%s\n' % data)
251 write('%s\n' % data)
252 elif kind=='output' and self.log_output:
252 elif kind=='output' and self.log_output:
253 odata = '\n'.join(['#[Out]# %s' % s
253 odata = '\n'.join(['#[Out]# %s' % s
254 for s in data.split('\n')])
254 for s in data.split('\n')])
255 write('%s\n' % odata)
255 write('%s\n' % odata)
256 self.logfile.flush()
256 self.logfile.flush()
257
257
258 def logstop(self):
258 def logstop(self):
259 """Fully stop logging and close log file.
259 """Fully stop logging and close log file.
260
260
261 In order to start logging again, a new logstart() call needs to be
261 In order to start logging again, a new logstart() call needs to be
262 made, possibly (though not necessarily) with a new filename, mode and
262 made, possibly (though not necessarily) with a new filename, mode and
263 other options."""
263 other options."""
264
264
265 self.logfile.close()
265 self.logfile.close()
266 self.logfile = None
266 self.logfile = None
267 self.log_active = False
267 self.log_active = False
268
268
269 # For backwards compatibility, in case anyone was using this.
269 # For backwards compatibility, in case anyone was using this.
270 close_log = logstop
270 close_log = logstop
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
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