Show More
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,155 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Tools for coloring text in ANSI terminals. | |||
|
3 | ||||
|
4 | $Id: ColorANSI.py 410 2004-11-04 07:58:17Z fperez $""" | |||
|
5 | ||||
|
6 | #***************************************************************************** | |||
|
7 | # Copyright (C) 2002-2004 Fernando Perez. <fperez@colorado.edu> | |||
|
8 | # | |||
|
9 | # Distributed under the terms of the BSD License. The full license is in | |||
|
10 | # the file COPYING, distributed as part of this software. | |||
|
11 | #***************************************************************************** | |||
|
12 | ||||
|
13 | from IPython import Release | |||
|
14 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
15 | __license__ = Release.license | |||
|
16 | ||||
|
17 | __all__ = ['TermColors','InputTermColors','ColorScheme','ColorSchemeTable'] | |||
|
18 | ||||
|
19 | import os | |||
|
20 | from UserDict import UserDict | |||
|
21 | ||||
|
22 | from IPython.Struct import Struct | |||
|
23 | ||||
|
24 | def make_color_table(in_class): | |||
|
25 | """Build a set of color attributes in a class. | |||
|
26 | ||||
|
27 | Helper function for building the *TermColors classes.""" | |||
|
28 | ||||
|
29 | color_templates = ( | |||
|
30 | ("Black" , "0;30"), | |||
|
31 | ("Red" , "0;31"), | |||
|
32 | ("Green" , "0;32"), | |||
|
33 | ("Brown" , "0;33"), | |||
|
34 | ("Blue" , "0;34"), | |||
|
35 | ("Purple" , "0;35"), | |||
|
36 | ("Cyan" , "0;36"), | |||
|
37 | ("LightGray" , "0;37"), | |||
|
38 | ("DarkGray" , "1;30"), | |||
|
39 | ("LightRed" , "1;31"), | |||
|
40 | ("LightGreen" , "1;32"), | |||
|
41 | ("Yellow" , "1;33"), | |||
|
42 | ("LightBlue" , "1;34"), | |||
|
43 | ("LightPurple" , "1;35"), | |||
|
44 | ("LightCyan" , "1;36"), | |||
|
45 | ("White" , "1;37"), ) | |||
|
46 | ||||
|
47 | for name,value in color_templates: | |||
|
48 | setattr(in_class,name,in_class._base % value) | |||
|
49 | ||||
|
50 | class TermColors: | |||
|
51 | """Color escape sequences. | |||
|
52 | ||||
|
53 | This class defines the escape sequences for all the standard (ANSI?) | |||
|
54 | colors in terminals. Also defines a NoColor escape which is just the null | |||
|
55 | string, suitable for defining 'dummy' color schemes in terminals which get | |||
|
56 | confused by color escapes. | |||
|
57 | ||||
|
58 | This class should be used as a mixin for building color schemes.""" | |||
|
59 | ||||
|
60 | NoColor = '' # for color schemes in color-less terminals. | |||
|
61 | Normal = '\033[0m' # Reset normal coloring | |||
|
62 | _base = '\033[%sm' # Template for all other colors | |||
|
63 | ||||
|
64 | # Build the actual color table as a set of class attributes: | |||
|
65 | make_color_table(TermColors) | |||
|
66 | ||||
|
67 | class InputTermColors: | |||
|
68 | """Color escape sequences for input prompts. | |||
|
69 | ||||
|
70 | This class is similar to TermColors, but the escapes are wrapped in \001 | |||
|
71 | and \002 so that readline can properly know the length of each line and | |||
|
72 | can wrap lines accordingly. Use this class for any colored text which | |||
|
73 | needs to be used in input prompts, such as in calls to raw_input(). | |||
|
74 | ||||
|
75 | This class defines the escape sequences for all the standard (ANSI?) | |||
|
76 | colors in terminals. Also defines a NoColor escape which is just the null | |||
|
77 | string, suitable for defining 'dummy' color schemes in terminals which get | |||
|
78 | confused by color escapes. | |||
|
79 | ||||
|
80 | This class should be used as a mixin for building color schemes.""" | |||
|
81 | ||||
|
82 | NoColor = '' # for color schemes in color-less terminals. | |||
|
83 | Normal = '\001\033[0m\002' # Reset normal coloring | |||
|
84 | _base = '\001\033[%sm\002' # Template for all other colors | |||
|
85 | ||||
|
86 | # Build the actual color table as a set of class attributes: | |||
|
87 | make_color_table(InputTermColors) | |||
|
88 | ||||
|
89 | class ColorScheme: | |||
|
90 | """Generic color scheme class. Just a name and a Struct.""" | |||
|
91 | def __init__(self,__scheme_name_,colordict=None,**colormap): | |||
|
92 | self.name = __scheme_name_ | |||
|
93 | if colordict is None: | |||
|
94 | self.colors = Struct(**colormap) | |||
|
95 | else: | |||
|
96 | self.colors = Struct(colordict) | |||
|
97 | ||||
|
98 | class ColorSchemeTable(UserDict): | |||
|
99 | """General class to handle tables of color schemes. | |||
|
100 | ||||
|
101 | It's basically a dict of color schemes with a couple of shorthand | |||
|
102 | attributes and some convenient methods. | |||
|
103 | ||||
|
104 | active_scheme_name -> obvious | |||
|
105 | active_colors -> actual color table of the active scheme""" | |||
|
106 | ||||
|
107 | def __init__(self,scheme_list=None,default_scheme=''): | |||
|
108 | """Create a table of color schemes. | |||
|
109 | ||||
|
110 | The table can be created empty and manually filled or it can be | |||
|
111 | created with a list of valid color schemes AND the specification for | |||
|
112 | the default active scheme. | |||
|
113 | """ | |||
|
114 | ||||
|
115 | UserDict.__init__(self) | |||
|
116 | if scheme_list is None: | |||
|
117 | self.active_scheme_name = '' | |||
|
118 | self.active_colors = None | |||
|
119 | else: | |||
|
120 | if default_scheme == '': | |||
|
121 | raise ValueError,'you must specify the default color scheme' | |||
|
122 | for scheme in scheme_list: | |||
|
123 | self.add_scheme(scheme) | |||
|
124 | self.set_active_scheme(default_scheme) | |||
|
125 | ||||
|
126 | def add_scheme(self,new_scheme): | |||
|
127 | """Add a new color scheme to the table.""" | |||
|
128 | if not isinstance(new_scheme,ColorScheme): | |||
|
129 | raise ValueError,'ColorSchemeTable only accepts ColorScheme instances' | |||
|
130 | self[new_scheme.name] = new_scheme | |||
|
131 | ||||
|
132 | def set_active_scheme(self,scheme,case_sensitive=0): | |||
|
133 | """Set the currently active scheme. | |||
|
134 | ||||
|
135 | Names are by default compared in a case-insensitive way, but this can | |||
|
136 | be changed by setting the parameter case_sensitive to true.""" | |||
|
137 | ||||
|
138 | scheme_list = self.keys() | |||
|
139 | if case_sensitive: | |||
|
140 | valid_schemes = scheme_list | |||
|
141 | scheme_test = scheme | |||
|
142 | else: | |||
|
143 | valid_schemes = [s.lower() for s in scheme_list] | |||
|
144 | scheme_test = scheme.lower() | |||
|
145 | try: | |||
|
146 | scheme_idx = valid_schemes.index(scheme_test) | |||
|
147 | except ValueError: | |||
|
148 | raise ValueError,'Unrecognized color scheme: ' + scheme + \ | |||
|
149 | '\nValid schemes: '+str(scheme_list).replace("'', ",'') | |||
|
150 | else: | |||
|
151 | active = scheme_list[scheme_idx] | |||
|
152 | self.active_scheme_name = active | |||
|
153 | self.active_colors = self[active].colors | |||
|
154 | # Now allow using '' as an index for the current active scheme | |||
|
155 | self[''] = self[active] |
@@ -0,0 +1,116 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Configuration loader | |||
|
3 | ||||
|
4 | $Id: ConfigLoader.py 525 2005-02-19 10:53:12Z fperez $""" | |||
|
5 | ||||
|
6 | #***************************************************************************** | |||
|
7 | # Copyright (C) 2001-2004 Fernando Perez. <fperez@colorado.edu> | |||
|
8 | # | |||
|
9 | # Distributed under the terms of the BSD License. The full license is in | |||
|
10 | # the file COPYING, distributed as part of this software. | |||
|
11 | #***************************************************************************** | |||
|
12 | ||||
|
13 | from IPython import Release | |||
|
14 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
15 | __license__ = Release.license | |||
|
16 | ||||
|
17 | import os | |||
|
18 | from pprint import pprint | |||
|
19 | import exceptions | |||
|
20 | ||||
|
21 | from IPython import ultraTB | |||
|
22 | from IPython.Struct import Struct | |||
|
23 | from IPython.genutils import * | |||
|
24 | ||||
|
25 | class ConfigLoaderError(exceptions.Exception): | |||
|
26 | """Exception for ConfigLoader class.""" | |||
|
27 | ||||
|
28 | def __init__(self,args=None): | |||
|
29 | self.args = args | |||
|
30 | ||||
|
31 | class ConfigLoader: | |||
|
32 | ||||
|
33 | """Configuration file loader capable of handling recursive inclusions and | |||
|
34 | with parametrized conflict resolution for multiply found keys.""" | |||
|
35 | ||||
|
36 | def __init__(self,conflict=None,field_sep=None,reclimit=15): | |||
|
37 | ||||
|
38 | """The reclimit parameter controls the number of recursive | |||
|
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 | |||
|
41 | inclusion. | |||
|
42 | ||||
|
43 | - conflict: dictionary for conflict resolutions (see Struct.merge()) | |||
|
44 | ||||
|
45 | """ | |||
|
46 | self.conflict = conflict | |||
|
47 | self.field_sep = field_sep | |||
|
48 | self.reset(reclimit) | |||
|
49 | ||||
|
50 | def reset(self,reclimit=15): | |||
|
51 | self.reclimit = reclimit | |||
|
52 | self.recdepth = 0 | |||
|
53 | self.included = [] | |||
|
54 | ||||
|
55 | def load(self,fname,convert=None,recurse_key='',incpath = '.',**kw): | |||
|
56 | """Load a configuration file, return the resulting Struct. | |||
|
57 | ||||
|
58 | Call: load_config(fname,convert=None,conflict=None,recurse_key='') | |||
|
59 | ||||
|
60 | - fname: file to load from. | |||
|
61 | - convert: dictionary of type conversions (see read_dict()) | |||
|
62 | - recurse_key: keyword in dictionary to trigger recursive file | |||
|
63 | inclusions. | |||
|
64 | """ | |||
|
65 | ||||
|
66 | if self.recdepth > self.reclimit: | |||
|
67 | raise ConfigLoaderError, 'maximum recursive inclusion of rcfiles '+\ | |||
|
68 | 'exceeded: ' + `self.recdepth` + \ | |||
|
69 | '.\nMaybe you have a circular chain of inclusions?' | |||
|
70 | self.recdepth += 1 | |||
|
71 | fname = filefind(fname,incpath) | |||
|
72 | data = Struct() | |||
|
73 | # avoid including the same file more than once | |||
|
74 | if fname in self.included: | |||
|
75 | return data | |||
|
76 | Xinfo = ultraTB.AutoFormattedTB() | |||
|
77 | if convert==None and recurse_key : convert = {qwflat:recurse_key} | |||
|
78 | # for production, change warn to 0: | |||
|
79 | data.merge(read_dict(fname,convert,fs=self.field_sep,strip=1, | |||
|
80 | warn=0,no_empty=0,**kw)) | |||
|
81 | # keep track of successfully loaded files | |||
|
82 | self.included.append(fname) | |||
|
83 | if recurse_key in data.keys(): | |||
|
84 | for incfilename in data[recurse_key]: | |||
|
85 | found=0 | |||
|
86 | try: | |||
|
87 | incfile = filefind(incfilename,incpath) | |||
|
88 | except IOError: | |||
|
89 | if os.name in ['nt','dos']: | |||
|
90 | try: | |||
|
91 | # Try again with '.ini' extension | |||
|
92 | incfilename += '.ini' | |||
|
93 | incfile = filefind(incfilename,incpath) | |||
|
94 | except IOError: | |||
|
95 | found = 0 | |||
|
96 | else: | |||
|
97 | found = 1 | |||
|
98 | else: | |||
|
99 | found = 0 | |||
|
100 | else: | |||
|
101 | found = 1 | |||
|
102 | if found: | |||
|
103 | try: | |||
|
104 | data.merge(self.load(incfile,convert,recurse_key, | |||
|
105 | incpath,**kw), | |||
|
106 | self.conflict) | |||
|
107 | except: | |||
|
108 | Xinfo() | |||
|
109 | warn('Problem loading included file: '+ | |||
|
110 | `incfilename` + '. Ignoring it...') | |||
|
111 | else: | |||
|
112 | warn('File `%s` not found. Included by %s' % (incfilename,fname)) | |||
|
113 | ||||
|
114 | return data | |||
|
115 | ||||
|
116 | # end ConfigLoader |
@@ -0,0 +1,109 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """sys.excepthook for IPython itself, leaves a detailed report on disk. | |||
|
3 | ||||
|
4 | $Id: CrashHandler.py 410 2004-11-04 07:58:17Z fperez $""" | |||
|
5 | ||||
|
6 | #***************************************************************************** | |||
|
7 | # Copyright (C) 2001-2004 Fernando Perez. <fperez@colorado.edu> | |||
|
8 | # | |||
|
9 | # Distributed under the terms of the BSD License. The full license is in | |||
|
10 | # the file COPYING, distributed as part of this software. | |||
|
11 | #***************************************************************************** | |||
|
12 | ||||
|
13 | from IPython import Release | |||
|
14 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
15 | __license__ = Release.license | |||
|
16 | __version__ = Release.version | |||
|
17 | ||||
|
18 | #**************************************************************************** | |||
|
19 | # Required modules | |||
|
20 | ||||
|
21 | # From the standard library | |||
|
22 | import os,sys | |||
|
23 | from pprint import pprint,pformat | |||
|
24 | ||||
|
25 | # Homebrewed | |||
|
26 | from IPython.genutils import * | |||
|
27 | from IPython.Itpl import Itpl,itpl,printpl | |||
|
28 | from IPython import ultraTB | |||
|
29 | from IPython.ultraTB import ColorScheme,ColorSchemeTable # too long names | |||
|
30 | ||||
|
31 | #**************************************************************************** | |||
|
32 | class CrashHandler: | |||
|
33 | """sys.excepthook for IPython itself, leaves a detailed report on disk.""" | |||
|
34 | ||||
|
35 | def __init__(self,IP): | |||
|
36 | self.IP = IP # IPython instance | |||
|
37 | self.bug_contact = Release.authors['Fernando'][0] | |||
|
38 | self.mailto = Release.authors['Fernando'][1] | |||
|
39 | ||||
|
40 | def __call__(self,etype, evalue, etb): | |||
|
41 | ||||
|
42 | # Report tracebacks shouldn't use color in general (safer for users) | |||
|
43 | color_scheme = 'NoColor' | |||
|
44 | ||||
|
45 | # Use this ONLY for developer debugging (keep commented out for release) | |||
|
46 | #color_scheme = 'Linux' # dbg | |||
|
47 | ||||
|
48 | try: | |||
|
49 | rptdir = self.IP.rc.ipythondir | |||
|
50 | except: | |||
|
51 | rptdir = os.getcwd() | |||
|
52 | if not os.path.isdir(rptdir): | |||
|
53 | rptdir = os.getcwd() | |||
|
54 | self.report_name = os.path.join(rptdir,'IPython_crash_report.txt') | |||
|
55 | self.TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,long_header=1) | |||
|
56 | traceback = self.TBhandler.text(etype,evalue,etb,context=31) | |||
|
57 | ||||
|
58 | # print traceback to screen | |||
|
59 | print >> sys.stderr, traceback | |||
|
60 | ||||
|
61 | # and generate a complete report on disk | |||
|
62 | try: | |||
|
63 | report = open(self.report_name,'w') | |||
|
64 | except: | |||
|
65 | print >> sys.stderr, 'Could not create crash report on disk.' | |||
|
66 | return | |||
|
67 | ||||
|
68 | msg = itpl('\n'+'*'*70+'\n' | |||
|
69 | """ | |||
|
70 | Oops, IPython crashed. We do our best to make it stable, but... | |||
|
71 | ||||
|
72 | A crash report was automatically generated with the following information: | |||
|
73 | - A verbatim copy of the traceback above this text. | |||
|
74 | - A copy of your input history during this session. | |||
|
75 | - Data on your current IPython configuration. | |||
|
76 | ||||
|
77 | It was left in the file named: | |||
|
78 | \t'$self.report_name' | |||
|
79 | If you can email this file to the developers, the information in it will help | |||
|
80 | them in understanding and correcting the problem. | |||
|
81 | ||||
|
82 | You can mail it to $self.bug_contact at $self.mailto | |||
|
83 | with the subject 'IPython Crash Report'. | |||
|
84 | ||||
|
85 | If you want to do it now, the following command will work (under Unix): | |||
|
86 | mail -s 'IPython Crash Report' $self.mailto < $self.report_name | |||
|
87 | ||||
|
88 | To ensure accurate tracking of this issue, please file a report about it at: | |||
|
89 | http://www.scipy.net/roundup/ipython (IPython's online bug tracker). | |||
|
90 | """) | |||
|
91 | print >> sys.stderr, msg | |||
|
92 | ||||
|
93 | sec_sep = '\n\n'+'*'*75+'\n\n' | |||
|
94 | report.write('*'*75+'\n\n'+'IPython post-mortem report\n\n') | |||
|
95 | report.write('IPython version: %s \n\n' % __version__) | |||
|
96 | report.write('Platform info : os.name -> %s, sys.platform -> %s' % | |||
|
97 | (os.name,sys.platform) ) | |||
|
98 | report.write(sec_sep+'Current user configuration structure:\n\n') | |||
|
99 | report.write(pformat(self.IP.rc.dict())) | |||
|
100 | report.write(sec_sep+'Crash traceback:\n\n' + traceback) | |||
|
101 | try: | |||
|
102 | report.write(sec_sep+"History of session input:") | |||
|
103 | for line in self.IP.user_ns['_ih']: | |||
|
104 | report.write(line) | |||
|
105 | report.write('\n*** Last line of input (may not be in above history):\n') | |||
|
106 | report.write(self.IP._last_input_line+'\n') | |||
|
107 | except: | |||
|
108 | pass | |||
|
109 | report.close() |
This diff has been collapsed as it changes many lines, (671 lines changed) Show them Hide them | |||||
@@ -0,0 +1,671 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """DPyGetOpt -- Demiurge Python GetOptions Module | |||
|
3 | ||||
|
4 | $Id: DPyGetOpt.py 389 2004-10-09 07:59:30Z fperez $ | |||
|
5 | ||||
|
6 | This module is modeled after perl's Getopt::Long module-- which | |||
|
7 | is, in turn, modeled after GNU's extended getopt() function. | |||
|
8 | ||||
|
9 | Upon instantiation, the option specification should be a sequence | |||
|
10 | (list) of option definitions. | |||
|
11 | ||||
|
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 | |||
|
14 | prepending 'no'; ie 'debug!' specifies that -debug and -nodebug | |||
|
15 | should be accepted. | |||
|
16 | ||||
|
17 | Mandatory arguments to options are specified using a postpended | |||
|
18 | '=' + a type specifier. '=s' specifies a mandatory string | |||
|
19 | argument, '=i' specifies a mandatory integer argument, and '=f' | |||
|
20 | specifies a mandatory real number. In all cases, the '=' can be | |||
|
21 | substituted with ':' to specify that the argument is optional. | |||
|
22 | ||||
|
23 | Dashes '-' in option names are allowed. | |||
|
24 | ||||
|
25 | If an option has the character '@' postpended (after the | |||
|
26 | argumentation specification), it can appear multiple times within | |||
|
27 | each argument list that is processed. The results will be stored | |||
|
28 | in a list. | |||
|
29 | ||||
|
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, | |||
|
32 | and -baz options that appear on within the parsed argument list | |||
|
33 | must have a real number argument and that the accumulated list | |||
|
34 | of values will be available under the name 'foo' | |||
|
35 | ||||
|
36 | $Id: DPyGetOpt.py 389 2004-10-09 07:59:30Z fperez $""" | |||
|
37 | ||||
|
38 | #***************************************************************************** | |||
|
39 | # | |||
|
40 | # Copyright (c) 2001 Bill Bumgarner <bbum@friday.com> | |||
|
41 | # | |||
|
42 | # | |||
|
43 | # Published under the terms of the MIT license, hereby reproduced: | |||
|
44 | # | |||
|
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 | |||
|
47 | # deal in the Software without restriction, including without limitation the | |||
|
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 | |||
|
50 | # furnished to do so, subject to the following conditions: | |||
|
51 | # | |||
|
52 | # The above copyright notice and this permission notice shall be included in | |||
|
53 | # all copies or substantial portions of the Software. | |||
|
54 | # | |||
|
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, | |||
|
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 | |||
|
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 | |||
|
61 | # IN THE SOFTWARE. | |||
|
62 | # | |||
|
63 | #***************************************************************************** | |||
|
64 | ||||
|
65 | __author__ = 'Bill Bumgarner <bbum@friday.com>' | |||
|
66 | __license__ = 'MIT' | |||
|
67 | __version__ = '1.2' | |||
|
68 | ||||
|
69 | # Modified to use re instead of regex and regsub modules. | |||
|
70 | # 2001/5/7, Jonathan Hogg <jonathan@onegoodidea.com> | |||
|
71 | ||||
|
72 | import string | |||
|
73 | import re | |||
|
74 | import sys | |||
|
75 | import types | |||
|
76 | ||||
|
77 | arg_error = 'DPyGetOpt Argument Error' | |||
|
78 | spec_error = 'DPyGetOpt Specification Error' | |||
|
79 | term_error = 'DPyGetOpt Termination Error' | |||
|
80 | ||||
|
81 | specificationExpr = re.compile('(?P<required>.)(?P<type>.)(?P<multi>@?)') | |||
|
82 | ||||
|
83 | ArgRequired = 'Requires an Argument' | |||
|
84 | ArgOptional = 'Argument Optional' | |||
|
85 | ||||
|
86 | # The types modules is not used for these identifiers because there | |||
|
87 | # is no identifier for 'boolean' or 'generic' | |||
|
88 | StringArgType = 'String Argument Type' | |||
|
89 | IntegerArgType = 'Integer Argument Type' | |||
|
90 | RealArgType = 'Real Argument Type' | |||
|
91 | BooleanArgType = 'Boolean Argument Type' | |||
|
92 | GenericArgType = 'Generic Argument Type' | |||
|
93 | ||||
|
94 | # dictionary of conversion functions-- boolean and generic options | |||
|
95 | # do not accept arguments and do not need conversion functions; | |||
|
96 | # the identity function is used purely for convenience. | |||
|
97 | ConversionFunctions = { | |||
|
98 | StringArgType : lambda x: x, | |||
|
99 | IntegerArgType : string.atoi, | |||
|
100 | RealArgType : string.atof, | |||
|
101 | BooleanArgType : lambda x: x, | |||
|
102 | GenericArgType : lambda x: x, | |||
|
103 | } | |||
|
104 | ||||
|
105 | class DPyGetOpt: | |||
|
106 | ||||
|
107 | def __init__(self, spec = None, terminators = ['--']): | |||
|
108 | """ | |||
|
109 | Declare and intialize instance variables | |||
|
110 | ||||
|
111 | Yes, declaration is not necessary... but one of the things | |||
|
112 | I sorely miss from C/Obj-C is the concept of having an | |||
|
113 | interface definition that clearly declares all instance | |||
|
114 | variables and methods without providing any implementation | |||
|
115 | details. it is a useful reference! | |||
|
116 | ||||
|
117 | all instance variables are initialized to 0/Null/None of | |||
|
118 | the appropriate type-- not even the default value... | |||
|
119 | """ | |||
|
120 | ||||
|
121 | # sys.stderr.write(string.join(spec) + "\n") | |||
|
122 | ||||
|
123 | self.allowAbbreviations = 1 # boolean, 1 if abbreviations will | |||
|
124 | # be expanded | |||
|
125 | self.freeValues = [] # list, contains free values | |||
|
126 | self.ignoreCase = 0 # boolean, YES if ignoring case | |||
|
127 | self.needsParse = 0 # boolean, YES if need to reparse parameter spec | |||
|
128 | self.optionNames = {} # dict, all option names-- value is index of tuple | |||
|
129 | self.optionStartExpr = None # regexp defining the start of an option (ie; '-', '--') | |||
|
130 | self.optionTuples = [] # list o' tuples containing defn of options AND aliases | |||
|
131 | self.optionValues = {} # dict, option names (after alias expansion) -> option value(s) | |||
|
132 | self.orderMixed = 0 # boolean, YES if options can be mixed with args | |||
|
133 | self.posixCompliance = 0 # boolean, YES indicates posix like behaviour | |||
|
134 | self.spec = [] # list, raw specs (in case it must be reparsed) | |||
|
135 | self.terminators = terminators # list, strings that terminate argument processing | |||
|
136 | self.termValues = [] # list, values after terminator | |||
|
137 | self.terminator = None # full name of terminator that ended | |||
|
138 | # option processing | |||
|
139 | ||||
|
140 | # set up defaults | |||
|
141 | self.setPosixCompliance() | |||
|
142 | self.setIgnoreCase() | |||
|
143 | self.setAllowAbbreviations() | |||
|
144 | ||||
|
145 | # parse spec-- if present | |||
|
146 | if spec: | |||
|
147 | self.parseConfiguration(spec) | |||
|
148 | ||||
|
149 | def setPosixCompliance(self, aFlag = 0): | |||
|
150 | """ | |||
|
151 | Enables and disables posix compliance. | |||
|
152 | ||||
|
153 | When enabled, '+' can be used as an option prefix and free | |||
|
154 | values can be mixed with options. | |||
|
155 | """ | |||
|
156 | self.posixCompliance = aFlag | |||
|
157 | self.needsParse = 1 | |||
|
158 | ||||
|
159 | if self.posixCompliance: | |||
|
160 | self.optionStartExpr = re.compile('(--|-)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?') | |||
|
161 | self.orderMixed = 0 | |||
|
162 | else: | |||
|
163 | self.optionStartExpr = re.compile('(--|-|\+)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?') | |||
|
164 | self.orderMixed = 1 | |||
|
165 | ||||
|
166 | def isPosixCompliant(self): | |||
|
167 | """ | |||
|
168 | Returns the value of the posix compliance flag. | |||
|
169 | """ | |||
|
170 | return self.posixCompliance | |||
|
171 | ||||
|
172 | def setIgnoreCase(self, aFlag = 1): | |||
|
173 | """ | |||
|
174 | Enables and disables ignoring case during option processing. | |||
|
175 | """ | |||
|
176 | self.needsParse = 1 | |||
|
177 | self.ignoreCase = aFlag | |||
|
178 | ||||
|
179 | def ignoreCase(self): | |||
|
180 | """ | |||
|
181 | Returns 1 if the option processor will ignore case when | |||
|
182 | processing options. | |||
|
183 | """ | |||
|
184 | return self.ignoreCase | |||
|
185 | ||||
|
186 | def setAllowAbbreviations(self, aFlag = 1): | |||
|
187 | """ | |||
|
188 | Enables and disables the expansion of abbreviations during | |||
|
189 | option processing. | |||
|
190 | """ | |||
|
191 | self.allowAbbreviations = aFlag | |||
|
192 | ||||
|
193 | def willAllowAbbreviations(self): | |||
|
194 | """ | |||
|
195 | Returns 1 if abbreviated options will be automatically | |||
|
196 | expanded to the non-abbreviated form (instead of causing an | |||
|
197 | unrecognized option error). | |||
|
198 | """ | |||
|
199 | return self.allowAbbreviations | |||
|
200 | ||||
|
201 | def addTerminator(self, newTerm): | |||
|
202 | """ | |||
|
203 | Adds newTerm as terminator of option processing. | |||
|
204 | ||||
|
205 | Whenever the option processor encounters one of the terminators | |||
|
206 | during option processing, the processing of options terminates | |||
|
207 | immediately, all remaining options are stored in the termValues | |||
|
208 | instance variable and the full name of the terminator is stored | |||
|
209 | in the terminator instance variable. | |||
|
210 | """ | |||
|
211 | self.terminators = self.terminators + [newTerm] | |||
|
212 | ||||
|
213 | def _addOption(self, oTuple): | |||
|
214 | """ | |||
|
215 | Adds the option described by oTuple (name, (type, mode, | |||
|
216 | default), alias) to optionTuples. Adds index keyed under name | |||
|
217 | to optionNames. Raises spec_error if name already in | |||
|
218 | optionNames | |||
|
219 | """ | |||
|
220 | (name, (type, mode, default, multi), realName) = oTuple | |||
|
221 | ||||
|
222 | # verify name and add to option names dictionary | |||
|
223 | if self.optionNames.has_key(name): | |||
|
224 | if realName: | |||
|
225 | raise spec_error, 'Alias \'' + name + '\' for \'' + realName + \ | |||
|
226 | '\' already used for another option or alias.' | |||
|
227 | else: | |||
|
228 | raise spec_error, 'Option named \'' + name + \ | |||
|
229 | '\' specified more than once. Specification: ' + option | |||
|
230 | ||||
|
231 | # validated. add to optionNames | |||
|
232 | self.optionNames[name] = self.tupleIndex | |||
|
233 | self.tupleIndex = self.tupleIndex + 1 | |||
|
234 | ||||
|
235 | # add to optionTuples | |||
|
236 | self.optionTuples = self.optionTuples + [oTuple] | |||
|
237 | ||||
|
238 | # if type is boolean, add negation | |||
|
239 | if type == BooleanArgType: | |||
|
240 | alias = 'no' + name | |||
|
241 | specTuple = (type, mode, 0, multi) | |||
|
242 | oTuple = (alias, specTuple, name) | |||
|
243 | ||||
|
244 | # verify name and add to option names dictionary | |||
|
245 | if self.optionNames.has_key(alias): | |||
|
246 | if realName: | |||
|
247 | raise spec_error, 'Negated alias \'' + name + '\' for \'' + realName + \ | |||
|
248 | '\' already used for another option or alias.' | |||
|
249 | else: | |||
|
250 | raise spec_error, 'Negated option named \'' + name + \ | |||
|
251 | '\' specified more than once. Specification: ' + option | |||
|
252 | ||||
|
253 | # validated. add to optionNames | |||
|
254 | self.optionNames[alias] = self.tupleIndex | |||
|
255 | self.tupleIndex = self.tupleIndex + 1 | |||
|
256 | ||||
|
257 | # add to optionTuples | |||
|
258 | self.optionTuples = self.optionTuples + [oTuple] | |||
|
259 | ||||
|
260 | def addOptionConfigurationTuple(self, oTuple): | |||
|
261 | (name, argSpec, realName) = oTuple | |||
|
262 | if self.ignoreCase: | |||
|
263 | name = string.lower(name) | |||
|
264 | if realName: | |||
|
265 | realName = string.lower(realName) | |||
|
266 | else: | |||
|
267 | realName = name | |||
|
268 | ||||
|
269 | oTuple = (name, argSpec, realName) | |||
|
270 | ||||
|
271 | # add option | |||
|
272 | self._addOption(oTuple) | |||
|
273 | ||||
|
274 | def addOptionConfigurationTuples(self, oTuple): | |||
|
275 | if type(oTuple) is ListType: | |||
|
276 | for t in oTuple: | |||
|
277 | self.addOptionConfigurationTuple(t) | |||
|
278 | else: | |||
|
279 | self.addOptionConfigurationTuple(oTuple) | |||
|
280 | ||||
|
281 | def parseConfiguration(self, spec): | |||
|
282 | # destroy previous stored information + store raw spec | |||
|
283 | self.spec = spec | |||
|
284 | self.optionTuples = [] | |||
|
285 | self.optionNames = {} | |||
|
286 | self.tupleIndex = 0 | |||
|
287 | ||||
|
288 | tupleIndex = 0 | |||
|
289 | ||||
|
290 | # create some regex's for parsing each spec | |||
|
291 | splitExpr = \ | |||
|
292 | re.compile('(?P<names>\w+[-A-Za-z0-9|]*)?(?P<spec>!|[=:][infs]@?)?') | |||
|
293 | for option in spec: | |||
|
294 | # push to lower case (does not negatively affect | |||
|
295 | # specification) | |||
|
296 | if self.ignoreCase: | |||
|
297 | option = string.lower(option) | |||
|
298 | ||||
|
299 | # break into names, specification | |||
|
300 | match = splitExpr.match(option) | |||
|
301 | if match is None: | |||
|
302 | raise spec_error, 'Invalid specification {' + option + '}' | |||
|
303 | ||||
|
304 | names = match.group('names') | |||
|
305 | specification = match.group('spec') | |||
|
306 | ||||
|
307 | # break name into name, aliases | |||
|
308 | nlist = string.split(names, '|') | |||
|
309 | ||||
|
310 | # get name | |||
|
311 | name = nlist[0] | |||
|
312 | aliases = nlist[1:] | |||
|
313 | ||||
|
314 | # specificationExpr = regex.symcomp('\(<required>.\)\(<type>.\)\(<multi>@?\)') | |||
|
315 | if not specification: | |||
|
316 | #spec tuple is ('type', 'arg mode', 'default value', 'multiple') | |||
|
317 | argType = GenericArgType | |||
|
318 | argMode = None | |||
|
319 | argDefault = 1 | |||
|
320 | argMultiple = 0 | |||
|
321 | elif specification == '!': | |||
|
322 | argType = BooleanArgType | |||
|
323 | argMode = None | |||
|
324 | argDefault = 1 | |||
|
325 | argMultiple = 0 | |||
|
326 | else: | |||
|
327 | # parse | |||
|
328 | match = specificationExpr.match(specification) | |||
|
329 | if match is None: | |||
|
330 | # failed to parse, die | |||
|
331 | raise spec_error, 'Invalid configuration for option \'' + option + '\'' | |||
|
332 | ||||
|
333 | # determine mode | |||
|
334 | required = match.group('required') | |||
|
335 | if required == '=': | |||
|
336 | argMode = ArgRequired | |||
|
337 | elif required == ':': | |||
|
338 | argMode = ArgOptional | |||
|
339 | else: | |||
|
340 | raise spec_error, 'Unknown requirement configuration \'' + required + '\'' | |||
|
341 | ||||
|
342 | # determine type | |||
|
343 | type = match.group('type') | |||
|
344 | if type == 's': | |||
|
345 | argType = StringArgType | |||
|
346 | argDefault = '' | |||
|
347 | elif type == 'i': | |||
|
348 | argType = IntegerArgType | |||
|
349 | argDefault = 1 | |||
|
350 | elif type == 'f' or type == 'n': | |||
|
351 | argType = RealArgType | |||
|
352 | argDefault = 1 | |||
|
353 | else: | |||
|
354 | raise spec_error, 'Unknown type specifier \'' + type + '\'' | |||
|
355 | ||||
|
356 | # determine quantity | |||
|
357 | if match.group('multi') == '@': | |||
|
358 | argMultiple = 1 | |||
|
359 | else: | |||
|
360 | argMultiple = 0 | |||
|
361 | ## end else (of not specification) | |||
|
362 | ||||
|
363 | # construct specification tuple | |||
|
364 | specTuple = (argType, argMode, argDefault, argMultiple) | |||
|
365 | ||||
|
366 | # add the option-- option tuple is (name, specTuple, real name) | |||
|
367 | oTuple = (name, specTuple, name) | |||
|
368 | self._addOption(oTuple) | |||
|
369 | ||||
|
370 | for alias in aliases: | |||
|
371 | # drop to all lower (if configured to do so) | |||
|
372 | if self.ignoreCase: | |||
|
373 | alias = string.lower(alias) | |||
|
374 | # create configuration tuple | |||
|
375 | oTuple = (alias, specTuple, name) | |||
|
376 | # add | |||
|
377 | self._addOption(oTuple) | |||
|
378 | ||||
|
379 | # successfully parsed.... | |||
|
380 | self.needsParse = 0 | |||
|
381 | ||||
|
382 | def _getArgTuple(self, argName): | |||
|
383 | """ | |||
|
384 | Returns a list containing all the specification tuples that | |||
|
385 | match argName. If none match, None is returned. If one | |||
|
386 | matches, a list with one tuple is returned. If more than one | |||
|
387 | match, a list containing all the tuples that matched is | |||
|
388 | returned. | |||
|
389 | ||||
|
390 | In other words, this function does not pass judgement upon the | |||
|
391 | validity of multiple matches. | |||
|
392 | """ | |||
|
393 | # is it in the optionNames dict? | |||
|
394 | ||||
|
395 | try: | |||
|
396 | # sys.stderr.write(argName + string.join(self.optionNames.keys()) + "\n") | |||
|
397 | ||||
|
398 | # yes, get index | |||
|
399 | tupleIndex = self.optionNames[argName] | |||
|
400 | # and return tuple as element of list | |||
|
401 | return [self.optionTuples[tupleIndex]] | |||
|
402 | except KeyError: | |||
|
403 | # are abbreviations allowed? | |||
|
404 | if not self.allowAbbreviations: | |||
|
405 | # No! terefore, this cannot be valid argument-- nothing found | |||
|
406 | return None | |||
|
407 | ||||
|
408 | # argName might be an abbreviation (and, abbreviations must | |||
|
409 | # be allowed... or this would not have been reached!) | |||
|
410 | ||||
|
411 | # create regex for argName | |||
|
412 | argExpr = re.compile('^' + argName) | |||
|
413 | ||||
|
414 | tuples = filter(lambda x, argExpr=argExpr: argExpr.search(x[0]) is not None, | |||
|
415 | self.optionTuples) | |||
|
416 | ||||
|
417 | if not len(tuples): | |||
|
418 | return None | |||
|
419 | else: | |||
|
420 | return tuples | |||
|
421 | ||||
|
422 | def _isTerminator(self, optionName): | |||
|
423 | """ | |||
|
424 | Returns the full name of the terminator if optionName is a valid | |||
|
425 | terminator. If it is, sets self.terminator to the full name of | |||
|
426 | the terminator. | |||
|
427 | ||||
|
428 | If more than one terminator matched, raises a term_error with a | |||
|
429 | string describing the ambiguity. | |||
|
430 | """ | |||
|
431 | ||||
|
432 | # sys.stderr.write(optionName + "\n") | |||
|
433 | # sys.stderr.write(repr(self.terminators)) | |||
|
434 | ||||
|
435 | if optionName in self.terminators: | |||
|
436 | self.terminator = optionName | |||
|
437 | elif not self.allowAbbreviations: | |||
|
438 | return None | |||
|
439 | ||||
|
440 | # regex thing in bogus | |||
|
441 | # termExpr = regex.compile('^' + optionName) | |||
|
442 | ||||
|
443 | terms = filter(lambda x, on=optionName: string.find(x,on) == 0, self.terminators) | |||
|
444 | ||||
|
445 | if not len(terms): | |||
|
446 | return None | |||
|
447 | elif len(terms) > 1: | |||
|
448 | raise term_error, 'Ambiguous terminator \'' + optionName + \ | |||
|
449 | '\' matches ' + repr(terms) | |||
|
450 | ||||
|
451 | self.terminator = terms[0] | |||
|
452 | return self.terminator | |||
|
453 | ||||
|
454 | def processArguments(self, args = None): | |||
|
455 | """ | |||
|
456 | Processes args, a list of arguments (including options). | |||
|
457 | ||||
|
458 | If args is the same as sys.argv, automatically trims the first | |||
|
459 | argument (the executable name/path). | |||
|
460 | ||||
|
461 | If an exception is not raised, the argument list was parsed | |||
|
462 | correctly. | |||
|
463 | ||||
|
464 | Upon successful completion, the freeValues instance variable | |||
|
465 | will contain all the arguments that were not associated with an | |||
|
466 | option in the order they were encountered. optionValues is a | |||
|
467 | dictionary containing the value of each option-- the method | |||
|
468 | valueForOption() can be used to query this dictionary. | |||
|
469 | terminator will contain the argument encountered that terminated | |||
|
470 | option processing (or None, if a terminator was never | |||
|
471 | encountered) and termValues will contain all of the options that | |||
|
472 | appeared after the Terminator (or an empty list). | |||
|
473 | """ | |||
|
474 | ||||
|
475 | if hasattr(sys, "argv") and args == sys.argv: | |||
|
476 | args = sys.argv[1:] | |||
|
477 | ||||
|
478 | max = len(args) # maximum index + 1 | |||
|
479 | self.freeValues = [] # array to hold return values | |||
|
480 | self.optionValues= {} | |||
|
481 | index = 0 # initial index | |||
|
482 | self.terminator = None | |||
|
483 | self.termValues = [] | |||
|
484 | ||||
|
485 | while index < max: | |||
|
486 | # obtain argument | |||
|
487 | arg = args[index] | |||
|
488 | # increment index -- REMEMBER; it is NOW incremented | |||
|
489 | index = index + 1 | |||
|
490 | ||||
|
491 | # terminate immediately if option terminator encountered | |||
|
492 | if self._isTerminator(arg): | |||
|
493 | self.freeValues = self.freeValues + args[index:] | |||
|
494 | self.termValues = args[index:] | |||
|
495 | return | |||
|
496 | ||||
|
497 | # is this possibly an option? | |||
|
498 | match = self.optionStartExpr.match(arg) | |||
|
499 | if match is None: | |||
|
500 | # not an option-- add to freeValues | |||
|
501 | self.freeValues = self.freeValues + [arg] | |||
|
502 | if not self.orderMixed: | |||
|
503 | # mixing not allowed; add rest of args as freeValues | |||
|
504 | self.freeValues = self.freeValues + args[index:] | |||
|
505 | # return to caller | |||
|
506 | return | |||
|
507 | else: | |||
|
508 | continue | |||
|
509 | ||||
|
510 | # grab name | |||
|
511 | optName = match.group('option') | |||
|
512 | ||||
|
513 | # obtain next argument-- index has already been incremented | |||
|
514 | nextArg = match.group('arg') | |||
|
515 | if nextArg: | |||
|
516 | nextArg = nextArg[1:] | |||
|
517 | index = index - 1 # put it back | |||
|
518 | else: | |||
|
519 | try: | |||
|
520 | nextArg = args[index] | |||
|
521 | except: | |||
|
522 | nextArg = None | |||
|
523 | ||||
|
524 | # transpose to lower case, if necessary | |||
|
525 | if self.ignoreCase: | |||
|
526 | optName = string.lower(optName) | |||
|
527 | ||||
|
528 | # obtain defining tuple | |||
|
529 | tuples = self._getArgTuple(optName) | |||
|
530 | ||||
|
531 | if tuples == None: | |||
|
532 | raise arg_error, 'Illegal option \'' + arg + '\'' | |||
|
533 | elif len(tuples) > 1: | |||
|
534 | raise arg_error, 'Ambiguous option \'' + arg + '\'; matches ' + \ | |||
|
535 | repr(map(lambda x: x[0], tuples)) | |||
|
536 | else: | |||
|
537 | config = tuples[0] | |||
|
538 | ||||
|
539 | # config is now set to the configuration tuple for the | |||
|
540 | # argument | |||
|
541 | (fullName, spec, realName) = config | |||
|
542 | (optType, optMode, optDefault, optMultiple) = spec | |||
|
543 | ||||
|
544 | # if opt mode required, but nextArg is none, raise an error | |||
|
545 | if (optMode == ArgRequired): | |||
|
546 | if (not nextArg) or self._isTerminator(nextArg): | |||
|
547 | # print nextArg | |||
|
548 | raise arg_error, 'Option \'' + arg + \ | |||
|
549 | '\' requires an argument of type ' + optType | |||
|
550 | ||||
|
551 | if (not optMode == None) and nextArg and (not self._isTerminator(nextArg)): | |||
|
552 | # nextArg defined, option configured to possibly consume arg | |||
|
553 | try: | |||
|
554 | # grab conversion function-- the try is more for internal diagnostics | |||
|
555 | func = ConversionFunctions[optType] | |||
|
556 | try: | |||
|
557 | optionValue = func(nextArg) | |||
|
558 | index = index + 1 | |||
|
559 | except: | |||
|
560 | # only raise conversion error if REQUIRED to consume argument | |||
|
561 | if optMode == ArgRequired: | |||
|
562 | raise arg_error, 'Invalid argument to option \'' + arg + \ | |||
|
563 | '\'; should be \'' + optType + '\'' | |||
|
564 | else: | |||
|
565 | optionValue = optDefault | |||
|
566 | except arg_error: | |||
|
567 | raise arg_error, sys.exc_value | |||
|
568 | except: | |||
|
569 | raise arg_error, '(' + arg + \ | |||
|
570 | ') Conversion function for \'' + optType + '\' not found.' | |||
|
571 | else: | |||
|
572 | optionValue = optDefault | |||
|
573 | ||||
|
574 | # add value to options dictionary | |||
|
575 | if optMultiple: | |||
|
576 | # can be multiple values | |||
|
577 | try: | |||
|
578 | # try to append element | |||
|
579 | self.optionValues[realName] = self.optionValues[realName] + [optionValue] | |||
|
580 | except: | |||
|
581 | # failed-- must not exist; add it | |||
|
582 | self.optionValues[realName] = [optionValue] | |||
|
583 | else: | |||
|
584 | # only one value per | |||
|
585 | if self.isPosixCompliant and self.optionValues.has_key(realName): | |||
|
586 | raise arg_error, 'Argument \'' + arg + '\' occurs multiple times.' | |||
|
587 | ||||
|
588 | self.optionValues[realName] = optionValue | |||
|
589 | ||||
|
590 | def valueForOption(self, optionName, defaultValue = None): | |||
|
591 | """ | |||
|
592 | Return the value associated with optionName. If optionName was | |||
|
593 | not encountered during parsing of the arguments, returns the | |||
|
594 | defaultValue (which defaults to None). | |||
|
595 | """ | |||
|
596 | try: | |||
|
597 | optionValue = self.optionValues[optionName] | |||
|
598 | except: | |||
|
599 | optionValue = defaultValue | |||
|
600 | ||||
|
601 | return optionValue | |||
|
602 | ||||
|
603 | ## | |||
|
604 | ## test/example section | |||
|
605 | ## | |||
|
606 | test_error = 'Test Run Amok!' | |||
|
607 | def _test(): | |||
|
608 | """ | |||
|
609 | A relatively complete test suite. | |||
|
610 | """ | |||
|
611 | try: | |||
|
612 | DPyGetOpt(['foo', 'bar=s', 'foo']) | |||
|
613 | except: | |||
|
614 | print 'EXCEPTION (should be \'foo\' already used..): ' + sys.exc_value | |||
|
615 | ||||
|
616 | try: | |||
|
617 | DPyGetOpt(['foo|bar|apple=s@', 'baz|apple!']) | |||
|
618 | except: | |||
|
619 | print 'EXCEPTION (should be duplicate alias/name error): ' + sys.exc_value | |||
|
620 | ||||
|
621 | x = DPyGetOpt(['apple|atlas=i@', 'application|executable=f@']) | |||
|
622 | try: | |||
|
623 | x.processArguments(['-app', '29.3']) | |||
|
624 | except: | |||
|
625 | print 'EXCEPTION (should be ambiguous argument): ' + sys.exc_value | |||
|
626 | ||||
|
627 | x = DPyGetOpt(['foo'], ['antigravity', 'antithesis']) | |||
|
628 | try: | |||
|
629 | x.processArguments(['-foo', 'anti']) | |||
|
630 | except: | |||
|
631 | print 'EXCEPTION (should be ambiguous terminator): ' + sys.exc_value | |||
|
632 | ||||
|
633 | profile = ['plain-option', | |||
|
634 | 'boolean-option!', | |||
|
635 | 'list-of-integers=i@', | |||
|
636 | 'list-real-option|list-real-alias|list-real-pseudonym=f@', | |||
|
637 | 'optional-string-option:s', | |||
|
638 | 'abbreviated-string-list=s@'] | |||
|
639 | ||||
|
640 | terminators = ['terminator'] | |||
|
641 | ||||
|
642 | args = ['-plain-option', | |||
|
643 | '+noboolean-option', | |||
|
644 | '--list-of-integers', '1', | |||
|
645 | '+list-of-integers', '2', | |||
|
646 | '-list-of-integers', '3', | |||
|
647 | 'freeargone', | |||
|
648 | '-list-real-option', '1.1', | |||
|
649 | '+list-real-alias', '1.2', | |||
|
650 | '--list-real-pseudonym', '1.3', | |||
|
651 | 'freeargtwo', | |||
|
652 | '-abbreviated-string-list', 'String1', | |||
|
653 | '--abbreviated-s', 'String2', | |||
|
654 | '-abbrev', 'String3', | |||
|
655 | '-a', 'String4', | |||
|
656 | '-optional-string-option', | |||
|
657 | 'term', | |||
|
658 | 'next option should look like an invalid arg', | |||
|
659 | '-a'] | |||
|
660 | ||||
|
661 | ||||
|
662 | print 'Using profile: ' + repr(profile) | |||
|
663 | print 'With terminator: ' + repr(terminators) | |||
|
664 | print 'Processing arguments: ' + repr(args) | |||
|
665 | ||||
|
666 | go = DPyGetOpt(profile, terminators) | |||
|
667 | go.processArguments(args) | |||
|
668 | ||||
|
669 | print 'Options (and values): ' + repr(go.optionValues) | |||
|
670 | print 'free args: ' + repr(go.freeValues) | |||
|
671 | print 'term args: ' + repr(go.termValues) |
@@ -0,0 +1,53 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | Pdb debugger class. | |||
|
4 | ||||
|
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 | |||
|
7 | damaged. | |||
|
8 | ||||
|
9 | In the future, this class will be expanded with improvements over the standard | |||
|
10 | pdb. | |||
|
11 | ||||
|
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 | |||
|
14 | details on the PSF (Python Software Foundation) standard license, see: | |||
|
15 | ||||
|
16 | http://www.python.org/2.2.3/license.html | |||
|
17 | ||||
|
18 | $Id: Debugger.py 590 2005-05-30 06:26:51Z fperez $""" | |||
|
19 | ||||
|
20 | from IPython import Release | |||
|
21 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
22 | __license__ = 'Python' | |||
|
23 | ||||
|
24 | import pdb,bdb,cmd,os,sys | |||
|
25 | ||||
|
26 | class Pdb(pdb.Pdb): | |||
|
27 | """Modified Pdb class, does not load readline.""" | |||
|
28 | def __init__(self): | |||
|
29 | bdb.Bdb.__init__(self) | |||
|
30 | cmd.Cmd.__init__(self,completekey=None) # don't load readline | |||
|
31 | self.prompt = '(Pdb) ' | |||
|
32 | self.aliases = {} | |||
|
33 | ||||
|
34 | # Read $HOME/.pdbrc and ./.pdbrc | |||
|
35 | self.rcLines = [] | |||
|
36 | if os.environ.has_key('HOME'): | |||
|
37 | envHome = os.environ['HOME'] | |||
|
38 | try: | |||
|
39 | rcFile = open(os.path.join(envHome, ".pdbrc")) | |||
|
40 | except IOError: | |||
|
41 | pass | |||
|
42 | else: | |||
|
43 | for line in rcFile.readlines(): | |||
|
44 | self.rcLines.append(line) | |||
|
45 | rcFile.close() | |||
|
46 | try: | |||
|
47 | rcFile = open(".pdbrc") | |||
|
48 | except IOError: | |||
|
49 | pass | |||
|
50 | else: | |||
|
51 | for line in rcFile.readlines(): | |||
|
52 | self.rcLines.append(line) | |||
|
53 | rcFile.close() |
@@ -0,0 +1,270 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Modified input prompt for executing files. | |||
|
3 | ||||
|
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 | |||
|
6 | executed. | |||
|
7 | ||||
|
8 | $Id: InterpreterExec.py 573 2005-04-08 08:38:09Z fperez $""" | |||
|
9 | ||||
|
10 | #***************************************************************************** | |||
|
11 | # Copyright (C) 2004 W.J. van der Laan <gnufnork@hetdigitalegat.nl> | |||
|
12 | # Copyright (C) 2004 Fernando Perez <fperez@colorado.edu> | |||
|
13 | # | |||
|
14 | # Distributed under the terms of the BSD License. The full license is in | |||
|
15 | # the file COPYING, distributed as part of this software. | |||
|
16 | #***************************************************************************** | |||
|
17 | ||||
|
18 | from IPython import Release | |||
|
19 | __author__ = 'W.J. van der Laan <gnufnork@hetdigitalegat.nl>, '\ | |||
|
20 | '%s <%s>' % Release.authors['Fernando'] | |||
|
21 | __license__ = Release.license | |||
|
22 | ||||
|
23 | def prefilter_shell(self,line,continuation): | |||
|
24 | """Alternate prefilter, modified for shell-like functionality. | |||
|
25 | ||||
|
26 | - Execute all lines beginning with '~', '/' or '.' | |||
|
27 | - $var=cmd <=> %sc var=cmd | |||
|
28 | - $$var=cmd <=> %sc -l var=cmd | |||
|
29 | """ | |||
|
30 | ||||
|
31 | if line: | |||
|
32 | l0 = line[0] | |||
|
33 | if l0 in '~/.': | |||
|
34 | return self._prefilter("!%s"%line,continuation) | |||
|
35 | elif l0=='$': | |||
|
36 | lrest = line[1:] | |||
|
37 | if lrest.startswith('$'): | |||
|
38 | # $$var=cmd <=> %sc -l var=cmd | |||
|
39 | return self._prefilter("%ssc -l %s" % (self.ESC_MAGIC,lrest[1:]), | |||
|
40 | continuation) | |||
|
41 | else: | |||
|
42 | # $var=cmd <=> %sc var=cmd | |||
|
43 | return self._prefilter("%ssc %s" % (self.ESC_MAGIC,lrest), | |||
|
44 | continuation) | |||
|
45 | else: | |||
|
46 | return self._prefilter(line,continuation) | |||
|
47 | else: | |||
|
48 | return self._prefilter(line,continuation) | |||
|
49 | ||||
|
50 | # Rebind this to be the new IPython prefilter: | |||
|
51 | from IPython.iplib import InteractiveShell | |||
|
52 | InteractiveShell.prefilter = prefilter_shell | |||
|
53 | # Clean up the namespace. | |||
|
54 | del InteractiveShell,prefilter_shell | |||
|
55 | ||||
|
56 | # Provide pysh and further shell-oriented services | |||
|
57 | import os,sys,shutil | |||
|
58 | from IPython.genutils import system,shell,getoutput,getoutputerror | |||
|
59 | ||||
|
60 | # Short aliases for getting shell output as a string and a list | |||
|
61 | sout = getoutput | |||
|
62 | lout = lambda cmd: getoutput(cmd,split=1) | |||
|
63 | ||||
|
64 | # Empty function, meant as a docstring holder so help(pysh) works. | |||
|
65 | def pysh(): | |||
|
66 | """Pysh is a set of modules and extensions to IPython which make shell-like | |||
|
67 | usage with Python syntax more convenient. Keep in mind that pysh is NOT a | |||
|
68 | full-blown shell, so don't try to make it your /etc/passwd entry! | |||
|
69 | ||||
|
70 | In particular, it has no job control, so if you type Ctrl-Z (under Unix), | |||
|
71 | you'll suspend pysh itself, not the process you just started. | |||
|
72 | ||||
|
73 | Since pysh is really nothing but a customized IPython, you should | |||
|
74 | familiarize yourself with IPython's features. This brief help mainly | |||
|
75 | documents areas in which pysh differs from the normal IPython. | |||
|
76 | ||||
|
77 | ALIASES | |||
|
78 | ------- | |||
|
79 | All of your $PATH has been loaded as IPython aliases, so you should be | |||
|
80 | able to type any normal system command and have it executed. See %alias? | |||
|
81 | and %unalias? for details on the alias facilities. | |||
|
82 | ||||
|
83 | SPECIAL SYNTAX | |||
|
84 | -------------- | |||
|
85 | Any lines which begin with '~', '/' and '.' will be executed as shell | |||
|
86 | commands instead of as Python code. The special escapes below are also | |||
|
87 | recognized. !cmd is valid in single or multi-line input, all others are | |||
|
88 | only valid in single-line input: | |||
|
89 | ||||
|
90 | !cmd - pass 'cmd' directly to the shell | |||
|
91 | !!cmd - execute 'cmd' and return output as a list (split on '\\n') | |||
|
92 | $var=cmd - capture output of cmd into var, as a string | |||
|
93 | $$var=cmd - capture output of cmd into var, as a list (split on '\\n') | |||
|
94 | ||||
|
95 | The $/$$ syntaxes make Python variables from system output, which you can | |||
|
96 | later use for further scripting. The converse is also possible: when | |||
|
97 | executing an alias or calling to the system via !/!!, you can expand any | |||
|
98 | python variable or expression by prepending it with $. Full details of | |||
|
99 | the allowed syntax can be found in Python's PEP 215. | |||
|
100 | ||||
|
101 | A few brief examples will illustrate these: | |||
|
102 | ||||
|
103 | fperez[~/test]|3> !ls *s.py | |||
|
104 | scopes.py strings.py | |||
|
105 | ||||
|
106 | ls is an internal alias, so there's no need to use !: | |||
|
107 | fperez[~/test]|4> ls *s.py | |||
|
108 | scopes.py* strings.py | |||
|
109 | ||||
|
110 | !!ls will return the output into a Python variable: | |||
|
111 | fperez[~/test]|5> !!ls *s.py | |||
|
112 | <5> ['scopes.py', 'strings.py'] | |||
|
113 | fperez[~/test]|6> print _5 | |||
|
114 | ['scopes.py', 'strings.py'] | |||
|
115 | ||||
|
116 | $ and $$ allow direct capture to named variables: | |||
|
117 | fperez[~/test]|7> $astr = ls *s.py | |||
|
118 | fperez[~/test]|8> astr | |||
|
119 | <8> 'scopes.py\\nstrings.py' | |||
|
120 | ||||
|
121 | fperez[~/test]|9> $$alist = ls *s.py | |||
|
122 | fperez[~/test]|10> alist | |||
|
123 | <10> ['scopes.py', 'strings.py'] | |||
|
124 | ||||
|
125 | alist is now a normal python list you can loop over. Using $ will expand | |||
|
126 | back the python values when alias calls are made: | |||
|
127 | fperez[~/test]|11> for f in alist: | |||
|
128 | |..> print 'file',f, | |||
|
129 | |..> wc -l $f | |||
|
130 | |..> | |||
|
131 | file scopes.py 13 scopes.py | |||
|
132 | file strings.py 4 strings.py | |||
|
133 | ||||
|
134 | Note that you may need to protect your variables with braces if you want | |||
|
135 | to append strings to their names. To copy all files in alist to .bak | |||
|
136 | extensions, you must use: | |||
|
137 | fperez[~/test]|12> for f in alist: | |||
|
138 | |..> cp $f ${f}.bak | |||
|
139 | ||||
|
140 | If you try using $f.bak, you'll get an AttributeError exception saying | |||
|
141 | that your string object doesn't have a .bak attribute. This is because | |||
|
142 | the $ expansion mechanism allows you to expand full Python expressions: | |||
|
143 | fperez[~/test]|13> echo "sys.platform is: $sys.platform" | |||
|
144 | sys.platform is: linux2 | |||
|
145 | ||||
|
146 | IPython's input history handling is still active, which allows you to | |||
|
147 | rerun a single block of multi-line input by simply using exec: | |||
|
148 | fperez[~/test]|14> $$alist = ls *.eps | |||
|
149 | fperez[~/test]|15> exec _i11 | |||
|
150 | file image2.eps 921 image2.eps | |||
|
151 | file image.eps 921 image.eps | |||
|
152 | ||||
|
153 | While these are new special-case syntaxes, they are designed to allow very | |||
|
154 | efficient use of the shell with minimal typing. At an interactive shell | |||
|
155 | prompt, conciseness of expression wins over readability. | |||
|
156 | ||||
|
157 | USEFUL FUNCTIONS AND MODULES | |||
|
158 | ---------------------------- | |||
|
159 | The os, sys and shutil modules from the Python standard library are | |||
|
160 | automatically loaded. Some additional functions, useful for shell usage, | |||
|
161 | are listed below. You can request more help about them with '?'. | |||
|
162 | ||||
|
163 | shell - execute a command in the underlying system shell | |||
|
164 | system - like shell(), but return the exit status of the command | |||
|
165 | sout - capture the output of a command as a string | |||
|
166 | lout - capture the output of a command as a list (split on '\\n') | |||
|
167 | getoutputerror - capture (output,error) of a shell command | |||
|
168 | ||||
|
169 | sout/lout are the functional equivalents of $/$$. They are provided to | |||
|
170 | allow you to capture system output in the middle of true python code, | |||
|
171 | function definitions, etc (where $ and $$ are invalid). | |||
|
172 | ||||
|
173 | DIRECTORY MANAGEMENT | |||
|
174 | -------------------- | |||
|
175 | Since each command passed by pysh to the underlying system is executed in | |||
|
176 | a subshell which exits immediately, you can NOT use !cd to navigate the | |||
|
177 | filesystem. | |||
|
178 | ||||
|
179 | Pysh provides its own builtin '%cd' magic command to move in the | |||
|
180 | filesystem (the % is not required with automagic on). It also maintains a | |||
|
181 | list of visited directories (use %dhist to see it) and allows direct | |||
|
182 | switching to any of them. Type 'cd?' for more details. | |||
|
183 | ||||
|
184 | %pushd, %popd and %dirs are provided for directory stack handling. | |||
|
185 | ||||
|
186 | PROMPT CUSTOMIZATION | |||
|
187 | -------------------- | |||
|
188 | ||||
|
189 | The supplied ipythonrc-pysh profile comes with an example of a very | |||
|
190 | colored and detailed prompt, mainly to serve as an illustration. The | |||
|
191 | valid escape sequences, besides color names, are: | |||
|
192 | ||||
|
193 | \\# - Prompt number. | |||
|
194 | \\D - Dots, as many as there are digits in \\# (so they align). | |||
|
195 | \\w - Current working directory (cwd). | |||
|
196 | \\W - Basename of current working directory. | |||
|
197 | \\XN - Where N=0..5. N terms of the cwd, with $HOME written as ~. | |||
|
198 | \\YN - Where N=0..5. Like XN, but if ~ is term N+1 it's also shown. | |||
|
199 | \\u - Username. | |||
|
200 | \\H - Full hostname. | |||
|
201 | \\h - Hostname up to first '.' | |||
|
202 | \\$ - Root symbol ($ or #). | |||
|
203 | \\t - Current time, in H:M:S format. | |||
|
204 | \\v - IPython release version. | |||
|
205 | \\n - Newline. | |||
|
206 | \\r - Carriage return. | |||
|
207 | \\\\ - An explicitly escaped '\\'. | |||
|
208 | ||||
|
209 | You can configure your prompt colors using any ANSI color escape. Each | |||
|
210 | color escape sets the color for any subsequent text, until another escape | |||
|
211 | comes in and changes things. The valid color escapes are: | |||
|
212 | ||||
|
213 | \\C_Black | |||
|
214 | \\C_Blue | |||
|
215 | \\C_Brown | |||
|
216 | \\C_Cyan | |||
|
217 | \\C_DarkGray | |||
|
218 | \\C_Green | |||
|
219 | \\C_LightBlue | |||
|
220 | \\C_LightCyan | |||
|
221 | \\C_LightGray | |||
|
222 | \\C_LightGreen | |||
|
223 | \\C_LightPurple | |||
|
224 | \\C_LightRed | |||
|
225 | \\C_Purple | |||
|
226 | \\C_Red | |||
|
227 | \\C_White | |||
|
228 | \\C_Yellow | |||
|
229 | \\C_Normal - Stop coloring, defaults to your terminal settings. | |||
|
230 | """ | |||
|
231 | pass | |||
|
232 | ||||
|
233 | # Configure a few things. Much of this is fairly hackish, since IPython | |||
|
234 | # doesn't really expose a clean API for it. Be careful if you start making | |||
|
235 | # many modifications here. | |||
|
236 | ||||
|
237 | print """\ | |||
|
238 | Welcome to pysh, a set of extensions to IPython for shell usage. | |||
|
239 | help(pysh) -> help on the installed shell extensions and syntax. | |||
|
240 | """ | |||
|
241 | ||||
|
242 | # Set the 'cd' command to quiet mode, a more shell-like behavior | |||
|
243 | __IPYTHON__.default_option('cd','-q') | |||
|
244 | ||||
|
245 | # Load all of $PATH as aliases | |||
|
246 | if os.name == 'posix': | |||
|
247 | # %rehash is very fast, but it doesn't check for executability, it simply | |||
|
248 | # dumps everything in $PATH as an alias. Use rehashx if you want more | |||
|
249 | # checks. | |||
|
250 | __IPYTHON__.magic_rehash() | |||
|
251 | else: | |||
|
252 | # Windows users: the list of extensions considered executable is read from | |||
|
253 | # the environment variable 'pathext'. If this is undefined, IPython | |||
|
254 | # defaults to EXE, COM and BAT. | |||
|
255 | # %rehashx is the one which does extension analysis, at the cost of | |||
|
256 | # being much slower than %rehash. | |||
|
257 | __IPYTHON__.magic_rehashx() | |||
|
258 | ||||
|
259 | # Remove %sc,%sx if present as aliases | |||
|
260 | __IPYTHON__.magic_unalias('sc') | |||
|
261 | __IPYTHON__.magic_unalias('sx') | |||
|
262 | ||||
|
263 | # We need different criteria for line-splitting, so that aliases such as | |||
|
264 | # 'gnome-terminal' are interpreted as a single alias instead of variable | |||
|
265 | # 'gnome' minus variable 'terminal'. | |||
|
266 | import re | |||
|
267 | __IPYTHON__.line_split = re.compile(r'^(\s*)([\?\w\.\-\+]+\w*\s*)(\(?.*$)') | |||
|
268 | ||||
|
269 | # Namespace cleanup | |||
|
270 | del re |
@@ -0,0 +1,91 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Modified input prompt for entering text with >>> or ... at the start. | |||
|
3 | ||||
|
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 | |||
|
6 | line, are stripped. This allows for direct pasting of code from examples such | |||
|
7 | as those available in the standard Python tutorial. | |||
|
8 | ||||
|
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 | |||
|
11 | removal of those characters. This module allows pasting that kind of | |||
|
12 | multi-line examples in one pass. | |||
|
13 | ||||
|
14 | Here is an 'screenshot' of a section of the tutorial pasted into IPython with | |||
|
15 | this feature enabled: | |||
|
16 | ||||
|
17 | In [1]: >>> def fib2(n): # return Fibonacci series up to n | |||
|
18 | ...: ... '''Return a list containing the Fibonacci series up to n.''' | |||
|
19 | ...: ... result = [] | |||
|
20 | ...: ... a, b = 0, 1 | |||
|
21 | ...: ... while b < n: | |||
|
22 | ...: ... result.append(b) # see below | |||
|
23 | ...: ... a, b = b, a+b | |||
|
24 | ...: ... return result | |||
|
25 | ...: | |||
|
26 | ||||
|
27 | In [2]: fib2(10) | |||
|
28 | Out[2]: [1, 1, 2, 3, 5, 8] | |||
|
29 | ||||
|
30 | The >>> and ... are stripped from the input so that the python interpreter | |||
|
31 | only sees the real part of the code. | |||
|
32 | ||||
|
33 | All other input is processed normally. | |||
|
34 | """ | |||
|
35 | #***************************************************************************** | |||
|
36 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
37 | # | |||
|
38 | # Distributed under the terms of the BSD License. The full license is in | |||
|
39 | # the file COPYING, distributed as part of this software. | |||
|
40 | #***************************************************************************** | |||
|
41 | ||||
|
42 | from IPython import Release | |||
|
43 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
44 | __license__ = Release.license | |||
|
45 | ||||
|
46 | # This file is an example of how to modify IPython's line-processing behavior | |||
|
47 | # without touching the internal code. We'll define an alternate pre-processing | |||
|
48 | # stage which allows a special form of input (which is invalid Python syntax) | |||
|
49 | # for certain quantities, rewrites a line of proper Python in those cases, and | |||
|
50 | # then passes it off to IPython's normal processor for further work. | |||
|
51 | ||||
|
52 | # With this kind of customization, IPython can be adapted for many | |||
|
53 | # special-purpose scenarios providing alternate input syntaxes. | |||
|
54 | ||||
|
55 | # This file can be imported like a regular module. | |||
|
56 | ||||
|
57 | # IPython has a prefilter() function that analyzes each input line. We redefine | |||
|
58 | # it here to first pre-process certain forms of input | |||
|
59 | ||||
|
60 | # The prototype of any alternate prefilter must be like this one (the name | |||
|
61 | # doesn't matter): | |||
|
62 | # - line is a string containing the user input line. | |||
|
63 | # - continuation is a parameter which tells us if we are processing a first line of | |||
|
64 | # user input or the second or higher of a multi-line statement. | |||
|
65 | ||||
|
66 | def prefilter_paste(self,line,continuation): | |||
|
67 | """Alternate prefilter for input of pasted code from an interpreter. | |||
|
68 | """ | |||
|
69 | ||||
|
70 | from re import match | |||
|
71 | ||||
|
72 | if match(r'^>>> |^\.\.\. ',line): | |||
|
73 | # In the end, always call the default IPython _prefilter() function. | |||
|
74 | # Note that self must be passed explicitly, b/c we're calling the | |||
|
75 | # unbound class method (since this method will overwrite the instance | |||
|
76 | # prefilter()) | |||
|
77 | return self._prefilter(line[4:],continuation) | |||
|
78 | elif line.strip() == '...': | |||
|
79 | return self._prefilter('',continuation) | |||
|
80 | else: | |||
|
81 | return self._prefilter(line,continuation) | |||
|
82 | ||||
|
83 | # Rebind this to be the new IPython prefilter: | |||
|
84 | from IPython.iplib import InteractiveShell | |||
|
85 | InteractiveShell.prefilter = prefilter_paste | |||
|
86 | ||||
|
87 | # Clean up the namespace. | |||
|
88 | del InteractiveShell,prefilter_paste | |||
|
89 | ||||
|
90 | # Just a heads up at the console | |||
|
91 | print '*** Pasting of code with ">>>" or "..." has been enabled.' |
@@ -0,0 +1,83 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Modified input prompt for entering quantities with units. | |||
|
3 | ||||
|
4 | Modify the behavior of the interactive interpreter to allow direct input of | |||
|
5 | quantities with units without having to make a function call. | |||
|
6 | ||||
|
7 | Now the following forms are accepted: | |||
|
8 | ||||
|
9 | x = 4 m | |||
|
10 | y = -.45e3 m/s | |||
|
11 | g = 9.8 m/s**2 | |||
|
12 | a = 2.3 m/s^2 # ^ -> ** automatically | |||
|
13 | ||||
|
14 | All other input is processed normally. | |||
|
15 | """ | |||
|
16 | #***************************************************************************** | |||
|
17 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
18 | # | |||
|
19 | # Distributed under the terms of the BSD License. The full license is in | |||
|
20 | # the file COPYING, distributed as part of this software. | |||
|
21 | #***************************************************************************** | |||
|
22 | ||||
|
23 | from IPython import Release | |||
|
24 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
25 | __license__ = Release.license | |||
|
26 | ||||
|
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 | |||
|
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 | |||
|
31 | # then passes it off to IPython's normal processor for further work. | |||
|
32 | ||||
|
33 | # With this kind of customization, IPython can be adapted for many | |||
|
34 | # special-purpose scenarios providing alternate input syntaxes. | |||
|
35 | ||||
|
36 | # This file can be imported like a regular module. | |||
|
37 | ||||
|
38 | # IPython has a prefilter() function that analyzes each input line. We redefine | |||
|
39 | # it here to first pre-process certain forms of input | |||
|
40 | ||||
|
41 | # The prototype of any alternate prefilter must be like this one (the name | |||
|
42 | # doesn't matter): | |||
|
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 | |||
|
45 | # user input or the second or higher of a multi-line statement. | |||
|
46 | ||||
|
47 | def prefilter_PQ(self,line,continuation): | |||
|
48 | """Alternate prefilter for input of PhysicalQuantityInteractive objects. | |||
|
49 | ||||
|
50 | This assumes that the function PhysicalQuantityInteractive() has been | |||
|
51 | imported.""" | |||
|
52 | ||||
|
53 | from re import match | |||
|
54 | from IPython.iplib import InteractiveShell | |||
|
55 | ||||
|
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].*)', | |||
|
58 | line) | |||
|
59 | ||||
|
60 | # If special input was ecnountered, process it: | |||
|
61 | if unit_split: | |||
|
62 | var,val,units = unit_split.groups() | |||
|
63 | if var and val and units: | |||
|
64 | units = units.replace('^','**') | |||
|
65 | # Now a valid line needs to be constructed for IPython to process: | |||
|
66 | line = var +" = PhysicalQuantityInteractive(" + val + ", '" + \ | |||
|
67 | units + "')" | |||
|
68 | #print 'New line:',line # dbg | |||
|
69 | ||||
|
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 | |||
|
72 | # method (since this method will overwrite the instance prefilter()) | |||
|
73 | return InteractiveShell._prefilter(self,line,continuation) | |||
|
74 | ||||
|
75 | # Rebind this to be the new IPython prefilter: | |||
|
76 | from IPython.iplib import InteractiveShell | |||
|
77 | InteractiveShell.prefilter = prefilter_PQ | |||
|
78 | ||||
|
79 | # Clean up the namespace. | |||
|
80 | del InteractiveShell,prefilter_PQ | |||
|
81 | ||||
|
82 | # Just a heads up at the console | |||
|
83 | print '*** Simplified input for physical quantities enabled.' |
@@ -0,0 +1,88 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Modify the PhysicalQuantities class for more convenient interactive use. | |||
|
3 | ||||
|
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 | |||
|
6 | namespace. | |||
|
7 | ||||
|
8 | This module should always be loaded *after* math or Numeric, so it can | |||
|
9 | overwrite math functions with the versions that handle units.""" | |||
|
10 | ||||
|
11 | #***************************************************************************** | |||
|
12 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
13 | # | |||
|
14 | # Distributed under the terms of the BSD License. The full license is in | |||
|
15 | # the file COPYING, distributed as part of this software. | |||
|
16 | #***************************************************************************** | |||
|
17 | ||||
|
18 | from IPython import Release | |||
|
19 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
20 | __license__ = Release.license | |||
|
21 | ||||
|
22 | from Scientific.Physics.PhysicalQuantities import PhysicalQuantity | |||
|
23 | ||||
|
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. | |||
|
26 | ||||
|
27 | # If you use math, sin(x) won't work for x an array, only float or PhysQty | |||
|
28 | import math | |||
|
29 | ||||
|
30 | # If you use Numeric, sin(x) works for x a float, PhysQty an array. | |||
|
31 | #import Numeric as math | |||
|
32 | ||||
|
33 | class PhysicalQuantityFunction: | |||
|
34 | """Generic function wrapper for PhysicalQuantity instances. | |||
|
35 | ||||
|
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 | |||
|
38 | whether theta is a pure number or a PhysicalQuantity. | |||
|
39 | ||||
|
40 | This is *slow*. It's meant for convenient interactive use, not for | |||
|
41 | speed.""" | |||
|
42 | ||||
|
43 | def __init__(self,name): | |||
|
44 | self.name = name | |||
|
45 | ||||
|
46 | def __call__(self,x): | |||
|
47 | if isinstance(x,PhysicalQuantity): | |||
|
48 | return PhysicalQuantity.__dict__[self.name](x) | |||
|
49 | else: | |||
|
50 | return math.__dict__[self.name](x) | |||
|
51 | ||||
|
52 | class PhysicalQuantityInteractive(PhysicalQuantity): | |||
|
53 | """Physical quantity with units - modified for Interactive use. | |||
|
54 | ||||
|
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 | |||
|
57 | significant figures are shown. | |||
|
58 | ||||
|
59 | Also adds the following aliases for commonly used methods: | |||
|
60 | b = PhysicalQuantity.inBaseUnits | |||
|
61 | u = PhysicalQuantity.inUnitsOf | |||
|
62 | ||||
|
63 | These are useful when doing a lot of interactive calculations. | |||
|
64 | """ | |||
|
65 | ||||
|
66 | # shorthands for the most useful unit conversions | |||
|
67 | b = PhysicalQuantity.inBaseUnits # so you can just type x.b to get base units | |||
|
68 | u = PhysicalQuantity.inUnitsOf | |||
|
69 | ||||
|
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 | |||
|
72 | # get automatically converted to k(*2), which doesn't work. | |||
|
73 | # Probably not a good idea in general... | |||
|
74 | #__call__ = b | |||
|
75 | ||||
|
76 | def __str__(self): | |||
|
77 | return PhysicalQuantity.__repr__(self) | |||
|
78 | ||||
|
79 | def __repr__(self): | |||
|
80 | value = '%.4G' % self.value | |||
|
81 | units = self.unit.name().replace('**','^') | |||
|
82 | return value + ' ' + units | |||
|
83 | ||||
|
84 | # implement the methods defined in PhysicalQuantity as PhysicalQuantityFunctions | |||
|
85 | sin = PhysicalQuantityFunction('sin') | |||
|
86 | cos = PhysicalQuantityFunction('cos') | |||
|
87 | tan = PhysicalQuantityFunction('tan') | |||
|
88 | sqrt = PhysicalQuantityFunction('sqrt') |
@@ -0,0 +1,13 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """This directory is meant for special-purpose extensions to IPython. | |||
|
3 | ||||
|
4 | This can include things which alter the syntax processing stage (see | |||
|
5 | PhysicalQ_Input for an example of how to do this). | |||
|
6 | ||||
|
7 | Any file located here can be called with an 'execfile =' option as | |||
|
8 | ||||
|
9 | execfile = Extensions/filename.py | |||
|
10 | ||||
|
11 | since the IPython directory itself is already part of the search path for | |||
|
12 | files listed as 'execfile ='. | |||
|
13 | """ |
@@ -0,0 +1,41 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | Extension for printing Numeric Arrays in flexible ways. | |||
|
4 | """ | |||
|
5 | ||||
|
6 | def num_display(self,arg): | |||
|
7 | """Display method for printing which treats Numeric arrays specially. | |||
|
8 | """ | |||
|
9 | ||||
|
10 | # Non-numpy variables are printed using the system default | |||
|
11 | if type(arg) != ArrayType: | |||
|
12 | self._display(arg) | |||
|
13 | return | |||
|
14 | # Otherwise, we do work. | |||
|
15 | format = __IPYTHON__.runtime_rc.numarray_print_format | |||
|
16 | print 'NumPy array, format:',format | |||
|
17 | # Here is where all the printing logic needs to be implemented | |||
|
18 | print arg # nothing yet :) | |||
|
19 | ||||
|
20 | ||||
|
21 | def magic_format(self,parameter_s=''): | |||
|
22 | """Specifies format of numerical output. | |||
|
23 | ||||
|
24 | This command is similar to Ocave's format command. | |||
|
25 | """ | |||
|
26 | ||||
|
27 | valid_formats = ['long','short'] | |||
|
28 | ||||
|
29 | if parameter_s in valid_formats: | |||
|
30 | self.runtime_rc.numarray_print_format = parameter_s | |||
|
31 | print 'Numeric output format is now:',parameter_s | |||
|
32 | else: | |||
|
33 | print 'Invalid format:',parameter_s | |||
|
34 | print 'Valid formats:',valid_formats | |||
|
35 | ||||
|
36 | # setup default format | |||
|
37 | __IPYTHON__.runtime_rc.numarray_print_format = 'long' | |||
|
38 | ||||
|
39 | # Bind our new functions to the interpreter | |||
|
40 | __IPYTHON__.__class__.magic_format = magic_format | |||
|
41 | __IPYTHON__.hooks.display = num_display |
@@ -0,0 +1,48 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | Class which mimics a module. | |||
|
4 | ||||
|
5 | Needed to allow pickle to correctly resolve namespaces during IPython | |||
|
6 | sessions. | |||
|
7 | ||||
|
8 | $Id: FakeModule.py 410 2004-11-04 07:58:17Z fperez $""" | |||
|
9 | ||||
|
10 | #***************************************************************************** | |||
|
11 | # Copyright (C) 2002-2004 Fernando Perez. <fperez@colorado.edu> | |||
|
12 | # | |||
|
13 | # Distributed under the terms of the BSD License. The full license is in | |||
|
14 | # the file COPYING, distributed as part of this software. | |||
|
15 | #***************************************************************************** | |||
|
16 | ||||
|
17 | class FakeModule: | |||
|
18 | """Simple class with attribute access to fake a module. | |||
|
19 | ||||
|
20 | This is not meant to replace a module, but to allow inserting a fake | |||
|
21 | module in sys.modules so that systems which rely on run-time module | |||
|
22 | importing (like shelve and pickle) work correctly in interactive IPython | |||
|
23 | sessions. | |||
|
24 | ||||
|
25 | Do NOT use this code for anything other than this IPython private hack.""" | |||
|
26 | ||||
|
27 | def __init__(self,adict): | |||
|
28 | ||||
|
29 | # It seems pydoc (and perhaps others) needs any module instance to | |||
|
30 | # implement a __nonzero__ method, so we add it if missing: | |||
|
31 | if '__nonzero__' not in adict: | |||
|
32 | def __nonzero__(): | |||
|
33 | return 1 | |||
|
34 | adict['__nonzero__'] = __nonzero__ | |||
|
35 | ||||
|
36 | self.__dict__ = adict | |||
|
37 | ||||
|
38 | def __getattr__(self,key): | |||
|
39 | try: | |||
|
40 | return self.__dict__[key] | |||
|
41 | except KeyError, e: | |||
|
42 | raise AttributeError("FakeModule object has no attribute %s" % e) | |||
|
43 | ||||
|
44 | def __str__(self): | |||
|
45 | return "<IPython.FakeModule instance>" | |||
|
46 | ||||
|
47 | def __repr__(self): | |||
|
48 | return str(self) |
@@ -0,0 +1,198 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Word completion for GNU readline 2.0. | |||
|
3 | ||||
|
4 | --------------------------------------------------------------------------- | |||
|
5 | NOTE: This version is a re-implementation of rlcompleter with selectable | |||
|
6 | namespace. | |||
|
7 | ||||
|
8 | The problem with rlcompleter is that it's hardwired to work with | |||
|
9 | __main__.__dict__, and in some cases one may have 'sandboxed' namespaces. So | |||
|
10 | this class is a ripoff of rlcompleter, with the namespace to work in as an | |||
|
11 | optional parameter. | |||
|
12 | ||||
|
13 | This class can be used just like rlcompleter, but the Completer class now has | |||
|
14 | a constructor with the optional 'namespace' parameter. | |||
|
15 | ||||
|
16 | A patch has been submitted to Python@sourceforge for these changes to go in | |||
|
17 | the standard Python distribution. | |||
|
18 | ||||
|
19 | The patch went in for Python 2.3. Once IPython drops support for Python 2.2, | |||
|
20 | this file can be significantly reduced. | |||
|
21 | --------------------------------------------------------------------------- | |||
|
22 | ||||
|
23 | Original rlcompleter documentation: | |||
|
24 | ||||
|
25 | This requires the latest extension to the readline module (the | |||
|
26 | completes keywords, built-ins and globals in __main__; when completing | |||
|
27 | NAME.NAME..., it evaluates (!) the expression up to the last dot and | |||
|
28 | completes its attributes. | |||
|
29 | ||||
|
30 | It's very cool to do "import string" type "string.", hit the | |||
|
31 | completion key (twice), and see the list of names defined by the | |||
|
32 | string module! | |||
|
33 | ||||
|
34 | Tip: to use the tab key as the completion key, call | |||
|
35 | ||||
|
36 | readline.parse_and_bind("tab: complete") | |||
|
37 | ||||
|
38 | Notes: | |||
|
39 | ||||
|
40 | - Exceptions raised by the completer function are *ignored* (and | |||
|
41 | generally cause the completion to fail). This is a feature -- since | |||
|
42 | readline sets the tty device in raw (or cbreak) mode, printing a | |||
|
43 | traceback wouldn't work well without some complicated hoopla to save, | |||
|
44 | reset and restore the tty state. | |||
|
45 | ||||
|
46 | - The evaluation of the NAME.NAME... form may cause arbitrary | |||
|
47 | application defined code to be executed if an object with a | |||
|
48 | __getattr__ hook is found. Since it is the responsibility of the | |||
|
49 | application (or the user) to enable this feature, I consider this an | |||
|
50 | acceptable risk. More complicated expressions (e.g. function calls or | |||
|
51 | indexing operations) are *not* evaluated. | |||
|
52 | ||||
|
53 | - GNU readline is also used by the built-in functions input() and | |||
|
54 | raw_input(), and thus these also benefit/suffer from the completer | |||
|
55 | features. Clearly an interactive application can benefit by | |||
|
56 | specifying its own completer function and using raw_input() for all | |||
|
57 | its input. | |||
|
58 | ||||
|
59 | - When the original stdin is not a tty device, GNU readline is never | |||
|
60 | used, and this module (and the readline module) are silently inactive. | |||
|
61 | ||||
|
62 | """ | |||
|
63 | ||||
|
64 | #***************************************************************************** | |||
|
65 | # | |||
|
66 | # Since this file is essentially a minimally modified copy of the rlcompleter | |||
|
67 | # module which is part of the standard Python distribution, I assume that the | |||
|
68 | # proper procedure is to maintain its copyright as belonging to the Python | |||
|
69 | # Software Foundation: | |||
|
70 | # | |||
|
71 | # Copyright (C) 2001 Python Software Foundation, www.python.org | |||
|
72 | # | |||
|
73 | # Distributed under the terms of the Python Software Foundation license. | |||
|
74 | # | |||
|
75 | # Full text available at: | |||
|
76 | # | |||
|
77 | # http://www.python.org/2.1/license.html | |||
|
78 | # | |||
|
79 | #***************************************************************************** | |||
|
80 | ||||
|
81 | import readline | |||
|
82 | import __builtin__ | |||
|
83 | import __main__ | |||
|
84 | ||||
|
85 | __all__ = ["Completer"] | |||
|
86 | ||||
|
87 | class Completer: | |||
|
88 | def __init__(self, namespace = None): | |||
|
89 | """Create a new completer for the command line. | |||
|
90 | ||||
|
91 | Completer([namespace]) -> completer instance. | |||
|
92 | ||||
|
93 | If unspecified, the default namespace where completions are performed | |||
|
94 | is __main__ (technically, __main__.__dict__). Namespaces should be | |||
|
95 | given as dictionaries. | |||
|
96 | ||||
|
97 | Completer instances should be used as the completion mechanism of | |||
|
98 | readline via the set_completer() call: | |||
|
99 | ||||
|
100 | readline.set_completer(Completer(my_namespace).complete) | |||
|
101 | """ | |||
|
102 | ||||
|
103 | if namespace and type(namespace) != type({}): | |||
|
104 | raise TypeError,'namespace must be a dictionary' | |||
|
105 | ||||
|
106 | # Don't bind to namespace quite yet, but flag whether the user wants a | |||
|
107 | # specific namespace or to use __main__.__dict__. This will allow us | |||
|
108 | # to bind to __main__.__dict__ at completion time, not now. | |||
|
109 | if namespace is None: | |||
|
110 | self.use_main_ns = 1 | |||
|
111 | else: | |||
|
112 | self.use_main_ns = 0 | |||
|
113 | self.namespace = namespace | |||
|
114 | ||||
|
115 | def complete(self, text, state): | |||
|
116 | """Return the next possible completion for 'text'. | |||
|
117 | ||||
|
118 | This is called successively with state == 0, 1, 2, ... until it | |||
|
119 | returns None. The completion should begin with 'text'. | |||
|
120 | ||||
|
121 | """ | |||
|
122 | if self.use_main_ns: | |||
|
123 | self.namespace = __main__.__dict__ | |||
|
124 | ||||
|
125 | if state == 0: | |||
|
126 | if "." in text: | |||
|
127 | self.matches = self.attr_matches(text) | |||
|
128 | else: | |||
|
129 | self.matches = self.global_matches(text) | |||
|
130 | try: | |||
|
131 | return self.matches[state] | |||
|
132 | except IndexError: | |||
|
133 | return None | |||
|
134 | ||||
|
135 | def global_matches(self, text): | |||
|
136 | """Compute matches when text is a simple name. | |||
|
137 | ||||
|
138 | Return a list of all keywords, built-in functions and names currently | |||
|
139 | defined in self.namespace that match. | |||
|
140 | ||||
|
141 | """ | |||
|
142 | import keyword | |||
|
143 | matches = [] | |||
|
144 | n = len(text) | |||
|
145 | for list in [keyword.kwlist, | |||
|
146 | __builtin__.__dict__.keys(), | |||
|
147 | self.namespace.keys()]: | |||
|
148 | for word in list: | |||
|
149 | if word[:n] == text and word != "__builtins__": | |||
|
150 | matches.append(word) | |||
|
151 | return matches | |||
|
152 | ||||
|
153 | def attr_matches(self, text): | |||
|
154 | """Compute matches when text contains a dot. | |||
|
155 | ||||
|
156 | Assuming the text is of the form NAME.NAME....[NAME], and is | |||
|
157 | evaluatable in self.namespace, it will be evaluated and its attributes | |||
|
158 | (as revealed by dir()) are used as possible completions. (For class | |||
|
159 | instances, class members are are also considered.) | |||
|
160 | ||||
|
161 | WARNING: this can still invoke arbitrary C code, if an object | |||
|
162 | with a __getattr__ hook is evaluated. | |||
|
163 | ||||
|
164 | """ | |||
|
165 | import re | |||
|
166 | ||||
|
167 | # Another option, seems to work great. Catches things like ''.<tab> | |||
|
168 | m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text) | |||
|
169 | ||||
|
170 | if not m: | |||
|
171 | return [] | |||
|
172 | expr, attr = m.group(1, 3) | |||
|
173 | object = eval(expr, self.namespace) | |||
|
174 | words = dir(object) | |||
|
175 | if hasattr(object,'__class__'): | |||
|
176 | words.append('__class__') | |||
|
177 | words.extend(get_class_members(object.__class__)) | |||
|
178 | n = len(attr) | |||
|
179 | matches = [] | |||
|
180 | for word in words: | |||
|
181 | try: | |||
|
182 | if word[:n] == attr and word != "__builtins__": | |||
|
183 | matches.append("%s.%s" % (expr, word)) | |||
|
184 | except: | |||
|
185 | # some badly behaved objects pollute dir() with non-strings, | |||
|
186 | # which cause the completion to fail. This way we skip the | |||
|
187 | # bad entries and can still continue processing the others. | |||
|
188 | pass | |||
|
189 | return matches | |||
|
190 | ||||
|
191 | def get_class_members(klass): | |||
|
192 | ret = dir(klass) | |||
|
193 | if hasattr(klass,'__bases__'): | |||
|
194 | for base in klass.__bases__: | |||
|
195 | ret.extend(get_class_members(base)) | |||
|
196 | return ret | |||
|
197 | ||||
|
198 | readline.set_completer(Completer().complete) |
This diff has been collapsed as it changes many lines, (655 lines changed) Show them Hide them | |||||
@@ -0,0 +1,655 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Improved replacement for the Gnuplot.Gnuplot class. | |||
|
3 | ||||
|
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 | |||
|
6 | convenient PostScript generation, plus some fixes for hardcopy(). | |||
|
7 | ||||
|
8 | It also adds a convenient plot2 method for plotting dictionaries and | |||
|
9 | lists/tuples of arrays. | |||
|
10 | ||||
|
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: | |||
|
13 | ||||
|
14 | import IPython.Gnuplot2 as Gnuplot | |||
|
15 | ||||
|
16 | $Id: Gnuplot2.py 392 2004-10-09 22:01:51Z fperez $""" | |||
|
17 | ||||
|
18 | import string,os,time,types | |||
|
19 | import cStringIO | |||
|
20 | import sys | |||
|
21 | import tempfile | |||
|
22 | import Numeric | |||
|
23 | import Gnuplot as Gnuplot_ori | |||
|
24 | from IPython.genutils import popkey,xsys | |||
|
25 | ||||
|
26 | # needed by hardcopy(): | |||
|
27 | gp = Gnuplot_ori.gp | |||
|
28 | ||||
|
29 | # Patch for Gnuplot.py 1.6 compatibility. | |||
|
30 | # Thanks to Hayden Callow <h.callow@elec.canterbury.ac.nz> | |||
|
31 | try: | |||
|
32 | OptionException = Gnuplot_ori.PlotItems.OptionException | |||
|
33 | except AttributeError: | |||
|
34 | OptionException = Gnuplot_ori.Errors.OptionError | |||
|
35 | ||||
|
36 | # exhibit a similar interface to Gnuplot so it can be somewhat drop-in | |||
|
37 | Data = Gnuplot_ori.Data | |||
|
38 | Func = Gnuplot_ori.Func | |||
|
39 | GridData = Gnuplot_ori.GridData | |||
|
40 | PlotItem = Gnuplot_ori.PlotItem | |||
|
41 | PlotItems = Gnuplot_ori.PlotItems | |||
|
42 | ||||
|
43 | # Modify some of Gnuplot's functions with improved versions (or bugfixed, in | |||
|
44 | # hardcopy's case). In order to preserve the docstrings at runtime, I've | |||
|
45 | # copied them from the original code. | |||
|
46 | ||||
|
47 | # After some significant changes in v 1.7 of Gnuplot.py, we need to do a bit | |||
|
48 | # of version checking. | |||
|
49 | ||||
|
50 | if Gnuplot_ori.__version__ <= '1.6': | |||
|
51 | _BaseFileItem = PlotItems.File | |||
|
52 | _BaseTempFileItem = PlotItems.TempFile | |||
|
53 | ||||
|
54 | # Fix the File class to add the 'index' option for Gnuplot versions < 1.7 | |||
|
55 | class File(_BaseFileItem): | |||
|
56 | ||||
|
57 | _option_list = _BaseFileItem._option_list.copy() | |||
|
58 | _option_list.update({ | |||
|
59 | 'index' : lambda self, index: self.set_option_index(index), | |||
|
60 | }) | |||
|
61 | ||||
|
62 | # A new initializer is needed b/c we want to add a modified | |||
|
63 | # _option_sequence list which includes 'index' in the right place. | |||
|
64 | def __init__(self,*args,**kw): | |||
|
65 | self._option_sequence = ['binary', 'index', 'using', 'smooth', 'axes', | |||
|
66 | 'title', 'with'] | |||
|
67 | ||||
|
68 | _BaseFileItem.__init__(self,*args,**kw) | |||
|
69 | ||||
|
70 | # Let's fix the constructor docstring | |||
|
71 | __newdoc = \ | |||
|
72 | """Additional Keyword arguments added by IPython: | |||
|
73 | ||||
|
74 | 'index=<int>' -- similar to the `index` keyword in Gnuplot. | |||
|
75 | This allows only some of the datasets in a file to be | |||
|
76 | plotted. Datasets within a file are assumed to be separated | |||
|
77 | by _pairs_ of blank lines, and the first one is numbered as | |||
|
78 | 0 (similar to C/Python usage).""" | |||
|
79 | __init__.__doc__ = PlotItems.File.__init__.__doc__ + __newdoc | |||
|
80 | ||||
|
81 | def set_option_index(self, index): | |||
|
82 | if index is None: | |||
|
83 | self.clear_option('index') | |||
|
84 | elif type(index) in [type(''), type(1)]: | |||
|
85 | self._options['index'] = (index, 'index %s' % index) | |||
|
86 | elif type(index) is type(()): | |||
|
87 | self._options['index'] = (index,'index %s' % | |||
|
88 | string.join(map(repr, index), ':')) | |||
|
89 | else: | |||
|
90 | raise OptionException('index=%s' % (index,)) | |||
|
91 | ||||
|
92 | # We need a FileClass with a different name from 'File', which is a | |||
|
93 | # factory function in 1.7, so that our String class can subclass FileClass | |||
|
94 | # in any version. | |||
|
95 | _FileClass = File | |||
|
96 | ||||
|
97 | else: # Gnuplot.py version 1.7 and greater | |||
|
98 | _FileClass = _BaseFileItem = PlotItems._FileItem | |||
|
99 | _BaseTempFileItem = PlotItems._TempFileItem | |||
|
100 | File = PlotItems.File | |||
|
101 | ||||
|
102 | # Now, we can add our generic code which is version independent | |||
|
103 | ||||
|
104 | # First some useful utilities | |||
|
105 | def eps_fix_bbox(fname): | |||
|
106 | """Fix the bounding box of an eps file by running ps2eps on it. | |||
|
107 | ||||
|
108 | If its name ends in .eps, the original file is removed. | |||
|
109 | ||||
|
110 | This is particularly useful for plots made by Gnuplot with square aspect | |||
|
111 | ratio: there is a bug in Gnuplot which makes it generate a bounding box | |||
|
112 | which is far wider than the actual plot. | |||
|
113 | ||||
|
114 | This function assumes that ps2eps is installed in your system.""" | |||
|
115 | ||||
|
116 | # note: ps2ps and eps2eps do NOT work, ONLY ps2eps works correctly. The | |||
|
117 | # others make output with bitmapped fonts, which looks horrible. | |||
|
118 | print 'Fixing eps file: <%s>' % fname | |||
|
119 | xsys('ps2eps -f -q -l %s' % fname) | |||
|
120 | if fname.endswith('.eps'): | |||
|
121 | os.rename(fname+'.eps',fname) | |||
|
122 | ||||
|
123 | def is_list1d(x,containers = [types.ListType,types.TupleType]): | |||
|
124 | """Returns true if x appears to be a 1d list/tuple/array. | |||
|
125 | ||||
|
126 | The heuristics are: identify Numeric arrays, or lists/tuples whose first | |||
|
127 | element is not itself a list/tuple. This way zipped lists should work like | |||
|
128 | the original Gnuplot. There's no inexpensive way to know if a list doesn't | |||
|
129 | have a composite object after its first element, so that kind of input | |||
|
130 | will produce an error. But it should work well in most cases. | |||
|
131 | """ | |||
|
132 | x_type = type(x) | |||
|
133 | ||||
|
134 | return x_type == Numeric.ArrayType and len(x.shape)==1 or \ | |||
|
135 | (x_type in containers and | |||
|
136 | type(x[0]) not in containers + [Numeric.ArrayType]) | |||
|
137 | ||||
|
138 | def zip_items(items,titles=None): | |||
|
139 | """zip together neighboring 1-d arrays, and zip standalone ones | |||
|
140 | with their index. Leave other plot items alone.""" | |||
|
141 | ||||
|
142 | class StandaloneItem(Exception): pass | |||
|
143 | ||||
|
144 | def get_titles(titles): | |||
|
145 | """Return the next title and the input titles array. | |||
|
146 | ||||
|
147 | The input array may be changed to None when no titles are left to | |||
|
148 | prevent extra unnecessary calls to this function.""" | |||
|
149 | ||||
|
150 | try: | |||
|
151 | title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope | |||
|
152 | except IndexError: | |||
|
153 | titles = None # so we don't enter again | |||
|
154 | title = None | |||
|
155 | else: | |||
|
156 | tit_ct[0] += 1 | |||
|
157 | return title,titles | |||
|
158 | ||||
|
159 | new_items = [] | |||
|
160 | ||||
|
161 | if titles: | |||
|
162 | # Initialize counter. It was put in a list as a hack to allow the | |||
|
163 | # nested get_titles to modify it without raising a NameError. | |||
|
164 | tit_ct = [0] | |||
|
165 | ||||
|
166 | n = 0 # this loop needs to be done by hand | |||
|
167 | while n < len(items): | |||
|
168 | item = items[n] | |||
|
169 | try: | |||
|
170 | if is_list1d(item): | |||
|
171 | if n==len(items)-1: # last in list | |||
|
172 | raise StandaloneItem | |||
|
173 | else: # check the next item and zip together if needed | |||
|
174 | next_item = items[n+1] | |||
|
175 | if next_item is None: | |||
|
176 | n += 1 | |||
|
177 | raise StandaloneItem | |||
|
178 | elif is_list1d(next_item): | |||
|
179 | # this would be best done with an iterator | |||
|
180 | if titles: | |||
|
181 | title,titles = get_titles(titles) | |||
|
182 | else: | |||
|
183 | title = None | |||
|
184 | new_items.append(Data(zip(item,next_item), | |||
|
185 | title=title)) | |||
|
186 | n += 1 # avoid double-inclusion of next item | |||
|
187 | else: # can't zip with next, zip with own index list | |||
|
188 | raise StandaloneItem | |||
|
189 | else: # not 1-d array | |||
|
190 | new_items.append(item) | |||
|
191 | except StandaloneItem: | |||
|
192 | if titles: | |||
|
193 | title,titles = get_titles(titles) | |||
|
194 | else: | |||
|
195 | title = None | |||
|
196 | new_items.append(Data(zip(range(len(item)),item),title=title)) | |||
|
197 | except AttributeError: | |||
|
198 | new_items.append(item) | |||
|
199 | n+=1 | |||
|
200 | ||||
|
201 | return new_items | |||
|
202 | ||||
|
203 | # And some classes with enhanced functionality. | |||
|
204 | class String(_FileClass): | |||
|
205 | """Make a PlotItem from data in a string with the same format as a File. | |||
|
206 | ||||
|
207 | This allows writing data directly inside python scripts using the exact | |||
|
208 | same format and manipulation options which would be used for external | |||
|
209 | files.""" | |||
|
210 | ||||
|
211 | def __init__(self, data_str, **keyw): | |||
|
212 | """Construct a String object. | |||
|
213 | ||||
|
214 | <data_str> is a string formatted exactly like a valid Gnuplot data | |||
|
215 | file would be. All options from the File constructor are valid here. | |||
|
216 | ||||
|
217 | Warning: when used for interactive plotting in scripts which exit | |||
|
218 | immediately, you may get an error because the temporary file used to | |||
|
219 | hold the string data was deleted before Gnuplot had a chance to see | |||
|
220 | it. You can work around this problem by putting a raw_input() call at | |||
|
221 | the end of the script. | |||
|
222 | ||||
|
223 | This problem does not appear when generating PostScript output, only | |||
|
224 | with Gnuplot windows.""" | |||
|
225 | ||||
|
226 | self.tmpfile = _BaseTempFileItem() | |||
|
227 | tmpfile = file(self.tmpfile.filename,'w') | |||
|
228 | tmpfile.write(data_str) | |||
|
229 | _BaseFileItem.__init__(self,self.tmpfile,**keyw) | |||
|
230 | ||||
|
231 | ||||
|
232 | class Gnuplot(Gnuplot_ori.Gnuplot): | |||
|
233 | """Improved Gnuplot class. | |||
|
234 | ||||
|
235 | Enhancements: better plot,replot and hardcopy methods. New methods for | |||
|
236 | quick range setting. | |||
|
237 | """ | |||
|
238 | ||||
|
239 | def xrange(self,min='*',max='*'): | |||
|
240 | """Set xrange. If min/max is omitted, it is set to '*' (auto). | |||
|
241 | ||||
|
242 | Note that this is different from the regular Gnuplot behavior, where | |||
|
243 | an unspecified limit means no change. Here any unspecified limit is | |||
|
244 | set to autoscaling, allowing these functions to be used for full | |||
|
245 | autoscaling when called with no arguments. | |||
|
246 | ||||
|
247 | To preserve one limit's current value while changing the other, an | |||
|
248 | explicit '' argument must be given as the limit to be kept. | |||
|
249 | ||||
|
250 | Similar functions exist for [y{2}z{2}rtuv]range.""" | |||
|
251 | ||||
|
252 | self('set xrange [%s:%s]' % (min,max)) | |||
|
253 | ||||
|
254 | def yrange(self,min='*',max='*'): | |||
|
255 | self('set yrange [%s:%s]' % (min,max)) | |||
|
256 | ||||
|
257 | def zrange(self,min='*',max='*'): | |||
|
258 | self('set zrange [%s:%s]' % (min,max)) | |||
|
259 | ||||
|
260 | def x2range(self,min='*',max='*'): | |||
|
261 | self('set xrange [%s:%s]' % (min,max)) | |||
|
262 | ||||
|
263 | def y2range(self,min='*',max='*'): | |||
|
264 | self('set yrange [%s:%s]' % (min,max)) | |||
|
265 | ||||
|
266 | def z2range(self,min='*',max='*'): | |||
|
267 | self('set zrange [%s:%s]' % (min,max)) | |||
|
268 | ||||
|
269 | def rrange(self,min='*',max='*'): | |||
|
270 | self('set rrange [%s:%s]' % (min,max)) | |||
|
271 | ||||
|
272 | def trange(self,min='*',max='*'): | |||
|
273 | self('set trange [%s:%s]' % (min,max)) | |||
|
274 | ||||
|
275 | def urange(self,min='*',max='*'): | |||
|
276 | self('set urange [%s:%s]' % (min,max)) | |||
|
277 | ||||
|
278 | def vrange(self,min='*',max='*'): | |||
|
279 | self('set vrange [%s:%s]' % (min,max)) | |||
|
280 | ||||
|
281 | def set_ps(self,option): | |||
|
282 | """Set an option for the PostScript terminal and reset default term.""" | |||
|
283 | ||||
|
284 | self('set terminal postscript %s ' % option) | |||
|
285 | self('set terminal %s' % gp.GnuplotOpts.default_term) | |||
|
286 | ||||
|
287 | def __plot_ps(self, plot_method,*items, **keyw): | |||
|
288 | """Wrapper for plot/splot/replot, with processing of hardcopy options. | |||
|
289 | ||||
|
290 | For internal use only.""" | |||
|
291 | ||||
|
292 | # Filter out PostScript options which will crash the normal plot/replot | |||
|
293 | psargs = {'filename':None, | |||
|
294 | 'mode':None, | |||
|
295 | 'eps':None, | |||
|
296 | 'enhanced':None, | |||
|
297 | 'color':None, | |||
|
298 | 'solid':None, | |||
|
299 | 'duplexing':None, | |||
|
300 | 'fontname':None, | |||
|
301 | 'fontsize':None, | |||
|
302 | 'debug':0 } | |||
|
303 | ||||
|
304 | for k in psargs.keys(): | |||
|
305 | if keyw.has_key(k): | |||
|
306 | psargs[k] = keyw[k] | |||
|
307 | del keyw[k] | |||
|
308 | ||||
|
309 | # Filter out other options the original plot doesn't know | |||
|
310 | hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None) | |||
|
311 | titles = popkey(keyw,'titles',0) | |||
|
312 | ||||
|
313 | # the filename keyword should control hardcopy generation, this is an | |||
|
314 | # override switch only which needs to be explicitly set to zero | |||
|
315 | if hardcopy: | |||
|
316 | if psargs['filename'] is None: | |||
|
317 | raise ValueError, \ | |||
|
318 | 'If you request hardcopy, you must give a filename.' | |||
|
319 | ||||
|
320 | # set null output so nothing goes to screen. hardcopy() restores output | |||
|
321 | self('set term dumb') | |||
|
322 | # I don't know how to prevent screen output in Windows | |||
|
323 | if os.name == 'posix': | |||
|
324 | self('set output "/dev/null"') | |||
|
325 | ||||
|
326 | new_items = zip_items(items,titles) | |||
|
327 | # plot_method is either plot or replot from the original Gnuplot class: | |||
|
328 | plot_method(self,*new_items,**keyw) | |||
|
329 | ||||
|
330 | # Do hardcopy if requested | |||
|
331 | if hardcopy: | |||
|
332 | if psargs['filename'].endswith('.eps'): | |||
|
333 | psargs['eps'] = 1 | |||
|
334 | self.hardcopy(**psargs) | |||
|
335 | ||||
|
336 | def plot(self, *items, **keyw): | |||
|
337 | """Draw a new plot. | |||
|
338 | ||||
|
339 | Clear the current plot and create a new 2-d plot containing | |||
|
340 | the specified items. Each arguments should be of the | |||
|
341 | following types: | |||
|
342 | ||||
|
343 | 'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most | |||
|
344 | flexible way to call plot because the PlotItems can | |||
|
345 | contain suboptions. Moreover, PlotItems can be saved to | |||
|
346 | variables so that their lifetime is longer than one plot | |||
|
347 | command; thus they can be replotted with minimal overhead. | |||
|
348 | ||||
|
349 | 'string' (e.g., 'sin(x)') -- The string is interpreted as | |||
|
350 | 'Func(string)' (a function that is computed by gnuplot). | |||
|
351 | ||||
|
352 | Anything else -- The object, which should be convertible to an | |||
|
353 | array, is passed to the 'Data' constructor, and thus | |||
|
354 | plotted as data. If the conversion fails, an exception is | |||
|
355 | raised. | |||
|
356 | ||||
|
357 | ||||
|
358 | This is a modified version of plot(). Compared to the original in | |||
|
359 | Gnuplot.py, this version has several enhancements, listed below. | |||
|
360 | ||||
|
361 | ||||
|
362 | Modifications to the input arguments | |||
|
363 | ------------------------------------ | |||
|
364 | ||||
|
365 | (1-d array means Numeric array, list or tuple): | |||
|
366 | ||||
|
367 | (i) Any 1-d array which is NOT followed by another 1-d array, is | |||
|
368 | automatically zipped with range(len(array_1d)). Typing g.plot(y) will | |||
|
369 | plot y against its indices. | |||
|
370 | ||||
|
371 | (ii) If two 1-d arrays are contiguous in the argument list, they are | |||
|
372 | automatically zipped together. So g.plot(x,y) plots y vs. x, and | |||
|
373 | g.plot(x1,y1,x2,y2) plots y1 vs. x1 and y2 vs. x2. | |||
|
374 | ||||
|
375 | (iii) Any 1-d array which is followed by None is automatically zipped | |||
|
376 | with range(len(array_1d)). In this form, typing g.plot(y1,None,y2) | |||
|
377 | will plot both y1 and y2 against their respective indices (and NOT | |||
|
378 | versus one another). The None prevents zipping y1 and y2 together, and | |||
|
379 | since y2 is unpaired it is automatically zipped to its indices by (i) | |||
|
380 | ||||
|
381 | (iv) Any other arguments which don't match these cases are left alone and | |||
|
382 | passed to the code below. | |||
|
383 | ||||
|
384 | For lists or tuples, the heuristics used to determine whether they are | |||
|
385 | in fact 1-d is fairly simplistic: their first element is checked, and | |||
|
386 | if it is not a list or tuple itself, it is assumed that the whole | |||
|
387 | object is one-dimensional. | |||
|
388 | ||||
|
389 | An additional optional keyword 'titles' has been added: it must be a | |||
|
390 | list of strings to be used as labels for the individual plots which | |||
|
391 | are NOT PlotItem objects (since those objects carry their own labels | |||
|
392 | within). | |||
|
393 | ||||
|
394 | ||||
|
395 | PostScript generation | |||
|
396 | --------------------- | |||
|
397 | ||||
|
398 | This version of plot() also handles automatically the production of | |||
|
399 | PostScript output. The main options are (given as keyword arguments): | |||
|
400 | ||||
|
401 | - filename: a string, typically ending in .eps. If given, the plot is | |||
|
402 | sent to this file in PostScript format. | |||
|
403 | ||||
|
404 | - hardcopy: this can be set to 0 to override 'filename'. It does not | |||
|
405 | need to be given to produce PostScript, its purpose is to allow | |||
|
406 | switching PostScript output off globally in scripts without having to | |||
|
407 | manually change 'filename' values in multiple calls. | |||
|
408 | ||||
|
409 | All other keywords accepted by Gnuplot.hardcopy() are transparently | |||
|
410 | passed, and safely ignored if output is sent to the screen instead of | |||
|
411 | PostScript. | |||
|
412 | ||||
|
413 | For example: | |||
|
414 | ||||
|
415 | In [1]: x=frange(0,2*pi,npts=100) | |||
|
416 | ||||
|
417 | Generate a plot in file 'sin.eps': | |||
|
418 | ||||
|
419 | In [2]: plot(x,sin(x),filename = 'sin.eps') | |||
|
420 | ||||
|
421 | Plot to screen instead, without having to change the filename: | |||
|
422 | ||||
|
423 | In [3]: plot(x,sin(x),filename = 'sin.eps',hardcopy=0) | |||
|
424 | ||||
|
425 | Pass the 'color=0' option to hardcopy for monochrome output: | |||
|
426 | ||||
|
427 | In [4]: plot(x,sin(x),filename = 'sin.eps',color=0) | |||
|
428 | ||||
|
429 | PostScript generation through plot() is useful mainly for scripting | |||
|
430 | uses where you are not interested in interactive plotting. For | |||
|
431 | interactive use, the hardcopy() function is typically more convenient: | |||
|
432 | ||||
|
433 | In [5]: plot(x,sin(x)) | |||
|
434 | ||||
|
435 | In [6]: hardcopy('sin.eps') """ | |||
|
436 | ||||
|
437 | self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw) | |||
|
438 | ||||
|
439 | def plot2(self,arg,**kw): | |||
|
440 | """Plot the entries of a dictionary or a list/tuple of arrays. | |||
|
441 | ||||
|
442 | This simple utility calls plot() with a list of Gnuplot.Data objects | |||
|
443 | constructed either from the values of the input dictionary, or the entries | |||
|
444 | in it if it is a tuple or list. Each item gets labeled with the key/index | |||
|
445 | in the Gnuplot legend. | |||
|
446 | ||||
|
447 | Each item is plotted by zipping it with a list of its indices. | |||
|
448 | ||||
|
449 | Any keywords are passed directly to plot().""" | |||
|
450 | ||||
|
451 | if hasattr(arg,'keys'): | |||
|
452 | keys = arg.keys() | |||
|
453 | keys.sort() | |||
|
454 | else: | |||
|
455 | keys = range(len(arg)) | |||
|
456 | ||||
|
457 | pitems = [Data(zip(range(len(arg[k])),arg[k]),title=`k`) for k in keys] | |||
|
458 | self.plot(*pitems,**kw) | |||
|
459 | ||||
|
460 | def splot(self, *items, **keyw): | |||
|
461 | """Draw a new three-dimensional plot. | |||
|
462 | ||||
|
463 | Clear the current plot and create a new 3-d plot containing | |||
|
464 | the specified items. Arguments can be of the following types: | |||
|
465 | ||||
|
466 | 'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This | |||
|
467 | is the most flexible way to call plot because the | |||
|
468 | PlotItems can contain suboptions. Moreover, PlotItems can | |||
|
469 | be saved to variables so that their lifetime is longer | |||
|
470 | than one plot command--thus they can be replotted with | |||
|
471 | minimal overhead. | |||
|
472 | ||||
|
473 | 'string' (e.g., 'sin(x*y)') -- The string is interpreted as a | |||
|
474 | 'Func()' (a function that is computed by gnuplot). | |||
|
475 | ||||
|
476 | Anything else -- The object is converted to a Data() item, and | |||
|
477 | thus plotted as data. Note that each data point should | |||
|
478 | normally have at least three values associated with it | |||
|
479 | (i.e., x, y, and z). If the conversion fails, an | |||
|
480 | exception is raised. | |||
|
481 | ||||
|
482 | This is a modified version of splot(). Compared to the original in | |||
|
483 | Gnuplot.py, this version has several enhancements, listed in the | |||
|
484 | plot() documentation. | |||
|
485 | """ | |||
|
486 | ||||
|
487 | self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw) | |||
|
488 | ||||
|
489 | def replot(self, *items, **keyw): | |||
|
490 | """Replot the data, possibly adding new 'PlotItem's. | |||
|
491 | ||||
|
492 | Replot the existing graph, using the items in the current | |||
|
493 | itemlist. If arguments are specified, they are interpreted as | |||
|
494 | additional items to be plotted alongside the existing items on | |||
|
495 | the same graph. See 'plot' for details. | |||
|
496 | ||||
|
497 | If you want to replot to a postscript file, you MUST give the | |||
|
498 | 'filename' keyword argument in each call to replot. The Gnuplot python | |||
|
499 | interface has no way of knowing that your previous call to | |||
|
500 | Gnuplot.plot() was meant for PostScript output.""" | |||
|
501 | ||||
|
502 | self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw) | |||
|
503 | ||||
|
504 | # The original hardcopy has a bug. See fix at the end. The rest of the code | |||
|
505 | # was lifted verbatim from the original, so that people using IPython get the | |||
|
506 | # benefits without having to manually patch Gnuplot.py | |||
|
507 | def hardcopy(self, filename=None, | |||
|
508 | mode=None, | |||
|
509 | eps=None, | |||
|
510 | enhanced=None, | |||
|
511 | color=None, | |||
|
512 | solid=None, | |||
|
513 | duplexing=None, | |||
|
514 | fontname=None, | |||
|
515 | fontsize=None, | |||
|
516 | debug = 0, | |||
|
517 | ): | |||
|
518 | """Create a hardcopy of the current plot. | |||
|
519 | ||||
|
520 | Create a postscript hardcopy of the current plot to the | |||
|
521 | default printer (if configured) or to the specified filename. | |||
|
522 | ||||
|
523 | Note that gnuplot remembers the postscript suboptions across | |||
|
524 | terminal changes. Therefore if you set, for example, color=1 | |||
|
525 | for one hardcopy then the next hardcopy will also be color | |||
|
526 | unless you explicitly choose color=0. Alternately you can | |||
|
527 | force all of the options to their defaults by setting | |||
|
528 | mode='default'. I consider this to be a bug in gnuplot. | |||
|
529 | ||||
|
530 | Keyword arguments: | |||
|
531 | ||||
|
532 | 'filename=<string>' -- if a filename is specified, save the | |||
|
533 | output in that file; otherwise print it immediately | |||
|
534 | using the 'default_lpr' configuration option. If the | |||
|
535 | filename ends in '.eps', EPS mode is automatically | |||
|
536 | selected (like manually specifying eps=1 or mode='eps'). | |||
|
537 | ||||
|
538 | 'mode=<string>' -- set the postscript submode ('landscape', | |||
|
539 | 'portrait', 'eps', or 'default'). The default is | |||
|
540 | to leave this option unspecified. | |||
|
541 | ||||
|
542 | 'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to | |||
|
543 | generate encapsulated postscript. | |||
|
544 | ||||
|
545 | 'enhanced=<bool>' -- if set (the default), then generate | |||
|
546 | enhanced postscript, which allows extra features like | |||
|
547 | font-switching, superscripts, and subscripts in axis | |||
|
548 | labels. (Some old gnuplot versions do not support | |||
|
549 | enhanced postscript; if this is the case set | |||
|
550 | gp.GnuplotOpts.prefer_enhanced_postscript=None.) | |||
|
551 | ||||
|
552 | 'color=<bool>' -- if set, create a plot with color. Default | |||
|
553 | is to leave this option unchanged. | |||
|
554 | ||||
|
555 | 'solid=<bool>' -- if set, force lines to be solid (i.e., not | |||
|
556 | dashed). | |||
|
557 | ||||
|
558 | 'duplexing=<string>' -- set duplexing option ('defaultplex', | |||
|
559 | 'simplex', or 'duplex'). Only request double-sided | |||
|
560 | printing if your printer can handle it. Actually this | |||
|
561 | option is probably meaningless since hardcopy() can only | |||
|
562 | print a single plot at a time. | |||
|
563 | ||||
|
564 | 'fontname=<string>' -- set the default font to <string>, | |||
|
565 | which must be a valid postscript font. The default is | |||
|
566 | to leave this option unspecified. | |||
|
567 | ||||
|
568 | 'fontsize=<double>' -- set the default font size, in | |||
|
569 | postscript points. | |||
|
570 | ||||
|
571 | 'debug=<bool>' -- print extra debugging information (useful if | |||
|
572 | your PostScript files are misteriously not being created). | |||
|
573 | """ | |||
|
574 | ||||
|
575 | if filename is None: | |||
|
576 | assert gp.GnuplotOpts.default_lpr is not None, \ | |||
|
577 | OptionException('default_lpr is not set, so you can only ' | |||
|
578 | 'print to a file.') | |||
|
579 | filename = gp.GnuplotOpts.default_lpr | |||
|
580 | lpr_output = 1 | |||
|
581 | else: | |||
|
582 | if filename.endswith('.eps'): | |||
|
583 | eps = 1 | |||
|
584 | lpr_output = 0 | |||
|
585 | ||||
|
586 | # Be careful processing the options. If the user didn't | |||
|
587 | # request an option explicitly, do not specify it on the 'set | |||
|
588 | # terminal' line (don't even specify the default value for the | |||
|
589 | # option). This is to avoid confusing older versions of | |||
|
590 | # gnuplot that do not support all of these options. The | |||
|
591 | # exception is 'enhanced', which is just too useful to have to | |||
|
592 | # specify each time! | |||
|
593 | ||||
|
594 | setterm = ['set', 'terminal', 'postscript'] | |||
|
595 | if eps: | |||
|
596 | assert mode is None or mode=='eps', \ | |||
|
597 | OptionException('eps option and mode are incompatible') | |||
|
598 | setterm.append('eps') | |||
|
599 | else: | |||
|
600 | if mode is not None: | |||
|
601 | assert mode in ['landscape', 'portrait', 'eps', 'default'], \ | |||
|
602 | OptionException('illegal mode "%s"' % mode) | |||
|
603 | setterm.append(mode) | |||
|
604 | if enhanced is None: | |||
|
605 | enhanced = gp.GnuplotOpts.prefer_enhanced_postscript | |||
|
606 | if enhanced is not None: | |||
|
607 | if enhanced: setterm.append('enhanced') | |||
|
608 | else: setterm.append('noenhanced') | |||
|
609 | if color is not None: | |||
|
610 | if color: setterm.append('color') | |||
|
611 | else: setterm.append('monochrome') | |||
|
612 | if solid is not None: | |||
|
613 | if solid: setterm.append('solid') | |||
|
614 | else: setterm.append('dashed') | |||
|
615 | if duplexing is not None: | |||
|
616 | assert duplexing in ['defaultplex', 'simplex', 'duplex'], \ | |||
|
617 | OptionException('illegal duplexing mode "%s"' % duplexing) | |||
|
618 | setterm.append(duplexing) | |||
|
619 | if fontname is not None: | |||
|
620 | setterm.append('"%s"' % fontname) | |||
|
621 | if fontsize is not None: | |||
|
622 | setterm.append('%s' % fontsize) | |||
|
623 | ||||
|
624 | self(string.join(setterm)) | |||
|
625 | self.set_string('output', filename) | |||
|
626 | # replot the current figure (to the printer): | |||
|
627 | self.refresh() | |||
|
628 | ||||
|
629 | # fperez. Ugly kludge: often for some reason the file is NOT created | |||
|
630 | # and we must reissue the creation commands. I have no idea why! | |||
|
631 | if not lpr_output: | |||
|
632 | #print 'Hardcopy <%s>' % filename # dbg | |||
|
633 | maxtries = 20 | |||
|
634 | delay = 0.1 # delay (in seconds) between print attempts | |||
|
635 | for i in range(maxtries): | |||
|
636 | time.sleep(0.05) # safety, very small delay | |||
|
637 | if os.path.isfile(filename): | |||
|
638 | if debug: | |||
|
639 | print 'Hardcopy to file <%s> success at attempt #%s.' \ | |||
|
640 | % (filename,i+1) | |||
|
641 | break | |||
|
642 | time.sleep(delay) | |||
|
643 | # try again, issue all commands just in case | |||
|
644 | self(string.join(setterm)) | |||
|
645 | self.set_string('output', filename) | |||
|
646 | self.refresh() | |||
|
647 | if not os.path.isfile(filename): | |||
|
648 | print >> sys.stderr,'ERROR: Tried %s times and failed to '\ | |||
|
649 | 'create hardcopy file `%s`' % (maxtries,filename) | |||
|
650 | ||||
|
651 | # reset the terminal to its `default' setting: | |||
|
652 | self('set terminal %s' % gp.GnuplotOpts.default_term) | |||
|
653 | self.set_string('output') | |||
|
654 | ||||
|
655 | #********************** End of file <Gnuplot2.py> ************************ |
@@ -0,0 +1,148 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Interactive functions and magic functions for Gnuplot usage. | |||
|
3 | ||||
|
4 | This requires the Gnuplot.py module for interfacing python with Gnuplot, which | |||
|
5 | can be downloaded from: | |||
|
6 | ||||
|
7 | http://gnuplot-py.sourceforge.net/ | |||
|
8 | ||||
|
9 | See gphelp() below for details on the services offered by this module. | |||
|
10 | ||||
|
11 | Inspired by a suggestion/request from Arnd Baecker. | |||
|
12 | ||||
|
13 | $Id: GnuplotInteractive.py 389 2004-10-09 07:59:30Z fperez $""" | |||
|
14 | ||||
|
15 | __all__ = ['Gnuplot','gp','gp_new','plot','plot2','splot','replot', | |||
|
16 | 'hardcopy','gpdata','gpfile','gpstring','gpfunc','gpgrid', | |||
|
17 | 'gphelp'] | |||
|
18 | ||||
|
19 | import IPython.GnuplotRuntime as GRun | |||
|
20 | from IPython.genutils import page,warn | |||
|
21 | ||||
|
22 | # Set global names for interactive use | |||
|
23 | Gnuplot = GRun.Gnuplot | |||
|
24 | gp_new = GRun.gp_new | |||
|
25 | gp = GRun.gp | |||
|
26 | plot = gp.plot | |||
|
27 | plot2 = gp.plot2 | |||
|
28 | splot = gp.splot | |||
|
29 | replot = gp.replot | |||
|
30 | hardcopy = gp.hardcopy | |||
|
31 | ||||
|
32 | # Accessors for the main plot object constructors: | |||
|
33 | gpdata = Gnuplot.Data | |||
|
34 | gpfile = Gnuplot.File | |||
|
35 | gpstring = Gnuplot.String | |||
|
36 | gpfunc = Gnuplot.Func | |||
|
37 | gpgrid = Gnuplot.GridData | |||
|
38 | ||||
|
39 | def gphelp(): | |||
|
40 | """Print information about the Gnuplot facilities in IPython.""" | |||
|
41 | ||||
|
42 | page(""" | |||
|
43 | IPython provides an interface to access the Gnuplot scientific plotting | |||
|
44 | system, in an environment similar to that of Mathematica or Matlab. | |||
|
45 | ||||
|
46 | New top-level global objects | |||
|
47 | ---------------------------- | |||
|
48 | ||||
|
49 | Please see their respective docstrings for further details. | |||
|
50 | ||||
|
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 | |||
|
53 | typed in an interactive gnuplot window. | |||
|
54 | ||||
|
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: | |||
|
57 | ||||
|
58 | In [1]: plot(x,sin(x),title='Sin(x)') # assuming x is a Numeric array | |||
|
59 | ||||
|
60 | and obtain a plot of sin(x) vs x with the title 'Sin(x)'. | |||
|
61 | ||||
|
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 | |||
|
64 | plots, each in a separate window. | |||
|
65 | ||||
|
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 | |||
|
68 | functions with improved versions (Gnuplot2 comes with IPython). | |||
|
69 | ||||
|
70 | - gpdata, gpfile, gpstring, gpfunc, gpgrid: aliases to Gnuplot.Data, | |||
|
71 | Gnuplot.File, Gnuplot.String, Gnuplot.Func and Gnuplot.GridData | |||
|
72 | respectively. These functions create objects which can then be passed to the | |||
|
73 | plotting commands. See the Gnuplot.py documentation for details. | |||
|
74 | ||||
|
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 | |||
|
77 | plotting sin(x) vs x as above, typing | |||
|
78 | ||||
|
79 | In [2]: gp('plot x,sin(x)') | |||
|
80 | ||||
|
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() | |||
|
83 | method lives in python and does know about these variables. | |||
|
84 | ||||
|
85 | ||||
|
86 | New magic functions | |||
|
87 | ------------------- | |||
|
88 | ||||
|
89 | %gpc: pass one command to Gnuplot and execute it or open a Gnuplot shell where | |||
|
90 | each line of input is executed. | |||
|
91 | ||||
|
92 | %gp_set_default: reset the value of IPython's global Gnuplot instance.""") | |||
|
93 | ||||
|
94 | # Code below is all for IPython use | |||
|
95 | # Define the magic functions for communicating with the above gnuplot instance. | |||
|
96 | def magic_gpc(self,parameter_s=''): | |||
|
97 | """Execute a gnuplot command or open a gnuplot shell. | |||
|
98 | ||||
|
99 | Usage (omit the % if automagic is on). There are two ways to use it: | |||
|
100 | ||||
|
101 | 1) %gpc 'command' -> passes 'command' directly to the gnuplot instance. | |||
|
102 | ||||
|
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 | |||
|
105 | command, use \\ at the end of each intermediate line. | |||
|
106 | ||||
|
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). | |||
|
109 | """ | |||
|
110 | ||||
|
111 | if parameter_s.strip(): | |||
|
112 | self.shell.gnuplot(parameter_s) | |||
|
113 | else: | |||
|
114 | self.shell.gnuplot.interact() | |||
|
115 | ||||
|
116 | def magic_gp_set_default(self,parameter_s=''): | |||
|
117 | """Set the default gnuplot instance accessed by the %gp magic function. | |||
|
118 | ||||
|
119 | %gp_set_default name | |||
|
120 | ||||
|
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 | |||
|
123 | example), simply set the variable __IPYTHON__.gnuplot to your own gnuplot | |||
|
124 | instance object.""" | |||
|
125 | ||||
|
126 | gname = parameter_s.strip() | |||
|
127 | G = eval(gname,self.shell.user_ns) | |||
|
128 | self.shell.gnuplot = G | |||
|
129 | self.shell.user_ns.update({'plot':G.plot,'splot':G.splot,'plot2':G.plot2, | |||
|
130 | 'replot':G.replot,'hardcopy':G.hardcopy}) | |||
|
131 | ||||
|
132 | try: | |||
|
133 | __IPYTHON__ | |||
|
134 | except NameError: | |||
|
135 | pass | |||
|
136 | else: | |||
|
137 | # make the global Gnuplot instance known to IPython | |||
|
138 | __IPYTHON__.gnuplot = GRun.gp | |||
|
139 | __IPYTHON__.gnuplot.shell_first_time = 1 | |||
|
140 | ||||
|
141 | print """*** Type `gphelp` for help on the Gnuplot integration features.""" | |||
|
142 | ||||
|
143 | # Add the new magic functions to the class dict | |||
|
144 | from IPython.iplib import InteractiveShell | |||
|
145 | InteractiveShell.magic_gpc = magic_gpc | |||
|
146 | InteractiveShell.magic_gp_set_default = magic_gp_set_default | |||
|
147 | ||||
|
148 | #********************** End of file <GnuplotInteractive.py> ******************* |
@@ -0,0 +1,147 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Basic Gnuplot functionality for inclusion in other code. | |||
|
3 | ||||
|
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 | |||
|
6 | you to script plotting tasks in Python with a minimum of effort. A typical | |||
|
7 | usage would be: | |||
|
8 | ||||
|
9 | import IPython.GnuplotRuntime as GP # or some other short name | |||
|
10 | GP.gp.plot(GP.File('your_data.dat')) | |||
|
11 | ||||
|
12 | ||||
|
13 | This module exposes the following objects: | |||
|
14 | ||||
|
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 | |||
|
17 | typed in an interactive gnuplot window. | |||
|
18 | ||||
|
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 | |||
|
21 | plots. | |||
|
22 | ||||
|
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 | |||
|
25 | functions with improved versions (Gnuplot2 comes with IPython). | |||
|
26 | ||||
|
27 | - Data: alias to Gnuplot.Data, makes a PlotItem from array data. | |||
|
28 | ||||
|
29 | - File: alias to Gnuplot.File, makes a PlotItem from a file. | |||
|
30 | ||||
|
31 | - String: alias to Gnuplot.String, makes a PlotItem from a string formatted | |||
|
32 | exactly like a file for Gnuplot.File would be. | |||
|
33 | ||||
|
34 | - Func: alias to Gnuplot.Func, makes a PlotItem from a function string. | |||
|
35 | ||||
|
36 | - GridData: alias to Gnuplot.GridData, makes a PlotItem from grid data. | |||
|
37 | ||||
|
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). | |||
|
40 | ||||
|
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). | |||
|
43 | ||||
|
44 | This requires the Gnuplot.py module for interfacing Python with Gnuplot, which | |||
|
45 | can be downloaded from: | |||
|
46 | ||||
|
47 | http://gnuplot-py.sourceforge.net/ | |||
|
48 | ||||
|
49 | Inspired by a suggestion/request from Arnd Baecker. | |||
|
50 | ||||
|
51 | $Id: GnuplotRuntime.py 389 2004-10-09 07:59:30Z fperez $""" | |||
|
52 | ||||
|
53 | __all__ = ['Gnuplot','gp','gp_new','Data','File','Func','GridData', | |||
|
54 | 'pm3d_config','eps_fix_bbox'] | |||
|
55 | ||||
|
56 | import os,tempfile,sys | |||
|
57 | from IPython.genutils import getoutput | |||
|
58 | ||||
|
59 | #--------------------------------------------------------------------------- | |||
|
60 | # Notes on mouse support for Gnuplot.py | |||
|
61 | ||||
|
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 | |||
|
64 | # extremely useful feature. Mouse support is official as of gnuplot 4.0, | |||
|
65 | # released in April 2004. | |||
|
66 | ||||
|
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 | |||
|
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 | |||
|
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 | |||
|
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 | |||
|
75 | # using temp files). | |||
|
76 | ||||
|
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 | |||
|
79 | # the variable prefer_fifo_data to 0 in gp_unix.py. | |||
|
80 | ||||
|
81 | tmpname = tempfile.mktemp() | |||
|
82 | open(tmpname,'w').write('set mouse') | |||
|
83 | gnu_out = getoutput('gnuplot '+ tmpname) | |||
|
84 | os.unlink(tmpname) | |||
|
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." | |||
|
87 | gnuplot_mouse = 0 | |||
|
88 | else: | |||
|
89 | gnuplot_mouse = 1 | |||
|
90 | del tmpname,gnu_out | |||
|
91 | ||||
|
92 | # Default state for persistence of new gnuplot instances | |||
|
93 | if os.name in ['nt','dos'] or sys.platform == 'cygwin': | |||
|
94 | gnuplot_persist = 0 | |||
|
95 | else: | |||
|
96 | gnuplot_persist = 1 | |||
|
97 | ||||
|
98 | import IPython.Gnuplot2 as Gnuplot | |||
|
99 | ||||
|
100 | class NotGiven: pass | |||
|
101 | ||||
|
102 | def gp_new(mouse=NotGiven,persist=NotGiven): | |||
|
103 | """Return a new Gnuplot instance. | |||
|
104 | ||||
|
105 | The instance returned uses the improved methods defined in Gnuplot2. | |||
|
106 | ||||
|
107 | Options (boolean): | |||
|
108 | ||||
|
109 | - mouse: if unspecified, the module global gnuplot_mouse is used. | |||
|
110 | ||||
|
111 | - persist: if unspecified, the module global gnuplot_persist is used.""" | |||
|
112 | ||||
|
113 | if mouse is NotGiven: | |||
|
114 | mouse = gnuplot_mouse | |||
|
115 | if persist is NotGiven: | |||
|
116 | persist = gnuplot_persist | |||
|
117 | g = Gnuplot.Gnuplot(persist=persist) | |||
|
118 | if mouse: | |||
|
119 | g('set mouse') | |||
|
120 | return g | |||
|
121 | ||||
|
122 | # Global-level names. | |||
|
123 | ||||
|
124 | # A global Gnuplot instance for interactive use: | |||
|
125 | gp = gp_new() | |||
|
126 | ||||
|
127 | # Accessors for the main plot object constructors: | |||
|
128 | Data = Gnuplot.Data | |||
|
129 | File = Gnuplot.File | |||
|
130 | Func = Gnuplot.Func | |||
|
131 | String = Gnuplot.String | |||
|
132 | GridData = Gnuplot.GridData | |||
|
133 | ||||
|
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): | |||
|
136 | eps_fix_bbox = Gnuplot.eps_fix_bbox | |||
|
137 | ||||
|
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 | |||
|
140 | # below to suit your taste. | |||
|
141 | pm3d_config = """ | |||
|
142 | set pm3d solid | |||
|
143 | set hidden3d | |||
|
144 | unset surface | |||
|
145 | set isosamples 50 | |||
|
146 | """ | |||
|
147 | #******************** End of file <GnuplotRuntime.py> ****************** |
@@ -0,0 +1,253 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000). | |||
|
3 | ||||
|
4 | This module lets you quickly and conveniently interpolate values into | |||
|
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, | |||
|
7 | because this module allows subscripting, slicing, function calls, | |||
|
8 | attribute lookup, or arbitrary expressions. Variables and expressions | |||
|
9 | are evaluated in the namespace of the caller. | |||
|
10 | ||||
|
11 | The itpl() function returns the result of interpolating a string, and | |||
|
12 | printpl() prints out an interpolated string. Here are some examples: | |||
|
13 | ||||
|
14 | from Itpl import printpl | |||
|
15 | printpl("Here is a $string.") | |||
|
16 | printpl("Here is a $module.member.") | |||
|
17 | printpl("Here is an $object.member.") | |||
|
18 | printpl("Here is a $functioncall(with, arguments).") | |||
|
19 | printpl("Here is an ${arbitrary + expression}.") | |||
|
20 | printpl("Here is an $array[3] member.") | |||
|
21 | printpl("Here is a $dictionary['member'].") | |||
|
22 | ||||
|
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 | |||
|
25 | how to do interpolation: | |||
|
26 | ||||
|
27 | import Itpl | |||
|
28 | sys.stdout = Itpl.filter() | |||
|
29 | f = "fancy" | |||
|
30 | print "Isn't this $f?" | |||
|
31 | print "Standard output has been replaced with a $sys.stdout object." | |||
|
32 | sys.stdout = Itpl.unfilter() | |||
|
33 | print "Okay, back $to $normal." | |||
|
34 | ||||
|
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 | |||
|
37 | upon initialization; the evaluation and substitution can then be done | |||
|
38 | each time the instance is evaluated with str(instance). For example: | |||
|
39 | ||||
|
40 | from Itpl import Itpl | |||
|
41 | s = Itpl("Here is $foo.") | |||
|
42 | foo = 5 | |||
|
43 | print str(s) | |||
|
44 | foo = "bar" | |||
|
45 | print str(s) | |||
|
46 | ||||
|
47 | $Id: Itpl.py 542 2005-03-18 09:16:04Z fperez $ | |||
|
48 | """ # ' -> close an open quote for stupid emacs | |||
|
49 | ||||
|
50 | #***************************************************************************** | |||
|
51 | # | |||
|
52 | # Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org> | |||
|
53 | # | |||
|
54 | # | |||
|
55 | # Published under the terms of the MIT license, hereby reproduced: | |||
|
56 | # | |||
|
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 | |||
|
59 | # deal in the Software without restriction, including without limitation the | |||
|
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 | |||
|
62 | # furnished to do so, subject to the following conditions: | |||
|
63 | # | |||
|
64 | # The above copyright notice and this permission notice shall be included in | |||
|
65 | # all copies or substantial portions of the Software. | |||
|
66 | # | |||
|
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, | |||
|
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 | |||
|
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 | |||
|
73 | # IN THE SOFTWARE. | |||
|
74 | # | |||
|
75 | #***************************************************************************** | |||
|
76 | ||||
|
77 | __author__ = 'Ka-Ping Yee <ping@lfw.org>' | |||
|
78 | __license__ = 'MIT' | |||
|
79 | ||||
|
80 | import sys, string | |||
|
81 | from types import StringType | |||
|
82 | from tokenize import tokenprog | |||
|
83 | ||||
|
84 | class ItplError(ValueError): | |||
|
85 | def __init__(self, text, pos): | |||
|
86 | self.text = text | |||
|
87 | self.pos = pos | |||
|
88 | def __str__(self): | |||
|
89 | return "unfinished expression in %s at char %d" % ( | |||
|
90 | repr(self.text), self.pos) | |||
|
91 | ||||
|
92 | def matchorfail(text, pos): | |||
|
93 | match = tokenprog.match(text, pos) | |||
|
94 | if match is None: | |||
|
95 | raise ItplError(text, pos) | |||
|
96 | return match, match.end() | |||
|
97 | ||||
|
98 | class Itpl: | |||
|
99 | """Class representing a string with interpolation abilities. | |||
|
100 | ||||
|
101 | Upon creation, an instance works out what parts of the format | |||
|
102 | string are literal and what parts need to be evaluated. The | |||
|
103 | evaluation and substitution happens in the namespace of the | |||
|
104 | caller when str(instance) is called.""" | |||
|
105 | ||||
|
106 | def __init__(self, format): | |||
|
107 | """The single argument to this constructor is a format string. | |||
|
108 | ||||
|
109 | The format string is parsed according to the following rules: | |||
|
110 | ||||
|
111 | 1. A dollar sign and a name, possibly followed by any of: | |||
|
112 | - an open-paren, and anything up to the matching paren | |||
|
113 | - an open-bracket, and anything up to the matching bracket | |||
|
114 | - a period and a name | |||
|
115 | any number of times, is evaluated as a Python expression. | |||
|
116 | ||||
|
117 | 2. A dollar sign immediately followed by an open-brace, and | |||
|
118 | anything up to the matching close-brace, is evaluated as | |||
|
119 | a Python expression. | |||
|
120 | ||||
|
121 | 3. Outside of the expressions described in the above two rules, | |||
|
122 | two dollar signs in a row give you one literal dollar sign.""" | |||
|
123 | ||||
|
124 | if type(format) != StringType: | |||
|
125 | raise TypeError, "needs string initializer" | |||
|
126 | self.format = format | |||
|
127 | ||||
|
128 | namechars = "abcdefghijklmnopqrstuvwxyz" \ | |||
|
129 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; | |||
|
130 | chunks = [] | |||
|
131 | pos = 0 | |||
|
132 | ||||
|
133 | while 1: | |||
|
134 | dollar = string.find(format, "$", pos) | |||
|
135 | if dollar < 0: break | |||
|
136 | nextchar = format[dollar+1] | |||
|
137 | ||||
|
138 | if nextchar == "{": | |||
|
139 | chunks.append((0, format[pos:dollar])) | |||
|
140 | pos, level = dollar+2, 1 | |||
|
141 | while level: | |||
|
142 | match, pos = matchorfail(format, pos) | |||
|
143 | tstart, tend = match.regs[3] | |||
|
144 | token = format[tstart:tend] | |||
|
145 | if token == "{": level = level+1 | |||
|
146 | elif token == "}": level = level-1 | |||
|
147 | chunks.append((1, format[dollar+2:pos-1])) | |||
|
148 | ||||
|
149 | elif nextchar in namechars: | |||
|
150 | chunks.append((0, format[pos:dollar])) | |||
|
151 | match, pos = matchorfail(format, dollar+1) | |||
|
152 | while pos < len(format): | |||
|
153 | if format[pos] == "." and \ | |||
|
154 | pos+1 < len(format) and format[pos+1] in namechars: | |||
|
155 | match, pos = matchorfail(format, pos+1) | |||
|
156 | elif format[pos] in "([": | |||
|
157 | pos, level = pos+1, 1 | |||
|
158 | while level: | |||
|
159 | match, pos = matchorfail(format, pos) | |||
|
160 | tstart, tend = match.regs[3] | |||
|
161 | token = format[tstart:tend] | |||
|
162 | if token[0] in "([": level = level+1 | |||
|
163 | elif token[0] in ")]": level = level-1 | |||
|
164 | else: break | |||
|
165 | chunks.append((1, format[dollar+1:pos])) | |||
|
166 | ||||
|
167 | else: | |||
|
168 | chunks.append((0, format[pos:dollar+1])) | |||
|
169 | pos = dollar + 1 + (nextchar == "$") | |||
|
170 | ||||
|
171 | if pos < len(format): chunks.append((0, format[pos:])) | |||
|
172 | self.chunks = chunks | |||
|
173 | ||||
|
174 | def __repr__(self): | |||
|
175 | return "<Itpl %s >" % repr(self.format) | |||
|
176 | ||||
|
177 | def __str__(self): | |||
|
178 | """Evaluate and substitute the appropriate parts of the string.""" | |||
|
179 | ||||
|
180 | # We need to skip enough frames to get to the actual caller outside of | |||
|
181 | # Itpl. | |||
|
182 | frame = sys._getframe(1) | |||
|
183 | while frame.f_globals["__name__"] == __name__: frame = frame.f_back | |||
|
184 | loc, glob = frame.f_locals, frame.f_globals | |||
|
185 | ||||
|
186 | result = [] | |||
|
187 | for live, chunk in self.chunks: | |||
|
188 | if live: result.append(str(eval(chunk,glob,loc))) | |||
|
189 | else: result.append(chunk) | |||
|
190 | ||||
|
191 | return ''.join(result) | |||
|
192 | ||||
|
193 | class ItplNS(Itpl): | |||
|
194 | """Class representing a string with interpolation abilities. | |||
|
195 | ||||
|
196 | This inherits from Itpl, but at creation time a namespace is provided | |||
|
197 | where the evaluation will occur. The interpolation becomes a bit more | |||
|
198 | efficient, as no traceback needs to be extracte. It also allows the | |||
|
199 | caller to supply a different namespace for the interpolation to occur than | |||
|
200 | its own.""" | |||
|
201 | ||||
|
202 | def __init__(self, format,globals,locals=None): | |||
|
203 | """ItplNS(format,globals[,locals]) -> interpolating string instance. | |||
|
204 | ||||
|
205 | This constructor, besides a format string, takes a globals dictionary | |||
|
206 | and optionally a locals (which defaults to globals if not provided). | |||
|
207 | ||||
|
208 | For further details, see the Itpl constructor.""" | |||
|
209 | ||||
|
210 | if locals is None: | |||
|
211 | locals = globals | |||
|
212 | self.globals = globals | |||
|
213 | self.locals = locals | |||
|
214 | Itpl.__init__(self,format) | |||
|
215 | ||||
|
216 | def __str__(self): | |||
|
217 | """Evaluate and substitute the appropriate parts of the string.""" | |||
|
218 | glob = self.globals | |||
|
219 | loc = self.locals | |||
|
220 | result = [] | |||
|
221 | for live, chunk in self.chunks: | |||
|
222 | if live: result.append(str(eval(chunk,glob,loc))) | |||
|
223 | else: result.append(chunk) | |||
|
224 | return ''.join(result) | |||
|
225 | ||||
|
226 | # utilities for fast printing | |||
|
227 | def itpl(text): return str(Itpl(text)) | |||
|
228 | def printpl(text): print itpl(text) | |||
|
229 | # versions with namespace | |||
|
230 | def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals)) | |||
|
231 | def printplns(text,globals,locals=None): print itplns(text,globals,locals) | |||
|
232 | ||||
|
233 | class ItplFile: | |||
|
234 | """A file object that filters each write() through an interpolator.""" | |||
|
235 | def __init__(self, file): self.file = file | |||
|
236 | def __repr__(self): return "<interpolated " + repr(self.file) + ">" | |||
|
237 | def __getattr__(self, attr): return getattr(self.file, attr) | |||
|
238 | def write(self, text): self.file.write(str(Itpl(text))) | |||
|
239 | ||||
|
240 | def filter(file=sys.stdout): | |||
|
241 | """Return an ItplFile that filters writes to the given file object. | |||
|
242 | ||||
|
243 | 'file = filter(file)' replaces 'file' with a filtered object that | |||
|
244 | has a write() method. When called with no argument, this creates | |||
|
245 | a filter to sys.stdout.""" | |||
|
246 | return ItplFile(file) | |||
|
247 | ||||
|
248 | def unfilter(ifile=None): | |||
|
249 | """Return the original file that corresponds to the given ItplFile. | |||
|
250 | ||||
|
251 | 'file = unfilter(file)' undoes the effect of 'file = filter(file)'. | |||
|
252 | 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'.""" | |||
|
253 | return ifile and ifile.file or sys.stdout.file |
@@ -0,0 +1,185 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | Logger class for IPython's logging facilities. | |||
|
4 | ||||
|
5 | $Id: Logger.py 430 2004-11-30 08:52:05Z fperez $ | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #***************************************************************************** | |||
|
9 | # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and | |||
|
10 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
11 | # | |||
|
12 | # Distributed under the terms of the BSD License. The full license is in | |||
|
13 | # the file COPYING, distributed as part of this software. | |||
|
14 | #***************************************************************************** | |||
|
15 | ||||
|
16 | #**************************************************************************** | |||
|
17 | # Modules and globals | |||
|
18 | ||||
|
19 | from IPython import Release | |||
|
20 | __author__ = '%s <%s>\n%s <%s>' % \ | |||
|
21 | ( Release.authors['Janko'] + Release.authors['Fernando'] ) | |||
|
22 | __license__ = Release.license | |||
|
23 | ||||
|
24 | # Python standard modules | |||
|
25 | import os,sys,glob | |||
|
26 | ||||
|
27 | # Homebrewed | |||
|
28 | from IPython.genutils import * | |||
|
29 | ||||
|
30 | #**************************************************************************** | |||
|
31 | # FIXME: The logger class shouldn't be a mixin, it throws too many things into | |||
|
32 | # the InteractiveShell namespace. Rather make it a standalone tool, and create | |||
|
33 | # a Logger instance in InteractiveShell that uses it. Doing this will require | |||
|
34 | # tracking down a *lot* of nasty uses of the Logger attributes in | |||
|
35 | # InteractiveShell, but will clean up things quite a bit. | |||
|
36 | ||||
|
37 | class Logger: | |||
|
38 | """A Logfile Mixin class with different policies for file creation""" | |||
|
39 | ||||
|
40 | # FIXME: once this isn't a mixin, log_ns should just be 'namespace', since the | |||
|
41 | # names won't collide anymore. | |||
|
42 | def __init__(self,log_ns): | |||
|
43 | self._i00,self._i,self._ii,self._iii = '','','','' | |||
|
44 | self.do_full_cache = 0 # FIXME. There's also a do_full.. in OutputCache | |||
|
45 | self.log_ns = log_ns | |||
|
46 | # defaults | |||
|
47 | self.LOGMODE = 'backup' | |||
|
48 | self.defname = 'logfile' | |||
|
49 | ||||
|
50 | def create_log(self,header='',fname='',defname='.Logger.log'): | |||
|
51 | """Generate a new log-file with a default header""" | |||
|
52 | if fname: | |||
|
53 | self.LOG = fname | |||
|
54 | ||||
|
55 | if self.LOG: | |||
|
56 | self.logfname = self.LOG | |||
|
57 | else: | |||
|
58 | self.logfname = defname | |||
|
59 | ||||
|
60 | if self.LOGMODE == 'over': | |||
|
61 | if os.path.isfile(self.logfname): | |||
|
62 | os.remove(self.logfname) | |||
|
63 | self.logfile = open(self.logfname,'w') | |||
|
64 | if self.LOGMODE == 'backup': | |||
|
65 | if os.path.isfile(self.logfname): | |||
|
66 | backup_logname = self.logfname+'~' | |||
|
67 | # Manually remove any old backup, since os.rename may fail | |||
|
68 | # under Windows. | |||
|
69 | if os.path.isfile(backup_logname): | |||
|
70 | os.remove(backup_logname) | |||
|
71 | os.rename(self.logfname,backup_logname) | |||
|
72 | self.logfile = open(self.logfname,'w') | |||
|
73 | elif self.LOGMODE == 'global': | |||
|
74 | self.logfname = os.path.join(self.home_dir, self.defname) | |||
|
75 | self.logfile = open(self.logfname, 'a') | |||
|
76 | self.LOG = self.logfname | |||
|
77 | elif self.LOGMODE == 'rotate': | |||
|
78 | if os.path.isfile(self.logfname): | |||
|
79 | if os.path.isfile(self.logfname+'.001~'): | |||
|
80 | old = glob.glob(self.logfname+'.*~') | |||
|
81 | old.sort() | |||
|
82 | old.reverse() | |||
|
83 | for f in old: | |||
|
84 | root, ext = os.path.splitext(f) | |||
|
85 | num = int(ext[1:-1])+1 | |||
|
86 | os.rename(f, root+'.'+`num`.zfill(3)+'~') | |||
|
87 | os.rename(self.logfname, self.logfname+'.001~') | |||
|
88 | self.logfile = open(self.logfname,'w') | |||
|
89 | elif self.LOGMODE == 'append': | |||
|
90 | self.logfile = open(self.logfname,'a') | |||
|
91 | ||||
|
92 | if self.LOGMODE != 'append': | |||
|
93 | self.logfile.write(header) | |||
|
94 | self.logfile.flush() | |||
|
95 | ||||
|
96 | def logstart(self, header='',parameter_s = ''): | |||
|
97 | if not hasattr(self, 'LOG'): | |||
|
98 | logfname = self.LOG or parameter_s or './'+self.defname | |||
|
99 | self.create_log(header,logfname) | |||
|
100 | elif parameter_s and hasattr(self,'logfname') and \ | |||
|
101 | parameter_s != self.logfname: | |||
|
102 | self.close_log() | |||
|
103 | self.create_log(header,parameter_s) | |||
|
104 | ||||
|
105 | self._dolog = 1 | |||
|
106 | ||||
|
107 | def switch_log(self,val): | |||
|
108 | """Switch logging on/off. val should be ONLY 0 or 1.""" | |||
|
109 | ||||
|
110 | if not val in [0,1]: | |||
|
111 | raise ValueError, \ | |||
|
112 | 'Call switch_log ONLY with 0 or 1 as argument, not with:',val | |||
|
113 | ||||
|
114 | label = {0:'OFF',1:'ON'} | |||
|
115 | ||||
|
116 | try: | |||
|
117 | _ = self.logfile | |||
|
118 | except AttributeError: | |||
|
119 | print """ | |||
|
120 | Logging hasn't been started yet (use %logstart for that). | |||
|
121 | ||||
|
122 | %logon/%logoff are for temporarily starting and stopping logging for a logfile | |||
|
123 | which already exists. But you must first start the logging process with | |||
|
124 | %logstart (optionally giving a logfile name).""" | |||
|
125 | ||||
|
126 | else: | |||
|
127 | if self._dolog == val: | |||
|
128 | print 'Logging is already',label[val] | |||
|
129 | else: | |||
|
130 | print 'Switching logging',label[val] | |||
|
131 | self._dolog = 1 - self._dolog | |||
|
132 | ||||
|
133 | def logstate(self): | |||
|
134 | """Print a status message about the logger.""" | |||
|
135 | try: | |||
|
136 | logfile = self.logfname | |||
|
137 | except: | |||
|
138 | print 'Logging has not been activated.' | |||
|
139 | else: | |||
|
140 | state = self._dolog and 'active' or 'temporarily suspended' | |||
|
141 | print """ | |||
|
142 | File:\t%s | |||
|
143 | Mode:\t%s | |||
|
144 | State:\t%s """ % (logfile,self.LOGMODE,state) | |||
|
145 | ||||
|
146 | ||||
|
147 | def log(self, line,continuation=None): | |||
|
148 | """Write the line to a log and create input cache variables _i*.""" | |||
|
149 | ||||
|
150 | # update the auto _i tables | |||
|
151 | #print '***logging line',line # dbg | |||
|
152 | #print '***cache_count', self.outputcache.prompt_count # dbg | |||
|
153 | input_hist = self.log_ns['_ih'] | |||
|
154 | if not continuation and line: | |||
|
155 | self._iii = self._ii | |||
|
156 | self._ii = self._i | |||
|
157 | self._i = self._i00 | |||
|
158 | # put back the final \n of every input line | |||
|
159 | self._i00 = line+'\n' | |||
|
160 | #print 'Logging input:<%s>' % line # dbg | |||
|
161 | input_hist.append(self._i00) | |||
|
162 | ||||
|
163 | # hackish access to top-level namespace to create _i1,_i2... dynamically | |||
|
164 | to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii} | |||
|
165 | if self.do_full_cache: | |||
|
166 | in_num = self.outputcache.prompt_count | |||
|
167 | # add blank lines if the input cache fell out of sync. This can happen | |||
|
168 | # for embedded instances which get killed via C-D and then get resumed. | |||
|
169 | while in_num >= len(input_hist): | |||
|
170 | input_hist.append('\n') | |||
|
171 | new_i = '_i%s' % in_num | |||
|
172 | if continuation: | |||
|
173 | self._i00 = '%s%s\n' % (self.log_ns[new_i],line) | |||
|
174 | input_hist[in_num] = self._i00 | |||
|
175 | to_main[new_i] = self._i00 | |||
|
176 | self.log_ns.update(to_main) | |||
|
177 | ||||
|
178 | if self._dolog and line: | |||
|
179 | self.logfile.write(line+'\n') | |||
|
180 | self.logfile.flush() | |||
|
181 | ||||
|
182 | def close_log(self): | |||
|
183 | if hasattr(self, 'logfile'): | |||
|
184 | self.logfile.close() | |||
|
185 | self.logfname = '' |
This diff has been collapsed as it changes many lines, (2490 lines changed) Show them Hide them | |||||
@@ -0,0 +1,2490 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Magic functions for InteractiveShell. | |||
|
3 | ||||
|
4 | $Id: Magic.py 583 2005-05-13 21:20:33Z fperez $""" | |||
|
5 | ||||
|
6 | #***************************************************************************** | |||
|
7 | # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and | |||
|
8 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
9 | # | |||
|
10 | # Distributed under the terms of the BSD License. The full license is in | |||
|
11 | # the file COPYING, distributed as part of this software. | |||
|
12 | #***************************************************************************** | |||
|
13 | ||||
|
14 | #**************************************************************************** | |||
|
15 | # Modules and globals | |||
|
16 | ||||
|
17 | from IPython import Release | |||
|
18 | __author__ = '%s <%s>\n%s <%s>' % \ | |||
|
19 | ( Release.authors['Janko'] + Release.authors['Fernando'] ) | |||
|
20 | __license__ = Release.license | |||
|
21 | ||||
|
22 | # Python standard modules | |||
|
23 | import __builtin__ | |||
|
24 | import os,sys,inspect,pydoc,re,tempfile,shlex,pdb,bdb,time | |||
|
25 | try: | |||
|
26 | import profile,pstats | |||
|
27 | except ImportError: | |||
|
28 | profile = pstats = None | |||
|
29 | from getopt import getopt | |||
|
30 | from pprint import pprint, pformat | |||
|
31 | from cStringIO import StringIO | |||
|
32 | ||||
|
33 | # Homebrewed | |||
|
34 | from IPython.Struct import Struct | |||
|
35 | from IPython.Itpl import Itpl, itpl, printpl,itplns | |||
|
36 | from IPython.FakeModule import FakeModule | |||
|
37 | from IPython import OInspect | |||
|
38 | from IPython.genutils import * | |||
|
39 | ||||
|
40 | # Globals to be set later by Magic constructor | |||
|
41 | MAGIC_PREFIX = '' | |||
|
42 | MAGIC_ESCAPE = '' | |||
|
43 | ||||
|
44 | #*************************************************************************** | |||
|
45 | # Utility functions | |||
|
46 | def magic2python(cmd): | |||
|
47 | """Convert a command string of magic syntax to valid Python code.""" | |||
|
48 | ||||
|
49 | if cmd.startswith('#'+MAGIC_ESCAPE) or \ | |||
|
50 | cmd.startswith(MAGIC_ESCAPE): | |||
|
51 | if cmd[0]=='#': | |||
|
52 | cmd = cmd[1:] | |||
|
53 | # we need to return the proper line end later | |||
|
54 | if cmd[-1] == '\n': | |||
|
55 | endl = '\n' | |||
|
56 | else: | |||
|
57 | endl = '' | |||
|
58 | try: | |||
|
59 | func,args = cmd[1:].split(' ',1) | |||
|
60 | except: | |||
|
61 | func,args = cmd[1:].rstrip(),'' | |||
|
62 | args = args.replace('"','\\"').replace("'","\\'").rstrip() | |||
|
63 | return '%s%s ("%s")%s' % (MAGIC_PREFIX,func,args,endl) | |||
|
64 | else: | |||
|
65 | return cmd | |||
|
66 | ||||
|
67 | def on_off(tag): | |||
|
68 | """Return an ON/OFF string for a 1/0 input. Simple utility function.""" | |||
|
69 | return ['OFF','ON'][tag] | |||
|
70 | ||||
|
71 | def get_py_filename(name): | |||
|
72 | """Return a valid python filename in the current directory. | |||
|
73 | ||||
|
74 | If the given name is not a file, it adds '.py' and searches again. | |||
|
75 | Raises IOError with an informative message if the file isn't found.""" | |||
|
76 | ||||
|
77 | name = os.path.expanduser(name) | |||
|
78 | if not os.path.isfile(name) and not name.endswith('.py'): | |||
|
79 | name += '.py' | |||
|
80 | if os.path.isfile(name): | |||
|
81 | return name | |||
|
82 | else: | |||
|
83 | raise IOError,'File `%s` not found.' % name | |||
|
84 | ||||
|
85 | # Try to use shlex.split for converting an input string into a sys.argv-type | |||
|
86 | # list. This appeared in Python 2.3, so here's a quick backport for 2.2. | |||
|
87 | try: | |||
|
88 | shlex_split = shlex.split | |||
|
89 | except AttributeError: | |||
|
90 | _quotesre = re.compile(r'[\'"](.*)[\'"]') | |||
|
91 | _wordchars = ('abcdfeghijklmnopqrstuvwxyz' | |||
|
92 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.~*?' | |||
|
93 | 'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' | |||
|
94 | 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ%s' | |||
|
95 | % os.sep) | |||
|
96 | ||||
|
97 | def shlex_split(s): | |||
|
98 | """Simplified backport to Python 2.2 of shlex.split(). | |||
|
99 | ||||
|
100 | This is a quick and dirty hack, since the shlex module under 2.2 lacks | |||
|
101 | several of the features needed to really match the functionality of | |||
|
102 | shlex.split() in 2.3.""" | |||
|
103 | ||||
|
104 | lex = shlex.shlex(StringIO(s)) | |||
|
105 | # Try to get options, extensions and path separators as characters | |||
|
106 | lex.wordchars = _wordchars | |||
|
107 | lex.commenters = '' | |||
|
108 | # Make a list out of the lexer by hand, since in 2.2 it's not an | |||
|
109 | # iterator. | |||
|
110 | lout = [] | |||
|
111 | while 1: | |||
|
112 | token = lex.get_token() | |||
|
113 | if token == '': | |||
|
114 | break | |||
|
115 | # Try to handle quoted tokens correctly | |||
|
116 | quotes = _quotesre.match(token) | |||
|
117 | if quotes: | |||
|
118 | token = quotes.group(1) | |||
|
119 | lout.append(token) | |||
|
120 | return lout | |||
|
121 | ||||
|
122 | #**************************************************************************** | |||
|
123 | # Utility classes | |||
|
124 | class Macro: | |||
|
125 | """Simple class to store the value of macros as strings. | |||
|
126 | ||||
|
127 | This allows us to later exec them by checking when something is an | |||
|
128 | instance of this class.""" | |||
|
129 | ||||
|
130 | def __init__(self,cmds): | |||
|
131 | """Build a macro from a list of commands.""" | |||
|
132 | ||||
|
133 | # Since the list may include multi-line entries, first make sure that | |||
|
134 | # they've been all broken up before passing it to magic2python | |||
|
135 | cmdlist = map(magic2python,''.join(cmds).split('\n')) | |||
|
136 | self.value = '\n'.join(cmdlist) | |||
|
137 | ||||
|
138 | def __str__(self): | |||
|
139 | return self.value | |||
|
140 | ||||
|
141 | #*************************************************************************** | |||
|
142 | # Main class implementing Magic functionality | |||
|
143 | class Magic: | |||
|
144 | """Magic functions for InteractiveShell. | |||
|
145 | ||||
|
146 | Shell functions which can be reached as %function_name. All magic | |||
|
147 | functions should accept a string, which they can parse for their own | |||
|
148 | needs. This can make some functions easier to type, eg `%cd ../` | |||
|
149 | vs. `%cd("../")` | |||
|
150 | ||||
|
151 | ALL definitions MUST begin with the prefix magic_. The user won't need it | |||
|
152 | at the command line, but it is is needed in the definition. """ | |||
|
153 | ||||
|
154 | # class globals | |||
|
155 | auto_status = ['Automagic is OFF, % prefix IS needed for magic functions.', | |||
|
156 | 'Automagic is ON, % prefix NOT needed for magic functions.'] | |||
|
157 | ||||
|
158 | #...................................................................... | |||
|
159 | # some utility functions | |||
|
160 | ||||
|
161 | def __init__(self,shell): | |||
|
162 | # XXX This is hackish, clean up later to avoid these messy globals | |||
|
163 | global MAGIC_PREFIX, MAGIC_ESCAPE | |||
|
164 | ||||
|
165 | self.options_table = {} | |||
|
166 | MAGIC_PREFIX = shell.name+'.magic_' | |||
|
167 | MAGIC_ESCAPE = shell.ESC_MAGIC | |||
|
168 | if profile is None: | |||
|
169 | self.magic_prun = self.profile_missing_notice | |||
|
170 | ||||
|
171 | def profile_missing_notice(self, *args, **kwargs): | |||
|
172 | error("""\ | |||
|
173 | The profile module could not be found. If you are a Debian user, | |||
|
174 | it has been removed from the standard Debian package because of its non-free | |||
|
175 | license. To use profiling, please install"python2.3-profiler" from non-free.""") | |||
|
176 | ||||
|
177 | def default_option(self,fn,optstr): | |||
|
178 | """Make an entry in the options_table for fn, with value optstr""" | |||
|
179 | ||||
|
180 | if fn not in self.lsmagic(): | |||
|
181 | error("%s is not a magic function" % fn) | |||
|
182 | self.options_table[fn] = optstr | |||
|
183 | ||||
|
184 | def lsmagic(self): | |||
|
185 | """Return a list of currently available magic functions. | |||
|
186 | ||||
|
187 | Gives a list of the bare names after mangling (['ls','cd', ...], not | |||
|
188 | ['magic_ls','magic_cd',...]""" | |||
|
189 | ||||
|
190 | # FIXME. This needs a cleanup, in the way the magics list is built. | |||
|
191 | ||||
|
192 | # magics in class definition | |||
|
193 | class_magic = lambda fn: fn.startswith('magic_') and \ | |||
|
194 | callable(Magic.__dict__[fn]) | |||
|
195 | # in instance namespace (run-time user additions) | |||
|
196 | inst_magic = lambda fn: fn.startswith('magic_') and \ | |||
|
197 | callable(self.__dict__[fn]) | |||
|
198 | # and bound magics by user (so they can access self): | |||
|
199 | inst_bound_magic = lambda fn: fn.startswith('magic_') and \ | |||
|
200 | callable(self.__class__.__dict__[fn]) | |||
|
201 | magics = filter(class_magic,Magic.__dict__.keys()) + \ | |||
|
202 | filter(inst_magic,self.__dict__.keys()) + \ | |||
|
203 | filter(inst_bound_magic,self.__class__.__dict__.keys()) | |||
|
204 | out = [] | |||
|
205 | for fn in magics: | |||
|
206 | out.append(fn.replace('magic_','',1)) | |||
|
207 | out.sort() | |||
|
208 | return out | |||
|
209 | ||||
|
210 | def set_shell(self,shell): | |||
|
211 | self.shell = shell | |||
|
212 | self.alias_table = shell.alias_table | |||
|
213 | ||||
|
214 | def extract_input_slices(self,slices): | |||
|
215 | """Return as a string a set of input history slices. | |||
|
216 | ||||
|
217 | The set of slices is given as a list of strings (like ['1','4:8','9'], | |||
|
218 | since this function is for use by magic functions which get their | |||
|
219 | arguments as strings.""" | |||
|
220 | ||||
|
221 | cmds = [] | |||
|
222 | for chunk in slices: | |||
|
223 | if ':' in chunk: | |||
|
224 | ini,fin = map(int,chunk.split(':')) | |||
|
225 | else: | |||
|
226 | ini = int(chunk) | |||
|
227 | fin = ini+1 | |||
|
228 | cmds.append(self.shell.input_hist[ini:fin]) | |||
|
229 | return cmds | |||
|
230 | ||||
|
231 | def _ofind(self,oname): | |||
|
232 | """Find an object in the available namespaces. | |||
|
233 | ||||
|
234 | self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic | |||
|
235 | ||||
|
236 | Has special code to detect magic functions. | |||
|
237 | """ | |||
|
238 | ||||
|
239 | oname = oname.strip() | |||
|
240 | ||||
|
241 | # Namespaces to search in: | |||
|
242 | user_ns = self.shell.user_ns | |||
|
243 | internal_ns = self.shell.internal_ns | |||
|
244 | builtin_ns = __builtin__.__dict__ | |||
|
245 | alias_ns = self.shell.alias_table | |||
|
246 | ||||
|
247 | # Put them in a list. The order is important so that we find things in | |||
|
248 | # the same order that Python finds them. | |||
|
249 | namespaces = [ ('Interactive',user_ns), | |||
|
250 | ('IPython internal',internal_ns), | |||
|
251 | ('Python builtin',builtin_ns), | |||
|
252 | ('Alias',alias_ns), | |||
|
253 | ] | |||
|
254 | ||||
|
255 | # initialize results to 'null' | |||
|
256 | found = 0; obj = None; ospace = None; ds = None; | |||
|
257 | ismagic = 0; isalias = 0 | |||
|
258 | ||||
|
259 | # Look for the given name by splitting it in parts. If the head is | |||
|
260 | # found, then we look for all the remaining parts as members, and only | |||
|
261 | # declare success if we can find them all. | |||
|
262 | oname_parts = oname.split('.') | |||
|
263 | oname_head, oname_rest = oname_parts[0],oname_parts[1:] | |||
|
264 | for nsname,ns in namespaces: | |||
|
265 | try: | |||
|
266 | obj = ns[oname_head] | |||
|
267 | except KeyError: | |||
|
268 | continue | |||
|
269 | else: | |||
|
270 | for part in oname_rest: | |||
|
271 | try: | |||
|
272 | obj = getattr(obj,part) | |||
|
273 | except: | |||
|
274 | # Blanket except b/c some badly implemented objects | |||
|
275 | # allow __getattr__ to raise exceptions other than | |||
|
276 | # AttributeError, which then crashes IPython. | |||
|
277 | break | |||
|
278 | else: | |||
|
279 | # If we finish the for loop (no break), we got all members | |||
|
280 | found = 1 | |||
|
281 | ospace = nsname | |||
|
282 | if ns == alias_ns: | |||
|
283 | isalias = 1 | |||
|
284 | break # namespace loop | |||
|
285 | ||||
|
286 | # Try to see if it's magic | |||
|
287 | if not found: | |||
|
288 | if oname.startswith(self.shell.ESC_MAGIC): | |||
|
289 | oname = oname[1:] | |||
|
290 | obj = getattr(self,'magic_'+oname,None) | |||
|
291 | if obj is not None: | |||
|
292 | found = 1 | |||
|
293 | ospace = 'IPython internal' | |||
|
294 | ismagic = 1 | |||
|
295 | ||||
|
296 | # Last try: special-case some literals like '', [], {}, etc: | |||
|
297 | if not found and oname_head in ["''",'""','[]','{}','()']: | |||
|
298 | obj = eval(oname_head) | |||
|
299 | found = 1 | |||
|
300 | ospace = 'Interactive' | |||
|
301 | ||||
|
302 | return {'found':found, 'obj':obj, 'namespace':ospace, | |||
|
303 | 'ismagic':ismagic, 'isalias':isalias} | |||
|
304 | ||||
|
305 | def arg_err(self,func): | |||
|
306 | """Print docstring if incorrect arguments were passed""" | |||
|
307 | print 'Error in arguments:' | |||
|
308 | print OInspect.getdoc(func) | |||
|
309 | ||||
|
310 | ||||
|
311 | def format_latex(self,str): | |||
|
312 | """Format a string for latex inclusion.""" | |||
|
313 | ||||
|
314 | # Characters that need to be escaped for latex: | |||
|
315 | escape_re = re.compile(r'(%|_|\$)',re.MULTILINE) | |||
|
316 | # Magic command names as headers: | |||
|
317 | cmd_name_re = re.compile(r'^(%s.*?):' % self.shell.ESC_MAGIC, | |||
|
318 | re.MULTILINE) | |||
|
319 | # Magic commands | |||
|
320 | cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % self.shell.ESC_MAGIC, | |||
|
321 | re.MULTILINE) | |||
|
322 | # Paragraph continue | |||
|
323 | par_re = re.compile(r'\\$',re.MULTILINE) | |||
|
324 | ||||
|
325 | str = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',str) | |||
|
326 | str = cmd_re.sub(r'\\texttt{\g<cmd>}',str) | |||
|
327 | str = par_re.sub(r'\\\\',str) | |||
|
328 | str = escape_re.sub(r'\\\1',str) | |||
|
329 | return str | |||
|
330 | ||||
|
331 | def format_screen(self,str): | |||
|
332 | """Format a string for screen printing. | |||
|
333 | ||||
|
334 | This removes some latex-type format codes.""" | |||
|
335 | # Paragraph continue | |||
|
336 | par_re = re.compile(r'\\$',re.MULTILINE) | |||
|
337 | str = par_re.sub('',str) | |||
|
338 | return str | |||
|
339 | ||||
|
340 | def parse_options(self,arg_str,opt_str,*long_opts,**kw): | |||
|
341 | """Parse options passed to an argument string. | |||
|
342 | ||||
|
343 | The interface is similar to that of getopt(), but it returns back a | |||
|
344 | Struct with the options as keys and the stripped argument string still | |||
|
345 | as a string. | |||
|
346 | ||||
|
347 | arg_str is quoted as a true sys.argv vector by calling on the fly a | |||
|
348 | python process in a subshell. This allows us to easily expand | |||
|
349 | variables, glob files, quote arguments, etc, with all the power and | |||
|
350 | correctness of the underlying system shell. | |||
|
351 | ||||
|
352 | Options: | |||
|
353 | -mode: default 'string'. If given as 'list', the argument string is | |||
|
354 | returned as a list (split on whitespace) instead of a string. | |||
|
355 | ||||
|
356 | -list_all: put all option values in lists. Normally only options | |||
|
357 | appearing more than once are put in a list.""" | |||
|
358 | ||||
|
359 | # inject default options at the beginning of the input line | |||
|
360 | caller = sys._getframe(1).f_code.co_name.replace('magic_','') | |||
|
361 | arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str) | |||
|
362 | ||||
|
363 | mode = kw.get('mode','string') | |||
|
364 | if mode not in ['string','list']: | |||
|
365 | raise ValueError,'incorrect mode given: %s' % mode | |||
|
366 | # Get options | |||
|
367 | list_all = kw.get('list_all',0) | |||
|
368 | ||||
|
369 | # Check if we have more than one argument to warrant extra processing: | |||
|
370 | odict = {} # Dictionary with options | |||
|
371 | args = arg_str.split() | |||
|
372 | if len(args) >= 1: | |||
|
373 | # If the list of inputs only has 0 or 1 thing in it, there's no | |||
|
374 | # need to look for options | |||
|
375 | argv = shlex_split(arg_str) | |||
|
376 | # Do regular option processing | |||
|
377 | opts,args = getopt(argv,opt_str,*long_opts) | |||
|
378 | for o,a in opts: | |||
|
379 | if o.startswith('--'): | |||
|
380 | o = o[2:] | |||
|
381 | else: | |||
|
382 | o = o[1:] | |||
|
383 | try: | |||
|
384 | odict[o].append(a) | |||
|
385 | except AttributeError: | |||
|
386 | odict[o] = [odict[o],a] | |||
|
387 | except KeyError: | |||
|
388 | if list_all: | |||
|
389 | odict[o] = [a] | |||
|
390 | else: | |||
|
391 | odict[o] = a | |||
|
392 | ||||
|
393 | # Prepare opts,args for return | |||
|
394 | opts = Struct(odict) | |||
|
395 | if mode == 'string': | |||
|
396 | args = ' '.join(args) | |||
|
397 | ||||
|
398 | return opts,args | |||
|
399 | ||||
|
400 | #...................................................................... | |||
|
401 | # And now the actual magic functions | |||
|
402 | ||||
|
403 | # Functions for IPython shell work (vars,funcs, config, etc) | |||
|
404 | def magic_lsmagic(self, parameter_s = ''): | |||
|
405 | """List currently available magic functions.""" | |||
|
406 | mesc = self.shell.ESC_MAGIC | |||
|
407 | print 'Available magic functions:\n'+mesc+\ | |||
|
408 | (' '+mesc).join(self.lsmagic()) | |||
|
409 | print '\n' + Magic.auto_status[self.shell.rc.automagic] | |||
|
410 | return None | |||
|
411 | ||||
|
412 | def magic_magic(self, parameter_s = ''): | |||
|
413 | """Print information about the magic function system.""" | |||
|
414 | ||||
|
415 | mode = '' | |||
|
416 | try: | |||
|
417 | if parameter_s.split()[0] == '-latex': | |||
|
418 | mode = 'latex' | |||
|
419 | except: | |||
|
420 | pass | |||
|
421 | ||||
|
422 | magic_docs = [] | |||
|
423 | for fname in self.lsmagic(): | |||
|
424 | mname = 'magic_' + fname | |||
|
425 | for space in (Magic,self,self.__class__): | |||
|
426 | try: | |||
|
427 | fn = space.__dict__[mname] | |||
|
428 | except KeyError: | |||
|
429 | pass | |||
|
430 | else: | |||
|
431 | break | |||
|
432 | magic_docs.append('%s%s:\n\t%s\n' %(self.shell.ESC_MAGIC, | |||
|
433 | fname,fn.__doc__)) | |||
|
434 | magic_docs = ''.join(magic_docs) | |||
|
435 | ||||
|
436 | if mode == 'latex': | |||
|
437 | print self.format_latex(magic_docs) | |||
|
438 | return | |||
|
439 | else: | |||
|
440 | magic_docs = self.format_screen(magic_docs) | |||
|
441 | ||||
|
442 | outmsg = """ | |||
|
443 | IPython's 'magic' functions | |||
|
444 | =========================== | |||
|
445 | ||||
|
446 | The magic function system provides a series of functions which allow you to | |||
|
447 | control the behavior of IPython itself, plus a lot of system-type | |||
|
448 | features. All these functions are prefixed with a % character, but parameters | |||
|
449 | are given without parentheses or quotes. | |||
|
450 | ||||
|
451 | NOTE: If you have 'automagic' enabled (via the command line option or with the | |||
|
452 | %automagic function), you don't need to type in the % explicitly. By default, | |||
|
453 | IPython ships with automagic on, so you should only rarely need the % escape. | |||
|
454 | ||||
|
455 | Example: typing '%cd mydir' (without the quotes) changes you working directory | |||
|
456 | to 'mydir', if it exists. | |||
|
457 | ||||
|
458 | You can define your own magic functions to extend the system. See the supplied | |||
|
459 | ipythonrc and example-magic.py files for details (in your ipython | |||
|
460 | configuration directory, typically $HOME/.ipython/). | |||
|
461 | ||||
|
462 | You can also define your own aliased names for magic functions. In your | |||
|
463 | ipythonrc file, placing a line like: | |||
|
464 | ||||
|
465 | execute __IPYTHON__.magic_pf = __IPYTHON__.magic_profile | |||
|
466 | ||||
|
467 | will define %pf as a new name for %profile. | |||
|
468 | ||||
|
469 | You can also call magics in code using the ipmagic() function, which IPython | |||
|
470 | automatically adds to the builtin namespace. Type 'ipmagic?' for details. | |||
|
471 | ||||
|
472 | For a list of the available magic functions, use %lsmagic. For a description | |||
|
473 | of any of them, type %magic_name?, e.g. '%cd?'. | |||
|
474 | ||||
|
475 | Currently the magic system has the following functions:\n""" | |||
|
476 | ||||
|
477 | mesc = self.shell.ESC_MAGIC | |||
|
478 | outmsg = ("%s\n%s\n\nSummary of magic functions (from %slsmagic):" | |||
|
479 | "\n\n%s%s\n\n%s" % (outmsg, | |||
|
480 | magic_docs,mesc,mesc, | |||
|
481 | (' '+mesc).join(self.lsmagic()), | |||
|
482 | Magic.auto_status[self.shell.rc.automagic] ) ) | |||
|
483 | ||||
|
484 | page(outmsg,screen_lines=self.shell.rc.screen_length) | |||
|
485 | ||||
|
486 | def magic_automagic(self, parameter_s = ''): | |||
|
487 | """Make magic functions callable without having to type the initial %. | |||
|
488 | ||||
|
489 | Toggles on/off (when off, you must call it as %automagic, of | |||
|
490 | course). Note that magic functions have lowest priority, so if there's | |||
|
491 | a variable whose name collides with that of a magic fn, automagic | |||
|
492 | won't work for that function (you get the variable instead). However, | |||
|
493 | if you delete the variable (del var), the previously shadowed magic | |||
|
494 | function becomes visible to automagic again.""" | |||
|
495 | ||||
|
496 | rc = self.shell.rc | |||
|
497 | rc.automagic = not rc.automagic | |||
|
498 | print '\n' + Magic.auto_status[rc.automagic] | |||
|
499 | ||||
|
500 | def magic_autocall(self, parameter_s = ''): | |||
|
501 | """Make functions callable without having to type parentheses. | |||
|
502 | ||||
|
503 | This toggles the autocall command line option on and off.""" | |||
|
504 | ||||
|
505 | rc = self.shell.rc | |||
|
506 | rc.autocall = not rc.autocall | |||
|
507 | print "Automatic calling is:",['OFF','ON'][rc.autocall] | |||
|
508 | ||||
|
509 | def magic_autoindent(self, parameter_s = ''): | |||
|
510 | """Toggle autoindent on/off (if available).""" | |||
|
511 | ||||
|
512 | self.shell.set_autoindent() | |||
|
513 | print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent] | |||
|
514 | ||||
|
515 | def magic_system_verbose(self, parameter_s = ''): | |||
|
516 | """Toggle verbose printing of system calls on/off.""" | |||
|
517 | ||||
|
518 | self.shell.rc_set_toggle('system_verbose') | |||
|
519 | print "System verbose printing is:",\ | |||
|
520 | ['OFF','ON'][self.shell.rc.system_verbose] | |||
|
521 | ||||
|
522 | def magic_history(self, parameter_s = ''): | |||
|
523 | """Print input history (_i<n> variables), with most recent last. | |||
|
524 | ||||
|
525 | %history [-n] -> print at most 40 inputs (some may be multi-line)\\ | |||
|
526 | %history [-n] n -> print at most n inputs\\ | |||
|
527 | %history [-n] n1 n2 -> print inputs between n1 and n2 (n2 not included)\\ | |||
|
528 | ||||
|
529 | Each input's number <n> is shown, and is accessible as the | |||
|
530 | automatically generated variable _i<n>. Multi-line statements are | |||
|
531 | printed starting at a new line for easy copy/paste. | |||
|
532 | ||||
|
533 | If option -n is used, input numbers are not printed. This is useful if | |||
|
534 | you want to get a printout of many lines which can be directly pasted | |||
|
535 | into a text editor. | |||
|
536 | ||||
|
537 | This feature is only available if numbered prompts are in use.""" | |||
|
538 | ||||
|
539 | if not self.do_full_cache: | |||
|
540 | print 'This feature is only available if numbered prompts are in use.' | |||
|
541 | return | |||
|
542 | opts,args = self.parse_options(parameter_s,'n',mode='list') | |||
|
543 | ||||
|
544 | default_length = 40 | |||
|
545 | if len(args) == 0: | |||
|
546 | final = self.outputcache.prompt_count | |||
|
547 | init = max(1,final-default_length) | |||
|
548 | elif len(args) == 1: | |||
|
549 | final = self.outputcache.prompt_count | |||
|
550 | init = max(1,final-int(args[0])) | |||
|
551 | elif len(args) == 2: | |||
|
552 | init,final = map(int,args) | |||
|
553 | else: | |||
|
554 | warn('%hist takes 0, 1 or 2 arguments separated by spaces.') | |||
|
555 | print self.magic_hist.__doc__ | |||
|
556 | return | |||
|
557 | width = len(str(final)) | |||
|
558 | line_sep = ['','\n'] | |||
|
559 | input_hist = self.shell.input_hist | |||
|
560 | print_nums = not opts.has_key('n') | |||
|
561 | for in_num in range(init,final): | |||
|
562 | inline = input_hist[in_num] | |||
|
563 | multiline = inline.count('\n') > 1 | |||
|
564 | if print_nums: | |||
|
565 | print str(in_num).ljust(width)+':'+ line_sep[multiline], | |||
|
566 | if inline.startswith('#'+self.shell.ESC_MAGIC) or \ | |||
|
567 | inline.startswith('#!'): | |||
|
568 | print inline[1:], | |||
|
569 | else: | |||
|
570 | print inline, | |||
|
571 | ||||
|
572 | def magic_hist(self, parameter_s=''): | |||
|
573 | """Alternate name for %history.""" | |||
|
574 | return self.magic_history(parameter_s) | |||
|
575 | ||||
|
576 | def magic_p(self, parameter_s=''): | |||
|
577 | """Just a short alias for Python's 'print'.""" | |||
|
578 | exec 'print ' + parameter_s in self.shell.user_ns | |||
|
579 | ||||
|
580 | def magic_r(self, parameter_s=''): | |||
|
581 | """Repeat previous input. | |||
|
582 | ||||
|
583 | If given an argument, repeats the previous command which starts with | |||
|
584 | the same string, otherwise it just repeats the previous input. | |||
|
585 | ||||
|
586 | Shell escaped commands (with ! as first character) are not recognized | |||
|
587 | by this system, only pure python code and magic commands. | |||
|
588 | """ | |||
|
589 | ||||
|
590 | start = parameter_s.strip() | |||
|
591 | esc_magic = self.shell.ESC_MAGIC | |||
|
592 | # Identify magic commands even if automagic is on (which means | |||
|
593 | # the in-memory version is different from that typed by the user). | |||
|
594 | if self.shell.rc.automagic: | |||
|
595 | start_magic = esc_magic+start | |||
|
596 | else: | |||
|
597 | start_magic = start | |||
|
598 | # Look through the input history in reverse | |||
|
599 | for n in range(len(self.shell.input_hist)-2,0,-1): | |||
|
600 | input = self.shell.input_hist[n] | |||
|
601 | # skip plain 'r' lines so we don't recurse to infinity | |||
|
602 | if input != 'ipmagic("r")\n' and \ | |||
|
603 | (input.startswith(start) or input.startswith(start_magic)): | |||
|
604 | #print 'match',`input` # dbg | |||
|
605 | if input.startswith(esc_magic): | |||
|
606 | input = magic2python(input) | |||
|
607 | #print 'modified',`input` # dbg | |||
|
608 | print 'Executing:',input, | |||
|
609 | exec input in self.shell.user_ns | |||
|
610 | return | |||
|
611 | print 'No previous input matching `%s` found.' % start | |||
|
612 | ||||
|
613 | def magic_page(self, parameter_s=''): | |||
|
614 | """Pretty print the object and display it through a pager. | |||
|
615 | ||||
|
616 | If no parameter is given, use _ (last output).""" | |||
|
617 | # After a function contributed by Olivier Aubert, slightly modified. | |||
|
618 | ||||
|
619 | oname = parameter_s and parameter_s or '_' | |||
|
620 | info = self._ofind(oname) | |||
|
621 | if info['found']: | |||
|
622 | page(pformat(info['obj'])) | |||
|
623 | else: | |||
|
624 | print 'Object `%s` not found' % oname | |||
|
625 | ||||
|
626 | def magic_profile(self, parameter_s=''): | |||
|
627 | """Print your currently active IPyhton profile.""" | |||
|
628 | if self.shell.rc.profile: | |||
|
629 | printpl('Current IPython profile: $self.shell.rc.profile.') | |||
|
630 | else: | |||
|
631 | print 'No profile active.' | |||
|
632 | ||||
|
633 | def _inspect(self,meth,oname,**kw): | |||
|
634 | """Generic interface to the inspector system. | |||
|
635 | ||||
|
636 | This function is meant to be called by pdef, pdoc & friends.""" | |||
|
637 | ||||
|
638 | oname = oname.strip() | |||
|
639 | info = Struct(self._ofind(oname)) | |||
|
640 | if info.found: | |||
|
641 | pmethod = getattr(self.shell.inspector,meth) | |||
|
642 | formatter = info.ismagic and self.format_screen or None | |||
|
643 | if meth == 'pdoc': | |||
|
644 | pmethod(info.obj,oname,formatter) | |||
|
645 | elif meth == 'pinfo': | |||
|
646 | pmethod(info.obj,oname,formatter,info,**kw) | |||
|
647 | else: | |||
|
648 | pmethod(info.obj,oname) | |||
|
649 | else: | |||
|
650 | print 'Object `%s` not found.' % oname | |||
|
651 | return 'not found' # so callers can take other action | |||
|
652 | ||||
|
653 | def magic_pdef(self, parameter_s=''): | |||
|
654 | """Print the definition header for any callable object. | |||
|
655 | ||||
|
656 | If the object is a class, print the constructor information.""" | |||
|
657 | self._inspect('pdef',parameter_s) | |||
|
658 | ||||
|
659 | def magic_pdoc(self, parameter_s=''): | |||
|
660 | """Print the docstring for an object. | |||
|
661 | ||||
|
662 | If the given object is a class, it will print both the class and the | |||
|
663 | constructor docstrings.""" | |||
|
664 | self._inspect('pdoc',parameter_s) | |||
|
665 | ||||
|
666 | def magic_psource(self, parameter_s=''): | |||
|
667 | """Print (or run through pager) the source code for an object.""" | |||
|
668 | self._inspect('psource',parameter_s) | |||
|
669 | ||||
|
670 | def magic_pfile(self, parameter_s=''): | |||
|
671 | """Print (or run through pager) the file where an object is defined. | |||
|
672 | ||||
|
673 | The file opens at the line where the object definition begins. IPython | |||
|
674 | will honor the environment variable PAGER if set, and otherwise will | |||
|
675 | do its best to print the file in a convenient form. | |||
|
676 | ||||
|
677 | If the given argument is not an object currently defined, IPython will | |||
|
678 | try to interpret it as a filename (automatically adding a .py extension | |||
|
679 | if needed). You can thus use %pfile as a syntax highlighting code | |||
|
680 | viewer.""" | |||
|
681 | ||||
|
682 | # first interpret argument as an object name | |||
|
683 | out = self._inspect('pfile',parameter_s) | |||
|
684 | # if not, try the input as a filename | |||
|
685 | if out == 'not found': | |||
|
686 | try: | |||
|
687 | filename = get_py_filename(parameter_s) | |||
|
688 | except IOError,msg: | |||
|
689 | print msg | |||
|
690 | return | |||
|
691 | page(self.shell.inspector.format(file(filename).read())) | |||
|
692 | ||||
|
693 | def magic_pinfo(self, parameter_s=''): | |||
|
694 | """Provide detailed information about an object. | |||
|
695 | ||||
|
696 | '%pinfo object' is just a synonym for object? or ?object.""" | |||
|
697 | ||||
|
698 | #print 'pinfo par: <%s>' % parameter_s # dbg | |||
|
699 | ||||
|
700 | # detail_level: 0 -> obj? , 1 -> obj?? | |||
|
701 | detail_level = 0 | |||
|
702 | # We need to detect if we got called as 'pinfo pinfo foo', which can | |||
|
703 | # happen if the user types 'pinfo foo?' at the cmd line. | |||
|
704 | pinfo,qmark1,oname,qmark2 = \ | |||
|
705 | re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups() | |||
|
706 | if pinfo or qmark1 or qmark2: | |||
|
707 | detail_level = 1 | |||
|
708 | self._inspect('pinfo',oname,detail_level=detail_level) | |||
|
709 | ||||
|
710 | def magic_who_ls(self, parameter_s=''): | |||
|
711 | """Return a sorted list of all interactive variables. | |||
|
712 | ||||
|
713 | If arguments are given, only variables of types matching these | |||
|
714 | arguments are returned.""" | |||
|
715 | ||||
|
716 | user_ns = self.shell.user_ns | |||
|
717 | out = [] | |||
|
718 | typelist = parameter_s.split() | |||
|
719 | for i in self.shell.user_ns.keys(): | |||
|
720 | if not (i.startswith('_') or i.startswith('_i')) \ | |||
|
721 | and not (self.internal_ns.has_key(i) or | |||
|
722 | self.user_config_ns.has_key(i)): | |||
|
723 | if typelist: | |||
|
724 | if type(user_ns[i]).__name__ in typelist: | |||
|
725 | out.append(i) | |||
|
726 | else: | |||
|
727 | out.append(i) | |||
|
728 | out.sort() | |||
|
729 | return out | |||
|
730 | ||||
|
731 | def magic_who(self, parameter_s=''): | |||
|
732 | """Print all interactive variables, with some minimal formatting. | |||
|
733 | ||||
|
734 | If any arguments are given, only variables whose type matches one of | |||
|
735 | these are printed. For example: | |||
|
736 | ||||
|
737 | %who function str | |||
|
738 | ||||
|
739 | will only list functions and strings, excluding all other types of | |||
|
740 | variables. To find the proper type names, simply use type(var) at a | |||
|
741 | command line to see how python prints type names. For example: | |||
|
742 | ||||
|
743 | In [1]: type('hello')\\ | |||
|
744 | Out[1]: <type 'str'> | |||
|
745 | ||||
|
746 | indicates that the type name for strings is 'str'. | |||
|
747 | ||||
|
748 | %who always excludes executed names loaded through your configuration | |||
|
749 | file and things which are internal to IPython. | |||
|
750 | ||||
|
751 | This is deliberate, as typically you may load many modules and the | |||
|
752 | purpose of %who is to show you only what you've manually defined.""" | |||
|
753 | ||||
|
754 | varlist = self.magic_who_ls(parameter_s) | |||
|
755 | if not varlist: | |||
|
756 | print 'Interactive namespace is empty.' | |||
|
757 | return | |||
|
758 | ||||
|
759 | # if we have variables, move on... | |||
|
760 | ||||
|
761 | # stupid flushing problem: when prompts have no separators, stdout is | |||
|
762 | # getting lost. I'm starting to think this is a python bug. I'm having | |||
|
763 | # to force a flush with a print because even a sys.stdout.flush | |||
|
764 | # doesn't seem to do anything! | |||
|
765 | ||||
|
766 | count = 0 | |||
|
767 | for i in varlist: | |||
|
768 | print i+'\t', | |||
|
769 | count += 1 | |||
|
770 | if count > 8: | |||
|
771 | count = 0 | |||
|
772 | ||||
|
773 | sys.stdout.flush() # FIXME. Why the hell isn't this flushing??? | |||
|
774 | ||||
|
775 | print # well, this does force a flush at the expense of an extra \n | |||
|
776 | ||||
|
777 | def magic_whos(self, parameter_s=''): | |||
|
778 | """Like %who, but gives some extra information about each variable. | |||
|
779 | ||||
|
780 | The same type filtering of %who can be applied here. | |||
|
781 | ||||
|
782 | For all variables, the type is printed. Additionally it prints: | |||
|
783 | ||||
|
784 | - For {},[],(): their length. | |||
|
785 | ||||
|
786 | - For Numeric arrays, a summary with shape, number of elements, | |||
|
787 | typecode and size in memory. | |||
|
788 | ||||
|
789 | - Everything else: a string representation, snipping their middle if | |||
|
790 | too long.""" | |||
|
791 | ||||
|
792 | varnames = self.magic_who_ls(parameter_s) | |||
|
793 | if not varnames: | |||
|
794 | print 'Interactive namespace is empty.' | |||
|
795 | return | |||
|
796 | ||||
|
797 | # if we have variables, move on... | |||
|
798 | ||||
|
799 | # for these types, show len() instead of data: | |||
|
800 | seq_types = [types.DictType,types.ListType,types.TupleType] | |||
|
801 | ||||
|
802 | # for Numeric arrays, display summary info | |||
|
803 | try: | |||
|
804 | import Numeric | |||
|
805 | except ImportError: | |||
|
806 | array_type = None | |||
|
807 | else: | |||
|
808 | array_type = Numeric.ArrayType.__name__ | |||
|
809 | ||||
|
810 | # Find all variable names and types so we can figure out column sizes | |||
|
811 | get_vars = lambda i: self.locals[i] | |||
|
812 | type_name = lambda v: type(v).__name__ | |||
|
813 | varlist = map(get_vars,varnames) | |||
|
814 | typelist = map(type_name,varlist) | |||
|
815 | # column labels and # of spaces as separator | |||
|
816 | varlabel = 'Variable' | |||
|
817 | typelabel = 'Type' | |||
|
818 | datalabel = 'Data/Info' | |||
|
819 | colsep = 3 | |||
|
820 | # variable format strings | |||
|
821 | vformat = "$vname.ljust(varwidth)$vtype.ljust(typewidth)" | |||
|
822 | vfmt_short = '$vstr[:25]<...>$vstr[-25:]' | |||
|
823 | aformat = "%s: %s elems, type `%s`, %s bytes" | |||
|
824 | # find the size of the columns to format the output nicely | |||
|
825 | varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep | |||
|
826 | typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep | |||
|
827 | # table header | |||
|
828 | print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \ | |||
|
829 | ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1) | |||
|
830 | # and the table itself | |||
|
831 | kb = 1024 | |||
|
832 | Mb = 1048576 # kb**2 | |||
|
833 | for vname,var,vtype in zip(varnames,varlist,typelist): | |||
|
834 | print itpl(vformat), | |||
|
835 | if vtype in seq_types: | |||
|
836 | print len(var) | |||
|
837 | elif vtype==array_type: | |||
|
838 | vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1] | |||
|
839 | vsize = Numeric.size(var) | |||
|
840 | vbytes = vsize*var.itemsize() | |||
|
841 | if vbytes < 100000: | |||
|
842 | print aformat % (vshape,vsize,var.typecode(),vbytes) | |||
|
843 | else: | |||
|
844 | print aformat % (vshape,vsize,var.typecode(),vbytes), | |||
|
845 | if vbytes < Mb: | |||
|
846 | print '(%s kb)' % (vbytes/kb,) | |||
|
847 | else: | |||
|
848 | print '(%s Mb)' % (vbytes/Mb,) | |||
|
849 | else: | |||
|
850 | vstr = str(var) | |||
|
851 | if len(vstr) < 50: | |||
|
852 | print vstr | |||
|
853 | else: | |||
|
854 | printpl(vfmt_short) | |||
|
855 | ||||
|
856 | def magic_reset(self, parameter_s=''): | |||
|
857 | """Resets the namespace by removing all names defined by the user. | |||
|
858 | ||||
|
859 | Input/Output history are left around in case you need them.""" | |||
|
860 | ||||
|
861 | ans = raw_input( | |||
|
862 | "Once deleted, variables cannot be recovered. Proceed (y/n)? ") | |||
|
863 | if not ans.lower() == 'y': | |||
|
864 | print 'Nothing done.' | |||
|
865 | return | |||
|
866 | for i in self.magic_who_ls(): | |||
|
867 | del(self.locals[i]) | |||
|
868 | ||||
|
869 | def magic_config(self,parameter_s=''): | |||
|
870 | """Show IPython's internal configuration.""" | |||
|
871 | ||||
|
872 | page('Current configuration structure:\n'+ | |||
|
873 | pformat(self.shell.rc.dict())) | |||
|
874 | ||||
|
875 | def magic_logstart(self,parameter_s=''): | |||
|
876 | """Start logging anywhere in a session. | |||
|
877 | ||||
|
878 | %logstart [log_name [log_mode]] | |||
|
879 | ||||
|
880 | If no name is given, it defaults to a file named 'ipython.log' in your | |||
|
881 | current directory, in 'rotate' mode (see below). | |||
|
882 | ||||
|
883 | '%logstart name' saves to file 'name' in 'backup' mode. It saves your | |||
|
884 | history up to that point and then continues logging. | |||
|
885 | ||||
|
886 | %logstart takes a second optional parameter: logging mode. This can be one | |||
|
887 | of (note that the modes are given unquoted):\\ | |||
|
888 | over: overwrite existing log.\\ | |||
|
889 | backup: rename (if exists) to name~ and start name.\\ | |||
|
890 | append: well, that says it.\\ | |||
|
891 | rotate: create rotating logs name.1~, name.2~, etc. | |||
|
892 | """ | |||
|
893 | ||||
|
894 | #FIXME. This function should all be moved to the Logger class. | |||
|
895 | ||||
|
896 | valid_modes = qw('over backup append rotate') | |||
|
897 | if self.LOG: | |||
|
898 | print 'Logging is already in place. Logfile:',self.LOG | |||
|
899 | return | |||
|
900 | ||||
|
901 | par = parameter_s.strip() | |||
|
902 | if not par: | |||
|
903 | logname = self.LOGDEF | |||
|
904 | logmode = 'rotate' # use rotate for the auto-generated logs | |||
|
905 | else: | |||
|
906 | try: | |||
|
907 | logname,logmode = par.split() | |||
|
908 | except: | |||
|
909 | try: | |||
|
910 | logname = par | |||
|
911 | logmode = 'backup' | |||
|
912 | except: | |||
|
913 | warn('Usage: %log [log_name [log_mode]]') | |||
|
914 | return | |||
|
915 | if not logmode in valid_modes: | |||
|
916 | warn('Logging NOT activated.\n' | |||
|
917 | 'Usage: %log [log_name [log_mode]]\n' | |||
|
918 | 'Valid modes: '+str(valid_modes)) | |||
|
919 | return | |||
|
920 | ||||
|
921 | # If we made it this far, I think we're ok: | |||
|
922 | print 'Activating auto-logging.' | |||
|
923 | print 'Current session state plus future input saved to:',logname | |||
|
924 | print 'Logging mode: ',logmode | |||
|
925 | # put logname into rc struct as if it had been called on the command line, | |||
|
926 | # so it ends up saved in the log header | |||
|
927 | # Save it in case we need to restore it... | |||
|
928 | old_logfile = self.shell.rc.opts.get('logfile','') | |||
|
929 | logname = os.path.expanduser(logname) | |||
|
930 | self.shell.rc.opts.logfile = logname | |||
|
931 | self.LOGMODE = logmode # FIXME: this should be set through a function. | |||
|
932 | try: | |||
|
933 | header = str(self.LOGHEAD) | |||
|
934 | self.create_log(header,logname) | |||
|
935 | self.logstart(header,logname) | |||
|
936 | except: | |||
|
937 | self.LOG = '' # we are NOT logging, something went wrong | |||
|
938 | self.shell.rc.opts.logfile = old_logfile | |||
|
939 | warn("Couldn't start log: "+str(sys.exc_info()[1])) | |||
|
940 | else: # log input history up to this point | |||
|
941 | self.logfile.write(self.shell.user_ns['_ih'][1:]) | |||
|
942 | self.logfile.flush() | |||
|
943 | ||||
|
944 | def magic_logoff(self,parameter_s=''): | |||
|
945 | """Temporarily stop logging. | |||
|
946 | ||||
|
947 | You must have previously started logging.""" | |||
|
948 | self.switch_log(0) | |||
|
949 | ||||
|
950 | def magic_logon(self,parameter_s=''): | |||
|
951 | """Restart logging. | |||
|
952 | ||||
|
953 | This function is for restarting logging which you've temporarily | |||
|
954 | stopped with %logoff. For starting logging for the first time, you | |||
|
955 | must use the %logstart function, which allows you to specify an | |||
|
956 | optional log filename.""" | |||
|
957 | ||||
|
958 | self.switch_log(1) | |||
|
959 | ||||
|
960 | def magic_logstate(self,parameter_s=''): | |||
|
961 | """Print the status of the logging system.""" | |||
|
962 | ||||
|
963 | self.logstate() | |||
|
964 | ||||
|
965 | def magic_pdb(self, parameter_s=''): | |||
|
966 | """Control the calling of the pdb interactive debugger. | |||
|
967 | ||||
|
968 | Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without | |||
|
969 | argument it works as a toggle. | |||
|
970 | ||||
|
971 | When an exception is triggered, IPython can optionally call the | |||
|
972 | interactive pdb debugger after the traceback printout. %pdb toggles | |||
|
973 | this feature on and off.""" | |||
|
974 | ||||
|
975 | par = parameter_s.strip().lower() | |||
|
976 | ||||
|
977 | if par: | |||
|
978 | try: | |||
|
979 | pdb = {'off':0,'0':0,'on':1,'1':1}[par] | |||
|
980 | except KeyError: | |||
|
981 | print 'Incorrect argument. Use on/1, off/0 or nothing for a toggle.' | |||
|
982 | return | |||
|
983 | else: | |||
|
984 | self.shell.InteractiveTB.call_pdb = pdb | |||
|
985 | else: | |||
|
986 | self.shell.InteractiveTB.call_pdb = 1 - self.shell.InteractiveTB.call_pdb | |||
|
987 | print 'Automatic pdb calling has been turned',\ | |||
|
988 | on_off(self.shell.InteractiveTB.call_pdb) | |||
|
989 | ||||
|
990 | ||||
|
991 | def magic_prun(self, parameter_s ='',user_mode=1, | |||
|
992 | opts=None,arg_lst=None,prog_ns=None): | |||
|
993 | ||||
|
994 | """Run a statement through the python code profiler. | |||
|
995 | ||||
|
996 | Usage:\\ | |||
|
997 | %prun [options] statement | |||
|
998 | ||||
|
999 | The given statement (which doesn't require quote marks) is run via the | |||
|
1000 | python profiler in a manner similar to the profile.run() function. | |||
|
1001 | Namespaces are internally managed to work correctly; profile.run | |||
|
1002 | cannot be used in IPython because it makes certain assumptions about | |||
|
1003 | namespaces which do not hold under IPython. | |||
|
1004 | ||||
|
1005 | Options: | |||
|
1006 | ||||
|
1007 | -l <limit>: you can place restrictions on what or how much of the | |||
|
1008 | profile gets printed. The limit value can be: | |||
|
1009 | ||||
|
1010 | * A string: only information for function names containing this string | |||
|
1011 | is printed. | |||
|
1012 | ||||
|
1013 | * An integer: only these many lines are printed. | |||
|
1014 | ||||
|
1015 | * A float (between 0 and 1): this fraction of the report is printed | |||
|
1016 | (for example, use a limit of 0.4 to see the topmost 40% only). | |||
|
1017 | ||||
|
1018 | You can combine several limits with repeated use of the option. For | |||
|
1019 | example, '-l __init__ -l 5' will print only the topmost 5 lines of | |||
|
1020 | information about class constructors. | |||
|
1021 | ||||
|
1022 | -r: return the pstats.Stats object generated by the profiling. This | |||
|
1023 | object has all the information about the profile in it, and you can | |||
|
1024 | later use it for further analysis or in other functions. | |||
|
1025 | ||||
|
1026 | Since magic functions have a particular form of calling which prevents | |||
|
1027 | you from writing something like:\\ | |||
|
1028 | In [1]: p = %prun -r print 4 # invalid!\\ | |||
|
1029 | you must instead use IPython's automatic variables to assign this:\\ | |||
|
1030 | In [1]: %prun -r print 4 \\ | |||
|
1031 | Out[1]: <pstats.Stats instance at 0x8222cec>\\ | |||
|
1032 | In [2]: stats = _ | |||
|
1033 | ||||
|
1034 | If you really need to assign this value via an explicit function call, | |||
|
1035 | you can always tap directly into the true name of the magic function | |||
|
1036 | by using the ipmagic function (which IPython automatically adds to the | |||
|
1037 | builtins):\\ | |||
|
1038 | In [3]: stats = ipmagic('prun','-r print 4') | |||
|
1039 | ||||
|
1040 | You can type ipmagic? for more details on ipmagic. | |||
|
1041 | ||||
|
1042 | -s <key>: sort profile by given key. You can provide more than one key | |||
|
1043 | by using the option several times: '-s key1 -s key2 -s key3...'. The | |||
|
1044 | default sorting key is 'time'. | |||
|
1045 | ||||
|
1046 | The following is copied verbatim from the profile documentation | |||
|
1047 | referenced below: | |||
|
1048 | ||||
|
1049 | When more than one key is provided, additional keys are used as | |||
|
1050 | secondary criteria when the there is equality in all keys selected | |||
|
1051 | before them. | |||
|
1052 | ||||
|
1053 | Abbreviations can be used for any key names, as long as the | |||
|
1054 | abbreviation is unambiguous. The following are the keys currently | |||
|
1055 | defined: | |||
|
1056 | ||||
|
1057 | Valid Arg Meaning\\ | |||
|
1058 | "calls" call count\\ | |||
|
1059 | "cumulative" cumulative time\\ | |||
|
1060 | "file" file name\\ | |||
|
1061 | "module" file name\\ | |||
|
1062 | "pcalls" primitive call count\\ | |||
|
1063 | "line" line number\\ | |||
|
1064 | "name" function name\\ | |||
|
1065 | "nfl" name/file/line\\ | |||
|
1066 | "stdname" standard name\\ | |||
|
1067 | "time" internal time | |||
|
1068 | ||||
|
1069 | Note that all sorts on statistics are in descending order (placing | |||
|
1070 | most time consuming items first), where as name, file, and line number | |||
|
1071 | searches are in ascending order (i.e., alphabetical). The subtle | |||
|
1072 | distinction between "nfl" and "stdname" is that the standard name is a | |||
|
1073 | sort of the name as printed, which means that the embedded line | |||
|
1074 | numbers get compared in an odd way. For example, lines 3, 20, and 40 | |||
|
1075 | would (if the file names were the same) appear in the string order | |||
|
1076 | "20" "3" and "40". In contrast, "nfl" does a numeric compare of the | |||
|
1077 | line numbers. In fact, sort_stats("nfl") is the same as | |||
|
1078 | sort_stats("name", "file", "line"). | |||
|
1079 | ||||
|
1080 | -T <filename>: save profile results as shown on screen to a text | |||
|
1081 | file. The profile is still shown on screen. | |||
|
1082 | ||||
|
1083 | -D <filename>: save (via dump_stats) profile statistics to given | |||
|
1084 | filename. This data is in a format understod by the pstats module, and | |||
|
1085 | is generated by a call to the dump_stats() method of profile | |||
|
1086 | objects. The profile is still shown on screen. | |||
|
1087 | ||||
|
1088 | If you want to run complete programs under the profiler's control, use | |||
|
1089 | '%run -p [prof_opts] filename.py [args to program]' where prof_opts | |||
|
1090 | contains profiler specific options as described here. | |||
|
1091 | ||||
|
1092 | You can read the complete documentation for the profile module with:\\ | |||
|
1093 | In [1]: import profile; profile.help() """ | |||
|
1094 | ||||
|
1095 | opts_def = Struct(D=[''],l=[],s=['time'],T=['']) | |||
|
1096 | # protect user quote marks | |||
|
1097 | parameter_s = parameter_s.replace('"',r'\"').replace("'",r"\'") | |||
|
1098 | ||||
|
1099 | if user_mode: # regular user call | |||
|
1100 | opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:', | |||
|
1101 | list_all=1) | |||
|
1102 | namespace = self.shell.user_ns | |||
|
1103 | else: # called to run a program by %run -p | |||
|
1104 | try: | |||
|
1105 | filename = get_py_filename(arg_lst[0]) | |||
|
1106 | except IOError,msg: | |||
|
1107 | error(msg) | |||
|
1108 | return | |||
|
1109 | ||||
|
1110 | arg_str = 'execfile(filename,prog_ns)' | |||
|
1111 | namespace = locals() | |||
|
1112 | ||||
|
1113 | opts.merge(opts_def) | |||
|
1114 | ||||
|
1115 | prof = profile.Profile() | |||
|
1116 | try: | |||
|
1117 | prof = prof.runctx(arg_str,namespace,namespace) | |||
|
1118 | sys_exit = '' | |||
|
1119 | except SystemExit: | |||
|
1120 | sys_exit = """*** SystemExit exception caught in code being profiled.""" | |||
|
1121 | ||||
|
1122 | stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s) | |||
|
1123 | ||||
|
1124 | lims = opts.l | |||
|
1125 | if lims: | |||
|
1126 | lims = [] # rebuild lims with ints/floats/strings | |||
|
1127 | for lim in opts.l: | |||
|
1128 | try: | |||
|
1129 | lims.append(int(lim)) | |||
|
1130 | except ValueError: | |||
|
1131 | try: | |||
|
1132 | lims.append(float(lim)) | |||
|
1133 | except ValueError: | |||
|
1134 | lims.append(lim) | |||
|
1135 | ||||
|
1136 | # trap output | |||
|
1137 | sys_stdout = sys.stdout | |||
|
1138 | stdout_trap = StringIO() | |||
|
1139 | try: | |||
|
1140 | sys.stdout = stdout_trap | |||
|
1141 | stats.print_stats(*lims) | |||
|
1142 | finally: | |||
|
1143 | sys.stdout = sys_stdout | |||
|
1144 | output = stdout_trap.getvalue() | |||
|
1145 | output = output.rstrip() | |||
|
1146 | ||||
|
1147 | page(output,screen_lines=self.shell.rc.screen_length) | |||
|
1148 | print sys_exit, | |||
|
1149 | ||||
|
1150 | dump_file = opts.D[0] | |||
|
1151 | text_file = opts.T[0] | |||
|
1152 | if dump_file: | |||
|
1153 | prof.dump_stats(dump_file) | |||
|
1154 | print '\n*** Profile stats marshalled to file',\ | |||
|
1155 | `dump_file`+'.',sys_exit | |||
|
1156 | if text_file: | |||
|
1157 | file(text_file,'w').write(output) | |||
|
1158 | print '\n*** Profile printout saved to text file',\ | |||
|
1159 | `text_file`+'.',sys_exit | |||
|
1160 | ||||
|
1161 | if opts.has_key('r'): | |||
|
1162 | return stats | |||
|
1163 | else: | |||
|
1164 | return None | |||
|
1165 | ||||
|
1166 | def magic_run(self, parameter_s ='',runner=None): | |||
|
1167 | """Run the named file inside IPython as a program. | |||
|
1168 | ||||
|
1169 | Usage:\\ | |||
|
1170 | %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args] | |||
|
1171 | ||||
|
1172 | Parameters after the filename are passed as command-line arguments to | |||
|
1173 | the program (put in sys.argv). Then, control returns to IPython's | |||
|
1174 | prompt. | |||
|
1175 | ||||
|
1176 | This is similar to running at a system prompt:\\ | |||
|
1177 | $ python file args\\ | |||
|
1178 | but with the advantage of giving you IPython's tracebacks, and of | |||
|
1179 | loading all variables into your interactive namespace for further use | |||
|
1180 | (unless -p is used, see below). | |||
|
1181 | ||||
|
1182 | The file is executed in a namespace initially consisting only of | |||
|
1183 | __name__=='__main__' and sys.argv constructed as indicated. It thus | |||
|
1184 | sees its environment as if it were being run as a stand-alone | |||
|
1185 | program. But after execution, the IPython interactive namespace gets | |||
|
1186 | updated with all variables defined in the program (except for __name__ | |||
|
1187 | and sys.argv). This allows for very convenient loading of code for | |||
|
1188 | interactive work, while giving each program a 'clean sheet' to run in. | |||
|
1189 | ||||
|
1190 | Options: | |||
|
1191 | ||||
|
1192 | -n: __name__ is NOT set to '__main__', but to the running file's name | |||
|
1193 | without extension (as python does under import). This allows running | |||
|
1194 | scripts and reloading the definitions in them without calling code | |||
|
1195 | protected by an ' if __name__ == "__main__" ' clause. | |||
|
1196 | ||||
|
1197 | -i: run the file in IPython's namespace instead of an empty one. This | |||
|
1198 | is useful if you are experimenting with code written in a text editor | |||
|
1199 | which depends on variables defined interactively. | |||
|
1200 | ||||
|
1201 | -e: ignore sys.exit() calls or SystemExit exceptions in the script | |||
|
1202 | being run. This is particularly useful if IPython is being used to | |||
|
1203 | run unittests, which always exit with a sys.exit() call. In such | |||
|
1204 | cases you are interested in the output of the test results, not in | |||
|
1205 | seeing a traceback of the unittest module. | |||
|
1206 | ||||
|
1207 | -t: print timing information at the end of the run. IPython will give | |||
|
1208 | you an estimated CPU time consumption for your script, which under | |||
|
1209 | Unix uses the resource module to avoid the wraparound problems of | |||
|
1210 | time.clock(). Under Unix, an estimate of time spent on system tasks | |||
|
1211 | is also given (for Windows platforms this is reported as 0.0). | |||
|
1212 | ||||
|
1213 | If -t is given, an additional -N<N> option can be given, where <N> | |||
|
1214 | must be an integer indicating how many times you want the script to | |||
|
1215 | run. The final timing report will include total and per run results. | |||
|
1216 | ||||
|
1217 | For example (testing the script uniq_stable.py): | |||
|
1218 | ||||
|
1219 | In [1]: run -t uniq_stable | |||
|
1220 | ||||
|
1221 | IPython CPU timings (estimated):\\ | |||
|
1222 | User : 0.19597 s.\\ | |||
|
1223 | System: 0.0 s.\\ | |||
|
1224 | ||||
|
1225 | In [2]: run -t -N5 uniq_stable | |||
|
1226 | ||||
|
1227 | IPython CPU timings (estimated):\\ | |||
|
1228 | Total runs performed: 5\\ | |||
|
1229 | Times : Total Per run\\ | |||
|
1230 | User : 0.910862 s, 0.1821724 s.\\ | |||
|
1231 | System: 0.0 s, 0.0 s. | |||
|
1232 | ||||
|
1233 | -d: run your program under the control of pdb, the Python debugger. | |||
|
1234 | This allows you to execute your program step by step, watch variables, | |||
|
1235 | etc. Internally, what IPython does is similar to calling: | |||
|
1236 | ||||
|
1237 | pdb.run('execfile("YOURFILENAME")') | |||
|
1238 | ||||
|
1239 | with a breakpoint set on line 1 of your file. You can change the line | |||
|
1240 | number for this automatic breakpoint to be <N> by using the -bN option | |||
|
1241 | (where N must be an integer). For example: | |||
|
1242 | ||||
|
1243 | %run -d -b40 myscript | |||
|
1244 | ||||
|
1245 | will set the first breakpoint at line 40 in myscript.py. Note that | |||
|
1246 | the first breakpoint must be set on a line which actually does | |||
|
1247 | something (not a comment or docstring) for it to stop execution. | |||
|
1248 | ||||
|
1249 | When the pdb debugger starts, you will see a (Pdb) prompt. You must | |||
|
1250 | first enter 'c' (without qoutes) to start execution up to the first | |||
|
1251 | breakpoint. | |||
|
1252 | ||||
|
1253 | Entering 'help' gives information about the use of the debugger. You | |||
|
1254 | can easily see pdb's full documentation with "import pdb;pdb.help()" | |||
|
1255 | at a prompt. | |||
|
1256 | ||||
|
1257 | -p: run program under the control of the Python profiler module (which | |||
|
1258 | prints a detailed report of execution times, function calls, etc). | |||
|
1259 | ||||
|
1260 | You can pass other options after -p which affect the behavior of the | |||
|
1261 | profiler itself. See the docs for %prun for details. | |||
|
1262 | ||||
|
1263 | In this mode, the program's variables do NOT propagate back to the | |||
|
1264 | IPython interactive namespace (because they remain in the namespace | |||
|
1265 | where the profiler executes them). | |||
|
1266 | ||||
|
1267 | Internally this triggers a call to %prun, see its documentation for | |||
|
1268 | details on the options available specifically for profiling.""" | |||
|
1269 | ||||
|
1270 | # get arguments and set sys.argv for program to be run. | |||
|
1271 | opts,arg_lst = self.parse_options(parameter_s,'nidtN:b:pD:l:rs:T:e', | |||
|
1272 | mode='list',list_all=1) | |||
|
1273 | ||||
|
1274 | try: | |||
|
1275 | filename = get_py_filename(arg_lst[0]) | |||
|
1276 | except IndexError: | |||
|
1277 | warn('you must provide at least a filename.') | |||
|
1278 | print '\n%run:\n',OInspect.getdoc(self.magic_run) | |||
|
1279 | return | |||
|
1280 | except IOError,msg: | |||
|
1281 | error(msg) | |||
|
1282 | return | |||
|
1283 | ||||
|
1284 | # Control the response to exit() calls made by the script being run | |||
|
1285 | exit_ignore = opts.has_key('e') | |||
|
1286 | ||||
|
1287 | # Make sure that the running script gets a proper sys.argv as if it | |||
|
1288 | # were run from a system shell. | |||
|
1289 | save_argv = sys.argv # save it for later restoring | |||
|
1290 | sys.argv = [filename]+ arg_lst[1:] # put in the proper filename | |||
|
1291 | ||||
|
1292 | if opts.has_key('i'): | |||
|
1293 | prog_ns = self.shell.user_ns | |||
|
1294 | __name__save = self.shell.user_ns['__name__'] | |||
|
1295 | prog_ns['__name__'] = '__main__' | |||
|
1296 | else: | |||
|
1297 | if opts.has_key('n'): | |||
|
1298 | name = os.path.splitext(os.path.basename(filename))[0] | |||
|
1299 | else: | |||
|
1300 | name = '__main__' | |||
|
1301 | prog_ns = {'__name__':name} | |||
|
1302 | ||||
|
1303 | # pickle fix. See iplib for an explanation | |||
|
1304 | sys.modules[prog_ns['__name__']] = FakeModule(prog_ns) | |||
|
1305 | ||||
|
1306 | stats = None | |||
|
1307 | try: | |||
|
1308 | if opts.has_key('p'): | |||
|
1309 | stats = self.magic_prun('',0,opts,arg_lst,prog_ns) | |||
|
1310 | else: | |||
|
1311 | if opts.has_key('d'): | |||
|
1312 | deb = pdb.Pdb() | |||
|
1313 | # reset Breakpoint state, which is moronically kept | |||
|
1314 | # in a class | |||
|
1315 | bdb.Breakpoint.next = 1 | |||
|
1316 | bdb.Breakpoint.bplist = {} | |||
|
1317 | bdb.Breakpoint.bpbynumber = [None] | |||
|
1318 | # Set an initial breakpoint to stop execution | |||
|
1319 | maxtries = 10 | |||
|
1320 | bp = int(opts.get('b',[1])[0]) | |||
|
1321 | checkline = deb.checkline(filename,bp) | |||
|
1322 | if not checkline: | |||
|
1323 | for bp in range(bp+1,bp+maxtries+1): | |||
|
1324 | if deb.checkline(filename,bp): | |||
|
1325 | break | |||
|
1326 | else: | |||
|
1327 | msg = ("\nI failed to find a valid line to set " | |||
|
1328 | "a breakpoint\n" | |||
|
1329 | "after trying up to line: %s.\n" | |||
|
1330 | "Please set a valid breakpoint manually " | |||
|
1331 | "with the -b option." % bp) | |||
|
1332 | error(msg) | |||
|
1333 | return | |||
|
1334 | # if we find a good linenumber, set the breakpoint | |||
|
1335 | deb.do_break('%s:%s' % (filename,bp)) | |||
|
1336 | # Start file run | |||
|
1337 | print "NOTE: Enter 'c' at the", | |||
|
1338 | print "(Pdb) prompt to start your script." | |||
|
1339 | deb.run('execfile("%s")' % filename,prog_ns) | |||
|
1340 | else: | |||
|
1341 | if runner is None: | |||
|
1342 | runner = self.shell.safe_execfile | |||
|
1343 | if opts.has_key('t'): | |||
|
1344 | try: | |||
|
1345 | nruns = int(opts['N'][0]) | |||
|
1346 | if nruns < 1: | |||
|
1347 | error('Number of runs must be >=1') | |||
|
1348 | return | |||
|
1349 | except (KeyError): | |||
|
1350 | nruns = 1 | |||
|
1351 | if nruns == 1: | |||
|
1352 | t0 = clock2() | |||
|
1353 | runner(filename,prog_ns,prog_ns,exit_ignore=exit_ignore) | |||
|
1354 | t1 = clock2() | |||
|
1355 | t_usr = t1[0]-t0[0] | |||
|
1356 | t_sys = t1[1]-t1[1] | |||
|
1357 | print "\nIPython CPU timings (estimated):" | |||
|
1358 | print " User : %10s s." % t_usr | |||
|
1359 | print " System: %10s s." % t_sys | |||
|
1360 | else: | |||
|
1361 | runs = range(nruns) | |||
|
1362 | t0 = clock2() | |||
|
1363 | for nr in runs: | |||
|
1364 | runner(filename,prog_ns,prog_ns,exit_ignore=exit_ignore) | |||
|
1365 | t1 = clock2() | |||
|
1366 | t_usr = t1[0]-t0[0] | |||
|
1367 | t_sys = t1[1]-t1[1] | |||
|
1368 | print "\nIPython CPU timings (estimated):" | |||
|
1369 | print "Total runs performed:",nruns | |||
|
1370 | print " Times : %10s %10s" % ('Total','Per run') | |||
|
1371 | print " User : %10s s, %10s s." % (t_usr,t_usr/nruns) | |||
|
1372 | print " System: %10s s, %10s s." % (t_sys,t_sys/nruns) | |||
|
1373 | ||||
|
1374 | else: | |||
|
1375 | runner(filename,prog_ns,prog_ns,exit_ignore=exit_ignore) | |||
|
1376 | if opts.has_key('i'): | |||
|
1377 | self.shell.user_ns['__name__'] = __name__save | |||
|
1378 | else: | |||
|
1379 | # update IPython interactive namespace | |||
|
1380 | del prog_ns['__name__'] | |||
|
1381 | self.shell.user_ns.update(prog_ns) | |||
|
1382 | finally: | |||
|
1383 | sys.argv = save_argv | |||
|
1384 | return stats | |||
|
1385 | ||||
|
1386 | def magic_runlog(self, parameter_s =''): | |||
|
1387 | """Run files as logs. | |||
|
1388 | ||||
|
1389 | Usage:\\ | |||
|
1390 | %runlog file1 file2 ... | |||
|
1391 | ||||
|
1392 | Run the named files (treating them as log files) in sequence inside | |||
|
1393 | the interpreter, and return to the prompt. This is much slower than | |||
|
1394 | %run because each line is executed in a try/except block, but it | |||
|
1395 | allows running files with syntax errors in them. | |||
|
1396 | ||||
|
1397 | Normally IPython will guess when a file is one of its own logfiles, so | |||
|
1398 | you can typically use %run even for logs. This shorthand allows you to | |||
|
1399 | force any file to be treated as a log file.""" | |||
|
1400 | ||||
|
1401 | for f in parameter_s.split(): | |||
|
1402 | self.shell.safe_execfile(f,self.shell.user_ns, | |||
|
1403 | self.shell.user_ns,islog=1) | |||
|
1404 | ||||
|
1405 | def magic_time(self,parameter_s = ''): | |||
|
1406 | """Time execution of a Python statement or expression. | |||
|
1407 | ||||
|
1408 | The CPU and wall clock times are printed, and the value of the | |||
|
1409 | expression (if any) is returned. Note that under Win32, system time | |||
|
1410 | is always reported as 0, since it can not be measured. | |||
|
1411 | ||||
|
1412 | This function provides very basic timing functionality. In Python | |||
|
1413 | 2.3, the timeit module offers more control and sophistication, but for | |||
|
1414 | now IPython supports Python 2.2, so we can not rely on timeit being | |||
|
1415 | present. | |||
|
1416 | ||||
|
1417 | Some examples: | |||
|
1418 | ||||
|
1419 | In [1]: time 2**128 | |||
|
1420 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s | |||
|
1421 | Wall time: 0.00 | |||
|
1422 | Out[1]: 340282366920938463463374607431768211456L | |||
|
1423 | ||||
|
1424 | In [2]: n = 1000000 | |||
|
1425 | ||||
|
1426 | In [3]: time sum(range(n)) | |||
|
1427 | CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s | |||
|
1428 | Wall time: 1.37 | |||
|
1429 | Out[3]: 499999500000L | |||
|
1430 | ||||
|
1431 | In [4]: time print 'hello world' | |||
|
1432 | hello world | |||
|
1433 | CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s | |||
|
1434 | Wall time: 0.00 | |||
|
1435 | """ | |||
|
1436 | ||||
|
1437 | # fail immediately if the given expression can't be compiled | |||
|
1438 | try: | |||
|
1439 | mode = 'eval' | |||
|
1440 | code = compile(parameter_s,'<timed eval>',mode) | |||
|
1441 | except SyntaxError: | |||
|
1442 | mode = 'exec' | |||
|
1443 | code = compile(parameter_s,'<timed exec>',mode) | |||
|
1444 | # skew measurement as little as possible | |||
|
1445 | glob = self.shell.user_ns | |||
|
1446 | clk = clock2 | |||
|
1447 | wtime = time.time | |||
|
1448 | # time execution | |||
|
1449 | wall_st = wtime() | |||
|
1450 | if mode=='eval': | |||
|
1451 | st = clk() | |||
|
1452 | out = eval(code,glob) | |||
|
1453 | end = clk() | |||
|
1454 | else: | |||
|
1455 | st = clk() | |||
|
1456 | exec code in glob | |||
|
1457 | end = clk() | |||
|
1458 | out = None | |||
|
1459 | wall_end = wtime() | |||
|
1460 | # Compute actual times and report | |||
|
1461 | wall_time = wall_end-wall_st | |||
|
1462 | cpu_user = end[0]-st[0] | |||
|
1463 | cpu_sys = end[1]-st[1] | |||
|
1464 | cpu_tot = cpu_user+cpu_sys | |||
|
1465 | print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \ | |||
|
1466 | (cpu_user,cpu_sys,cpu_tot) | |||
|
1467 | print "Wall time: %.2f" % wall_time | |||
|
1468 | return out | |||
|
1469 | ||||
|
1470 | def magic_macro(self,parameter_s = ''): | |||
|
1471 | """Define a set of input lines as a macro for future re-execution. | |||
|
1472 | ||||
|
1473 | Usage:\\ | |||
|
1474 | %macro name n1:n2 n3:n4 ... n5 .. n6 ... | |||
|
1475 | ||||
|
1476 | This will define a global variable called `name` which is a string | |||
|
1477 | made of joining the slices and lines you specify (n1,n2,... numbers | |||
|
1478 | above) from your input history into a single string. This variable | |||
|
1479 | acts like an automatic function which re-executes those lines as if | |||
|
1480 | you had typed them. You just type 'name' at the prompt and the code | |||
|
1481 | executes. | |||
|
1482 | ||||
|
1483 | Note that the slices use the standard Python slicing notation (5:8 | |||
|
1484 | means include lines numbered 5,6,7). | |||
|
1485 | ||||
|
1486 | For example, if your history contains (%hist prints it): | |||
|
1487 | ||||
|
1488 | 44: x=1\\ | |||
|
1489 | 45: y=3\\ | |||
|
1490 | 46: z=x+y\\ | |||
|
1491 | 47: print x\\ | |||
|
1492 | 48: a=5\\ | |||
|
1493 | 49: print 'x',x,'y',y\\ | |||
|
1494 | ||||
|
1495 | you can create a macro with lines 44 through 47 (included) and line 49 | |||
|
1496 | called my_macro with: | |||
|
1497 | ||||
|
1498 | In [51]: %macro my_macro 44:48 49 | |||
|
1499 | ||||
|
1500 | Now, typing `my_macro` (without quotes) will re-execute all this code | |||
|
1501 | in one pass. | |||
|
1502 | ||||
|
1503 | You don't need to give the line-numbers in order, and any given line | |||
|
1504 | number can appear multiple times. You can assemble macros with any | |||
|
1505 | lines from your input history in any order. | |||
|
1506 | ||||
|
1507 | The macro is a simple object which holds its value in an attribute, | |||
|
1508 | but IPython's display system checks for macros and executes them as | |||
|
1509 | code instead of printing them when you type their name. | |||
|
1510 | ||||
|
1511 | You can view a macro's contents by explicitly printing it with: | |||
|
1512 | ||||
|
1513 | 'print macro_name'. | |||
|
1514 | ||||
|
1515 | For one-off cases which DON'T contain magic function calls in them you | |||
|
1516 | can obtain similar results by explicitly executing slices from your | |||
|
1517 | input history with: | |||
|
1518 | ||||
|
1519 | In [60]: exec In[44:48]+In[49]""" | |||
|
1520 | ||||
|
1521 | args = parameter_s.split() | |||
|
1522 | name,ranges = args[0], args[1:] | |||
|
1523 | #print 'rng',ranges # dbg | |||
|
1524 | cmds = self.extract_input_slices(ranges) | |||
|
1525 | macro = Macro(cmds) | |||
|
1526 | self.shell.user_ns.update({name:macro}) | |||
|
1527 | print 'Macro `%s` created. To execute, type its name (without quotes).' % name | |||
|
1528 | print 'Macro contents:' | |||
|
1529 | print str(macro).rstrip(), | |||
|
1530 | ||||
|
1531 | def magic_save(self,parameter_s = ''): | |||
|
1532 | """Save a set of lines to a given filename. | |||
|
1533 | ||||
|
1534 | Usage:\\ | |||
|
1535 | %save filename n1:n2 n3:n4 ... n5 .. n6 ... | |||
|
1536 | ||||
|
1537 | This function uses the same syntax as %macro for line extraction, but | |||
|
1538 | instead of creating a macro it saves the resulting string to the | |||
|
1539 | filename you specify. | |||
|
1540 | ||||
|
1541 | It adds a '.py' extension to the file if you don't do so yourself, and | |||
|
1542 | it asks for confirmation before overwriting existing files.""" | |||
|
1543 | ||||
|
1544 | args = parameter_s.split() | |||
|
1545 | fname,ranges = args[0], args[1:] | |||
|
1546 | if not fname.endswith('.py'): | |||
|
1547 | fname += '.py' | |||
|
1548 | if os.path.isfile(fname): | |||
|
1549 | ans = raw_input('File `%s` exists. Overwrite (y/[N])? ' % fname) | |||
|
1550 | if ans.lower() not in ['y','yes']: | |||
|
1551 | print 'Operation cancelled.' | |||
|
1552 | return | |||
|
1553 | cmds = ''.join(self.extract_input_slices(ranges)) | |||
|
1554 | f = file(fname,'w') | |||
|
1555 | f.write(cmds) | |||
|
1556 | f.close() | |||
|
1557 | print 'The following commands were written to file `%s`:' % fname | |||
|
1558 | print cmds | |||
|
1559 | ||||
|
1560 | def magic_ed(self,parameter_s = ''): | |||
|
1561 | """Alias to %edit.""" | |||
|
1562 | return self.magic_edit(parameter_s) | |||
|
1563 | ||||
|
1564 | def magic_edit(self,parameter_s = '',last_call=['','']): | |||
|
1565 | """Bring up an editor and execute the resulting code. | |||
|
1566 | ||||
|
1567 | Usage: | |||
|
1568 | %edit [options] [args] | |||
|
1569 | ||||
|
1570 | %edit runs IPython's editor hook. The default version of this hook is | |||
|
1571 | set to call the __IPYTHON__.rc.editor command. This is read from your | |||
|
1572 | environment variable $EDITOR. If this isn't found, it will default to | |||
|
1573 | vi under Linux/Unix and to notepad under Windows. See the end of this | |||
|
1574 | docstring for how to change the editor hook. | |||
|
1575 | ||||
|
1576 | You can also set the value of this editor via the command line option | |||
|
1577 | '-editor' or in your ipythonrc file. This is useful if you wish to use | |||
|
1578 | specifically for IPython an editor different from your typical default | |||
|
1579 | (and for Windows users who typically don't set environment variables). | |||
|
1580 | ||||
|
1581 | This command allows you to conveniently edit multi-line code right in | |||
|
1582 | your IPython session. | |||
|
1583 | ||||
|
1584 | If called without arguments, %edit opens up an empty editor with a | |||
|
1585 | temporary file and will execute the contents of this file when you | |||
|
1586 | close it (don't forget to save it!). | |||
|
1587 | ||||
|
1588 | Options: | |||
|
1589 | ||||
|
1590 | -p: this will call the editor with the same data as the previous time | |||
|
1591 | it was used, regardless of how long ago (in your current session) it | |||
|
1592 | was. | |||
|
1593 | ||||
|
1594 | -x: do not execute the edited code immediately upon exit. This is | |||
|
1595 | mainly useful if you are editing programs which need to be called with | |||
|
1596 | command line arguments, which you can then do using %run. | |||
|
1597 | ||||
|
1598 | Arguments: | |||
|
1599 | ||||
|
1600 | If arguments are given, the following possibilites exist: | |||
|
1601 | ||||
|
1602 | - The arguments are numbers or pairs of colon-separated numbers (like | |||
|
1603 | 1 4:8 9). These are interpreted as lines of previous input to be | |||
|
1604 | loaded into the editor. The syntax is the same of the %macro command. | |||
|
1605 | ||||
|
1606 | - If the argument doesn't start with a number, it is evaluated as a | |||
|
1607 | variable and its contents loaded into the editor. You can thus edit | |||
|
1608 | any string which contains python code (including the result of | |||
|
1609 | previous edits). | |||
|
1610 | ||||
|
1611 | - If the argument is the name of an object (other than a string), | |||
|
1612 | IPython will try to locate the file where it was defined and open the | |||
|
1613 | editor at the point where it is defined. You can use `%edit function` | |||
|
1614 | to load an editor exactly at the point where 'function' is defined, | |||
|
1615 | edit it and have the file be executed automatically. | |||
|
1616 | ||||
|
1617 | Note: opening at an exact line is only supported under Unix, and some | |||
|
1618 | editors (like kedit and gedit up to Gnome 2.8) do not understand the | |||
|
1619 | '+NUMBER' parameter necessary for this feature. Good editors like | |||
|
1620 | (X)Emacs, vi, jed, pico and joe all do. | |||
|
1621 | ||||
|
1622 | - If the argument is not found as a variable, IPython will look for a | |||
|
1623 | file with that name (adding .py if necessary) and load it into the | |||
|
1624 | editor. It will execute its contents with execfile() when you exit, | |||
|
1625 | loading any code in the file into your interactive namespace. | |||
|
1626 | ||||
|
1627 | After executing your code, %edit will return as output the code you | |||
|
1628 | typed in the editor (except when it was an existing file). This way | |||
|
1629 | you can reload the code in further invocations of %edit as a variable, | |||
|
1630 | via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of | |||
|
1631 | the output. | |||
|
1632 | ||||
|
1633 | Note that %edit is also available through the alias %ed. | |||
|
1634 | ||||
|
1635 | This is an example of creating a simple function inside the editor and | |||
|
1636 | then modifying it. First, start up the editor: | |||
|
1637 | ||||
|
1638 | In [1]: ed\\ | |||
|
1639 | Editing... done. Executing edited code...\\ | |||
|
1640 | Out[1]: 'def foo():\\n print "foo() was defined in an editing session"\\n' | |||
|
1641 | ||||
|
1642 | We can then call the function foo(): | |||
|
1643 | ||||
|
1644 | In [2]: foo()\\ | |||
|
1645 | foo() was defined in an editing session | |||
|
1646 | ||||
|
1647 | Now we edit foo. IPython automatically loads the editor with the | |||
|
1648 | (temporary) file where foo() was previously defined: | |||
|
1649 | ||||
|
1650 | In [3]: ed foo\\ | |||
|
1651 | Editing... done. Executing edited code... | |||
|
1652 | ||||
|
1653 | And if we call foo() again we get the modified version: | |||
|
1654 | ||||
|
1655 | In [4]: foo()\\ | |||
|
1656 | foo() has now been changed! | |||
|
1657 | ||||
|
1658 | Here is an example of how to edit a code snippet successive | |||
|
1659 | times. First we call the editor: | |||
|
1660 | ||||
|
1661 | In [8]: ed\\ | |||
|
1662 | Editing... done. Executing edited code...\\ | |||
|
1663 | hello\\ | |||
|
1664 | Out[8]: "print 'hello'\\n" | |||
|
1665 | ||||
|
1666 | Now we call it again with the previous output (stored in _): | |||
|
1667 | ||||
|
1668 | In [9]: ed _\\ | |||
|
1669 | Editing... done. Executing edited code...\\ | |||
|
1670 | hello world\\ | |||
|
1671 | Out[9]: "print 'hello world'\\n" | |||
|
1672 | ||||
|
1673 | Now we call it with the output #8 (stored in _8, also as Out[8]): | |||
|
1674 | ||||
|
1675 | In [10]: ed _8\\ | |||
|
1676 | Editing... done. Executing edited code...\\ | |||
|
1677 | hello again\\ | |||
|
1678 | Out[10]: "print 'hello again'\\n" | |||
|
1679 | ||||
|
1680 | ||||
|
1681 | Changing the default editor hook: | |||
|
1682 | ||||
|
1683 | If you wish to write your own editor hook, you can put it in a | |||
|
1684 | configuration file which you load at startup time. The default hook | |||
|
1685 | is defined in the IPython.hooks module, and you can use that as a | |||
|
1686 | starting example for further modifications. That file also has | |||
|
1687 | general instructions on how to set a new hook for use once you've | |||
|
1688 | defined it.""" | |||
|
1689 | ||||
|
1690 | # FIXME: This function has become a convoluted mess. It needs a | |||
|
1691 | # ground-up rewrite with clean, simple logic. | |||
|
1692 | ||||
|
1693 | def make_filename(arg): | |||
|
1694 | "Make a filename from the given args" | |||
|
1695 | try: | |||
|
1696 | filename = get_py_filename(arg) | |||
|
1697 | except IOError: | |||
|
1698 | if args.endswith('.py'): | |||
|
1699 | filename = arg | |||
|
1700 | else: | |||
|
1701 | filename = None | |||
|
1702 | return filename | |||
|
1703 | ||||
|
1704 | # custom exceptions | |||
|
1705 | class DataIsObject(Exception): pass | |||
|
1706 | ||||
|
1707 | opts,args = self.parse_options(parameter_s,'px') | |||
|
1708 | ||||
|
1709 | # Default line number value | |||
|
1710 | lineno = None | |||
|
1711 | if opts.has_key('p'): | |||
|
1712 | args = '_%s' % last_call[0] | |||
|
1713 | if not self.shell.user_ns.has_key(args): | |||
|
1714 | args = last_call[1] | |||
|
1715 | ||||
|
1716 | # use last_call to remember the state of the previous call, but don't | |||
|
1717 | # let it be clobbered by successive '-p' calls. | |||
|
1718 | try: | |||
|
1719 | last_call[0] = self.shell.outputcache.prompt_count | |||
|
1720 | if not opts.has_key('p'): | |||
|
1721 | last_call[1] = parameter_s | |||
|
1722 | except: | |||
|
1723 | pass | |||
|
1724 | ||||
|
1725 | # by default this is done with temp files, except when the given | |||
|
1726 | # arg is a filename | |||
|
1727 | use_temp = 1 | |||
|
1728 | ||||
|
1729 | if re.match(r'\d',args): | |||
|
1730 | # Mode where user specifies ranges of lines, like in %macro. | |||
|
1731 | # This means that you can't edit files whose names begin with | |||
|
1732 | # numbers this way. Tough. | |||
|
1733 | ranges = args.split() | |||
|
1734 | data = ''.join(self.extract_input_slices(ranges)) | |||
|
1735 | elif args.endswith('.py'): | |||
|
1736 | filename = make_filename(args) | |||
|
1737 | data = '' | |||
|
1738 | use_temp = 0 | |||
|
1739 | elif args: | |||
|
1740 | try: | |||
|
1741 | # Load the parameter given as a variable. If not a string, | |||
|
1742 | # process it as an object instead (below) | |||
|
1743 | ||||
|
1744 | #print '*** args',args,'type',type(args) # dbg | |||
|
1745 | data = eval(args,self.shell.user_ns) | |||
|
1746 | if not type(data) in StringTypes: | |||
|
1747 | raise DataIsObject | |||
|
1748 | except (NameError,SyntaxError): | |||
|
1749 | # given argument is not a variable, try as a filename | |||
|
1750 | filename = make_filename(args) | |||
|
1751 | if filename is None: | |||
|
1752 | warn("Argument given (%s) can't be found as a variable " | |||
|
1753 | "or as a filename." % args) | |||
|
1754 | return | |||
|
1755 | data = '' | |||
|
1756 | use_temp = 0 | |||
|
1757 | except DataIsObject: | |||
|
1758 | # For objects, try to edit the file where they are defined | |||
|
1759 | try: | |||
|
1760 | filename = inspect.getabsfile(data) | |||
|
1761 | datafile = 1 | |||
|
1762 | except TypeError: | |||
|
1763 | filename = make_filename(args) | |||
|
1764 | datafile = 1 | |||
|
1765 | warn('Could not find file where `%s` is defined.\n' | |||
|
1766 | 'Opening a file named `%s`' % (args,filename)) | |||
|
1767 | # Now, make sure we can actually read the source (if it was in | |||
|
1768 | # a temp file it's gone by now). | |||
|
1769 | if datafile: | |||
|
1770 | try: | |||
|
1771 | lineno = inspect.getsourcelines(data)[1] | |||
|
1772 | except IOError: | |||
|
1773 | filename = make_filename(args) | |||
|
1774 | if filename is None: | |||
|
1775 | warn('The file `%s` where `%s` was defined cannot ' | |||
|
1776 | 'be read.' % (filename,data)) | |||
|
1777 | return | |||
|
1778 | use_temp = 0 | |||
|
1779 | else: | |||
|
1780 | data = '' | |||
|
1781 | ||||
|
1782 | if use_temp: | |||
|
1783 | filename = tempfile.mktemp('.py') | |||
|
1784 | self.shell.tempfiles.append(filename) | |||
|
1785 | ||||
|
1786 | if data and use_temp: | |||
|
1787 | tmp_file = open(filename,'w') | |||
|
1788 | tmp_file.write(data) | |||
|
1789 | tmp_file.close() | |||
|
1790 | ||||
|
1791 | # do actual editing here | |||
|
1792 | print 'Editing...', | |||
|
1793 | sys.stdout.flush() | |||
|
1794 | self.shell.hooks.editor(filename,lineno) | |||
|
1795 | if opts.has_key('x'): # -x prevents actual execution | |||
|
1796 | ||||
|
1797 | else: | |||
|
1798 | print 'done. Executing edited code...' | |||
|
1799 | try: | |||
|
1800 | execfile(filename,self.shell.user_ns) | |||
|
1801 | except IOError,msg: | |||
|
1802 | if msg.filename == filename: | |||
|
1803 | warn('File not found. Did you forget to save?') | |||
|
1804 | return | |||
|
1805 | else: | |||
|
1806 | self.shell.showtraceback() | |||
|
1807 | except: | |||
|
1808 | self.shell.showtraceback() | |||
|
1809 | if use_temp: | |||
|
1810 | contents = open(filename).read() | |||
|
1811 | return contents | |||
|
1812 | ||||
|
1813 | def magic_xmode(self,parameter_s = ''): | |||
|
1814 | """Switch modes for the exception handlers. | |||
|
1815 | ||||
|
1816 | Valid modes: Plain, Context and Verbose. | |||
|
1817 | ||||
|
1818 | If called without arguments, acts as a toggle.""" | |||
|
1819 | ||||
|
1820 | new_mode = parameter_s.strip().capitalize() | |||
|
1821 | try: | |||
|
1822 | self.InteractiveTB.set_mode(mode = new_mode) | |||
|
1823 | print 'Exception reporting mode:',self.InteractiveTB.mode | |||
|
1824 | except: | |||
|
1825 | warn('Error changing exception modes.\n' + str(sys.exc_info()[1])) | |||
|
1826 | ||||
|
1827 | def magic_colors(self,parameter_s = ''): | |||
|
1828 | """Switch color scheme for prompts, info system and exception handlers. | |||
|
1829 | ||||
|
1830 | Currently implemented schemes: NoColor, Linux, LightBG. | |||
|
1831 | ||||
|
1832 | Color scheme names are not case-sensitive.""" | |||
|
1833 | ||||
|
1834 | new_scheme = parameter_s.strip() | |||
|
1835 | if not new_scheme: | |||
|
1836 | print 'You must specify a color scheme.' | |||
|
1837 | return | |||
|
1838 | # Under Windows, check for Gary Bishop's readline, which is necessary | |||
|
1839 | # for ANSI coloring | |||
|
1840 | if os.name in ['nt','dos']: | |||
|
1841 | try: | |||
|
1842 | import readline | |||
|
1843 | except ImportError: | |||
|
1844 | has_readline = 0 | |||
|
1845 | else: | |||
|
1846 | try: | |||
|
1847 | readline.GetOutputFile() | |||
|
1848 | except AttributeError: | |||
|
1849 | has_readline = 0 | |||
|
1850 | else: | |||
|
1851 | has_readline = 1 | |||
|
1852 | if not has_readline: | |||
|
1853 | msg = """\ | |||
|
1854 | Proper color support under MS Windows requires Gary Bishop's readline library. | |||
|
1855 | You can find it at: | |||
|
1856 | http://sourceforge.net/projects/uncpythontools | |||
|
1857 | Gary's readline needs the ctypes module, from: | |||
|
1858 | http://starship.python.net/crew/theller/ctypes | |||
|
1859 | ||||
|
1860 | Defaulting color scheme to 'NoColor'""" | |||
|
1861 | new_scheme = 'NoColor' | |||
|
1862 | warn(msg) | |||
|
1863 | ||||
|
1864 | # Set prompt colors | |||
|
1865 | try: | |||
|
1866 | self.shell.outputcache.set_colors(new_scheme) | |||
|
1867 | except: | |||
|
1868 | warn('Error changing prompt color schemes.\n' | |||
|
1869 | + str(sys.exc_info()[1])) | |||
|
1870 | else: | |||
|
1871 | self.shell.rc.colors = \ | |||
|
1872 | self.shell.outputcache.color_table.active_scheme_name | |||
|
1873 | # Set exception colors | |||
|
1874 | try: | |||
|
1875 | self.shell.InteractiveTB.set_colors(scheme = new_scheme) | |||
|
1876 | self.shell.SyntaxTB.set_colors(scheme = new_scheme) | |||
|
1877 | except: | |||
|
1878 | warn('Error changing exception color schemes.\n' | |||
|
1879 | + str(sys.exc_info()[1])) | |||
|
1880 | # Set info (for 'object?') colors | |||
|
1881 | if self.shell.rc.color_info: | |||
|
1882 | try: | |||
|
1883 | self.shell.inspector.set_active_scheme(new_scheme) | |||
|
1884 | except: | |||
|
1885 | warn('Error changing object inspector color schemes.\n' | |||
|
1886 | + str(sys.exc_info()[1])) | |||
|
1887 | else: | |||
|
1888 | self.shell.inspector.set_active_scheme('NoColor') | |||
|
1889 | ||||
|
1890 | def magic_color_info(self,parameter_s = ''): | |||
|
1891 | """Toggle color_info. | |||
|
1892 | ||||
|
1893 | The color_info configuration parameter controls whether colors are | |||
|
1894 | used for displaying object details (by things like %psource, %pfile or | |||
|
1895 | the '?' system). This function toggles this value with each call. | |||
|
1896 | ||||
|
1897 | Note that unless you have a fairly recent pager (less works better | |||
|
1898 | than more) in your system, using colored object information displays | |||
|
1899 | will not work properly. Test it and see.""" | |||
|
1900 | ||||
|
1901 | self.shell.rc.color_info = 1 - self.shell.rc.color_info | |||
|
1902 | self.magic_colors(self.shell.rc.colors) | |||
|
1903 | print 'Object introspection functions have now coloring:', | |||
|
1904 | print ['OFF','ON'][self.shell.rc.color_info] | |||
|
1905 | ||||
|
1906 | def magic_Pprint(self, parameter_s=''): | |||
|
1907 | """Toggle pretty printing on/off.""" | |||
|
1908 | ||||
|
1909 | self.shell.outputcache.Pprint = 1 - self.shell.outputcache.Pprint | |||
|
1910 | print 'Pretty printing has been turned', \ | |||
|
1911 | ['OFF','ON'][self.shell.outputcache.Pprint] | |||
|
1912 | ||||
|
1913 | def magic_Exit(self, parameter_s=''): | |||
|
1914 | """Exit IPython without confirmation.""" | |||
|
1915 | ||||
|
1916 | self.shell.exit_now = True | |||
|
1917 | ||||
|
1918 | def magic_Quit(self, parameter_s=''): | |||
|
1919 | """Exit IPython without confirmation (like %Exit).""" | |||
|
1920 | ||||
|
1921 | self.shell.exit_now = True | |||
|
1922 | ||||
|
1923 | #...................................................................... | |||
|
1924 | # Functions to implement unix shell-type things | |||
|
1925 | ||||
|
1926 | def magic_alias(self, parameter_s = ''): | |||
|
1927 | """Define an alias for a system command. | |||
|
1928 | ||||
|
1929 | '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd' | |||
|
1930 | ||||
|
1931 | Then, typing 'alias_name params' will execute the system command 'cmd | |||
|
1932 | params' (from your underlying operating system). | |||
|
1933 | ||||
|
1934 | Aliases have lower precedence than magic functions and Python normal | |||
|
1935 | variables, so if 'foo' is both a Python variable and an alias, the | |||
|
1936 | alias can not be executed until 'del foo' removes the Python variable. | |||
|
1937 | ||||
|
1938 | You can use the %l specifier in an alias definition to represent the | |||
|
1939 | whole line when the alias is called. For example: | |||
|
1940 | ||||
|
1941 | In [2]: alias all echo "Input in brackets: <%l>"\\ | |||
|
1942 | In [3]: all hello world\\ | |||
|
1943 | Input in brackets: <hello world> | |||
|
1944 | ||||
|
1945 | You can also define aliases with parameters using %s specifiers (one | |||
|
1946 | per parameter): | |||
|
1947 | ||||
|
1948 | In [1]: alias parts echo first %s second %s\\ | |||
|
1949 | In [2]: %parts A B\\ | |||
|
1950 | first A second B\\ | |||
|
1951 | In [3]: %parts A\\ | |||
|
1952 | Incorrect number of arguments: 2 expected.\\ | |||
|
1953 | parts is an alias to: 'echo first %s second %s' | |||
|
1954 | ||||
|
1955 | Note that %l and %s are mutually exclusive. You can only use one or | |||
|
1956 | the other in your aliases. | |||
|
1957 | ||||
|
1958 | Aliases expand Python variables just like system calls using ! or !! | |||
|
1959 | do: all expressions prefixed with '$' get expanded. For details of | |||
|
1960 | the semantic rules, see PEP-215: | |||
|
1961 | http://www.python.org/peps/pep-0215.html. This is the library used by | |||
|
1962 | IPython for variable expansion. If you want to access a true shell | |||
|
1963 | variable, an extra $ is necessary to prevent its expansion by IPython: | |||
|
1964 | ||||
|
1965 | In [6]: alias show echo\\ | |||
|
1966 | In [7]: PATH='A Python string'\\ | |||
|
1967 | In [8]: show $PATH\\ | |||
|
1968 | A Python string\\ | |||
|
1969 | In [9]: show $$PATH\\ | |||
|
1970 | /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... | |||
|
1971 | ||||
|
1972 | You can use the alias facility to acess all of $PATH. See the %rehash | |||
|
1973 | and %rehashx functions, which automatically create aliases for the | |||
|
1974 | contents of your $PATH. | |||
|
1975 | ||||
|
1976 | If called with no parameters, %alias prints the current alias table.""" | |||
|
1977 | ||||
|
1978 | par = parameter_s.strip() | |||
|
1979 | if not par: | |||
|
1980 | if self.shell.rc.automagic: | |||
|
1981 | prechar = '' | |||
|
1982 | else: | |||
|
1983 | prechar = self.shell.ESC_MAGIC | |||
|
1984 | print 'Alias\t\tSystem Command\n'+'-'*30 | |||
|
1985 | atab = self.shell.alias_table | |||
|
1986 | aliases = atab.keys() | |||
|
1987 | aliases.sort() | |||
|
1988 | for alias in aliases: | |||
|
1989 | print prechar+alias+'\t\t'+atab[alias][1] | |||
|
1990 | print '-'*30+'\nTotal number of aliases:',len(aliases) | |||
|
1991 | return | |||
|
1992 | try: | |||
|
1993 | alias,cmd = par.split(None,1) | |||
|
1994 | except: | |||
|
1995 | print OInspect.getdoc(self.magic_alias) | |||
|
1996 | else: | |||
|
1997 | nargs = cmd.count('%s') | |||
|
1998 | if nargs>0 and cmd.find('%l')>=0: | |||
|
1999 | error('The %s and %l specifiers are mutually exclusive ' | |||
|
2000 | 'in alias definitions.') | |||
|
2001 | else: # all looks OK | |||
|
2002 | self.shell.alias_table[alias] = (nargs,cmd) | |||
|
2003 | self.shell.alias_table_validate(verbose=1) | |||
|
2004 | # end magic_alias | |||
|
2005 | ||||
|
2006 | def magic_unalias(self, parameter_s = ''): | |||
|
2007 | """Remove an alias""" | |||
|
2008 | ||||
|
2009 | aname = parameter_s.strip() | |||
|
2010 | if aname in self.shell.alias_table: | |||
|
2011 | del self.shell.alias_table[aname] | |||
|
2012 | ||||
|
2013 | def magic_rehash(self, parameter_s = ''): | |||
|
2014 | """Update the alias table with all entries in $PATH. | |||
|
2015 | ||||
|
2016 | This version does no checks on execute permissions or whether the | |||
|
2017 | contents of $PATH are truly files (instead of directories or something | |||
|
2018 | else). For such a safer (but slower) version, use %rehashx.""" | |||
|
2019 | ||||
|
2020 | # This function (and rehashx) manipulate the alias_table directly | |||
|
2021 | # rather than calling magic_alias, for speed reasons. A rehash on a | |||
|
2022 | # typical Linux box involves several thousand entries, so efficiency | |||
|
2023 | # here is a top concern. | |||
|
2024 | ||||
|
2025 | path = filter(os.path.isdir,os.environ['PATH'].split(os.pathsep)) | |||
|
2026 | alias_table = self.shell.alias_table | |||
|
2027 | for pdir in path: | |||
|
2028 | for ff in os.listdir(pdir): | |||
|
2029 | # each entry in the alias table must be (N,name), where | |||
|
2030 | # N is the number of positional arguments of the alias. | |||
|
2031 | alias_table[ff] = (0,ff) | |||
|
2032 | # Make sure the alias table doesn't contain keywords or builtins | |||
|
2033 | self.shell.alias_table_validate() | |||
|
2034 | # Call again init_auto_alias() so we get 'rm -i' and other modified | |||
|
2035 | # aliases since %rehash will probably clobber them | |||
|
2036 | self.shell.init_auto_alias() | |||
|
2037 | ||||
|
2038 | def magic_rehashx(self, parameter_s = ''): | |||
|
2039 | """Update the alias table with all executable files in $PATH. | |||
|
2040 | ||||
|
2041 | This version explicitly checks that every entry in $PATH is a file | |||
|
2042 | with execute access (os.X_OK), so it is much slower than %rehash. | |||
|
2043 | ||||
|
2044 | Under Windows, it checks executability as a match agains a | |||
|
2045 | '|'-separated string of extensions, stored in the IPython config | |||
|
2046 | variable win_exec_ext. This defaults to 'exe|com|bat'. """ | |||
|
2047 | ||||
|
2048 | path = filter(os.path.isdir,os.environ['PATH'].split(os.pathsep)) | |||
|
2049 | alias_table = self.shell.alias_table | |||
|
2050 | ||||
|
2051 | if os.name == 'posix': | |||
|
2052 | isexec = lambda fname:os.path.isfile(fname) and \ | |||
|
2053 | os.access(fname,os.X_OK) | |||
|
2054 | else: | |||
|
2055 | ||||
|
2056 | try: | |||
|
2057 | winext = os.environ['pathext'].replace(';','|').replace('.','') | |||
|
2058 | except KeyError: | |||
|
2059 | winext = 'exe|com|bat' | |||
|
2060 | ||||
|
2061 | execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) | |||
|
2062 | isexec = lambda fname:os.path.isfile(fname) and execre.match(fname) | |||
|
2063 | savedir = os.getcwd() | |||
|
2064 | try: | |||
|
2065 | # write the whole loop for posix/Windows so we don't have an if in | |||
|
2066 | # the innermost part | |||
|
2067 | if os.name == 'posix': | |||
|
2068 | for pdir in path: | |||
|
2069 | os.chdir(pdir) | |||
|
2070 | for ff in os.listdir(pdir): | |||
|
2071 | if isexec(ff): | |||
|
2072 | # each entry in the alias table must be (N,name), | |||
|
2073 | # where N is the number of positional arguments of the | |||
|
2074 | # alias. | |||
|
2075 | alias_table[ff] = (0,ff) | |||
|
2076 | else: | |||
|
2077 | for pdir in path: | |||
|
2078 | os.chdir(pdir) | |||
|
2079 | for ff in os.listdir(pdir): | |||
|
2080 | if isexec(ff): | |||
|
2081 | alias_table[execre.sub(r'\1',ff)] = (0,ff) | |||
|
2082 | # Make sure the alias table doesn't contain keywords or builtins | |||
|
2083 | self.shell.alias_table_validate() | |||
|
2084 | # Call again init_auto_alias() so we get 'rm -i' and other | |||
|
2085 | # modified aliases since %rehashx will probably clobber them | |||
|
2086 | self.shell.init_auto_alias() | |||
|
2087 | finally: | |||
|
2088 | os.chdir(savedir) | |||
|
2089 | ||||
|
2090 | def magic_pwd(self, parameter_s = ''): | |||
|
2091 | """Return the current working directory path.""" | |||
|
2092 | return os.getcwd() | |||
|
2093 | ||||
|
2094 | def magic_cd(self, parameter_s=''): | |||
|
2095 | """Change the current working directory. | |||
|
2096 | ||||
|
2097 | This command automatically maintains an internal list of directories | |||
|
2098 | you visit during your IPython session, in the variable _dh. The | |||
|
2099 | command %dhist shows this history nicely formatted. | |||
|
2100 | ||||
|
2101 | Usage: | |||
|
2102 | ||||
|
2103 | cd 'dir': changes to directory 'dir'. | |||
|
2104 | ||||
|
2105 | cd -: changes to the last visited directory. | |||
|
2106 | ||||
|
2107 | cd -<n>: changes to the n-th directory in the directory history. | |||
|
2108 | ||||
|
2109 | cd -b <bookmark_name>: jump to a bookmark set by %bookmark | |||
|
2110 | (note: cd <bookmark_name> is enough if there is no | |||
|
2111 | directory <bookmark_name>, but a bookmark with the name exists.) | |||
|
2112 | ||||
|
2113 | Options: | |||
|
2114 | ||||
|
2115 | -q: quiet. Do not print the working directory after the cd command is | |||
|
2116 | executed. By default IPython's cd command does print this directory, | |||
|
2117 | since the default prompts do not display path information. | |||
|
2118 | ||||
|
2119 | Note that !cd doesn't work for this purpose because the shell where | |||
|
2120 | !command runs is immediately discarded after executing 'command'.""" | |||
|
2121 | ||||
|
2122 | parameter_s = parameter_s.strip() | |||
|
2123 | bkms = self.shell.persist.get("bookmarks",{}) | |||
|
2124 | ||||
|
2125 | numcd = re.match(r'(-)(\d+)$',parameter_s) | |||
|
2126 | # jump in directory history by number | |||
|
2127 | if numcd: | |||
|
2128 | nn = int(numcd.group(2)) | |||
|
2129 | try: | |||
|
2130 | ps = self.shell.user_ns['_dh'][nn] | |||
|
2131 | except IndexError: | |||
|
2132 | print 'The requested directory does not exist in history.' | |||
|
2133 | return | |||
|
2134 | else: | |||
|
2135 | opts = {} | |||
|
2136 | else: | |||
|
2137 | opts,ps = self.parse_options(parameter_s,'qb',mode='string') | |||
|
2138 | # jump to previous | |||
|
2139 | if ps == '-': | |||
|
2140 | try: | |||
|
2141 | ps = self.shell.user_ns['_dh'][-2] | |||
|
2142 | except IndexError: | |||
|
2143 | print 'No previous directory to change to.' | |||
|
2144 | return | |||
|
2145 | # jump to bookmark | |||
|
2146 | elif opts.has_key('b') or (bkms.has_key(ps) and not os.path.isdir(ps)): | |||
|
2147 | if bkms.has_key(ps): | |||
|
2148 | target = bkms[ps] | |||
|
2149 | print '(bookmark:%s) -> %s' % (ps,target) | |||
|
2150 | ps = target | |||
|
2151 | else: | |||
|
2152 | if bkms: | |||
|
2153 | error("Bookmark '%s' not found. " | |||
|
2154 | "Use '%bookmark -l' to see your bookmarks." % ps) | |||
|
2155 | else: | |||
|
2156 | print "Bookmarks not set - use %bookmark <bookmarkname>" | |||
|
2157 | return | |||
|
2158 | ||||
|
2159 | # at this point ps should point to the target dir | |||
|
2160 | if ps: | |||
|
2161 | try: | |||
|
2162 | os.chdir(os.path.expanduser(ps)) | |||
|
2163 | except OSError: | |||
|
2164 | print sys.exc_info()[1] | |||
|
2165 | else: | |||
|
2166 | self.shell.user_ns['_dh'].append(os.getcwd()) | |||
|
2167 | else: | |||
|
2168 | os.chdir(self.home_dir) | |||
|
2169 | self.shell.user_ns['_dh'].append(os.getcwd()) | |||
|
2170 | if not 'q' in opts: | |||
|
2171 | print self.shell.user_ns['_dh'][-1] | |||
|
2172 | ||||
|
2173 | def magic_dhist(self, parameter_s=''): | |||
|
2174 | """Print your history of visited directories. | |||
|
2175 | ||||
|
2176 | %dhist -> print full history\\ | |||
|
2177 | %dhist n -> print last n entries only\\ | |||
|
2178 | %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\ | |||
|
2179 | ||||
|
2180 | This history is automatically maintained by the %cd command, and | |||
|
2181 | always available as the global list variable _dh. You can use %cd -<n> | |||
|
2182 | to go to directory number <n>.""" | |||
|
2183 | ||||
|
2184 | dh = self.shell.user_ns['_dh'] | |||
|
2185 | if parameter_s: | |||
|
2186 | try: | |||
|
2187 | args = map(int,parameter_s.split()) | |||
|
2188 | except: | |||
|
2189 | self.arg_err(Magic.magic_dhist) | |||
|
2190 | return | |||
|
2191 | if len(args) == 1: | |||
|
2192 | ini,fin = max(len(dh)-(args[0]),0),len(dh) | |||
|
2193 | elif len(args) == 2: | |||
|
2194 | ini,fin = args | |||
|
2195 | else: | |||
|
2196 | self.arg_err(Magic.magic_dhist) | |||
|
2197 | return | |||
|
2198 | else: | |||
|
2199 | ini,fin = 0,len(dh) | |||
|
2200 | nlprint(dh, | |||
|
2201 | header = 'Directory history (kept in _dh)', | |||
|
2202 | start=ini,stop=fin) | |||
|
2203 | ||||
|
2204 | def magic_env(self, parameter_s=''): | |||
|
2205 | """List environment variables.""" | |||
|
2206 | ||||
|
2207 | # environ is an instance of UserDict | |||
|
2208 | return os.environ.data | |||
|
2209 | ||||
|
2210 | def magic_pushd(self, parameter_s=''): | |||
|
2211 | """Place the current dir on stack and change directory. | |||
|
2212 | ||||
|
2213 | Usage:\\ | |||
|
2214 | %pushd ['dirname'] | |||
|
2215 | ||||
|
2216 | %pushd with no arguments does a %pushd to your home directory. | |||
|
2217 | """ | |||
|
2218 | if parameter_s == '': parameter_s = '~' | |||
|
2219 | if len(self.dir_stack)>0 and os.path.expanduser(parameter_s) != \ | |||
|
2220 | os.path.expanduser(self.dir_stack[0]): | |||
|
2221 | try: | |||
|
2222 | self.magic_cd(parameter_s) | |||
|
2223 | self.dir_stack.insert(0,os.getcwd().replace(self.home_dir,'~')) | |||
|
2224 | self.magic_dirs() | |||
|
2225 | except: | |||
|
2226 | print 'Invalid directory' | |||
|
2227 | else: | |||
|
2228 | print 'You are already there!' | |||
|
2229 | ||||
|
2230 | def magic_popd(self, parameter_s=''): | |||
|
2231 | """Change to directory popped off the top of the stack. | |||
|
2232 | """ | |||
|
2233 | if len (self.dir_stack) > 1: | |||
|
2234 | self.dir_stack.pop(0) | |||
|
2235 | self.magic_cd(self.dir_stack[0]) | |||
|
2236 | print self.dir_stack[0] | |||
|
2237 | else: | |||
|
2238 | print "You can't remove the starting directory from the stack:",\ | |||
|
2239 | self.dir_stack | |||
|
2240 | ||||
|
2241 | def magic_dirs(self, parameter_s=''): | |||
|
2242 | """Return the current directory stack.""" | |||
|
2243 | ||||
|
2244 | return self.dir_stack[:] | |||
|
2245 | ||||
|
2246 | def magic_sc(self, parameter_s=''): | |||
|
2247 | """Shell capture - execute a shell command and capture its output. | |||
|
2248 | ||||
|
2249 | %sc [options] varname=command | |||
|
2250 | ||||
|
2251 | IPython will run the given command using commands.getoutput(), and | |||
|
2252 | will then update the user's interactive namespace with a variable | |||
|
2253 | called varname, containing the value of the call. Your command can | |||
|
2254 | contain shell wildcards, pipes, etc. | |||
|
2255 | ||||
|
2256 | The '=' sign in the syntax is mandatory, and the variable name you | |||
|
2257 | supply must follow Python's standard conventions for valid names. | |||
|
2258 | ||||
|
2259 | Options: | |||
|
2260 | ||||
|
2261 | -l: list output. Split the output on newlines into a list before | |||
|
2262 | assigning it to the given variable. By default the output is stored | |||
|
2263 | as a single string. | |||
|
2264 | ||||
|
2265 | -v: verbose. Print the contents of the variable. | |||
|
2266 | ||||
|
2267 | In most cases you should not need to split as a list, because the | |||
|
2268 | returned value is a special type of string which can automatically | |||
|
2269 | provide its contents either as a list (split on newlines) or as a | |||
|
2270 | space-separated string. These are convenient, respectively, either | |||
|
2271 | for sequential processing or to be passed to a shell command. | |||
|
2272 | ||||
|
2273 | For example: | |||
|
2274 | ||||
|
2275 | # Capture into variable a | |||
|
2276 | In [9]: sc a=ls *py | |||
|
2277 | ||||
|
2278 | # a is a string with embedded newlines | |||
|
2279 | In [10]: a | |||
|
2280 | Out[10]: 'setup.py\nwin32_manual_post_install.py' | |||
|
2281 | ||||
|
2282 | # which can be seen as a list: | |||
|
2283 | In [11]: a.l | |||
|
2284 | Out[11]: ['setup.py', 'win32_manual_post_install.py'] | |||
|
2285 | ||||
|
2286 | # or as a whitespace-separated string: | |||
|
2287 | In [12]: a.s | |||
|
2288 | Out[12]: 'setup.py win32_manual_post_install.py' | |||
|
2289 | ||||
|
2290 | # a.s is useful to pass as a single command line: | |||
|
2291 | In [13]: !wc -l $a.s | |||
|
2292 | 146 setup.py | |||
|
2293 | 130 win32_manual_post_install.py | |||
|
2294 | 276 total | |||
|
2295 | ||||
|
2296 | # while the list form is useful to loop over: | |||
|
2297 | In [14]: for f in a.l: | |||
|
2298 | ....: !wc -l $f | |||
|
2299 | ....: | |||
|
2300 | 146 setup.py | |||
|
2301 | 130 win32_manual_post_install.py | |||
|
2302 | ||||
|
2303 | Similiarly, the lists returned by the -l option are also special, in | |||
|
2304 | the sense that you can equally invoke the .s attribute on them to | |||
|
2305 | automatically get a whitespace-separated string from their contents: | |||
|
2306 | ||||
|
2307 | In [1]: sc -l b=ls *py | |||
|
2308 | ||||
|
2309 | In [2]: b | |||
|
2310 | Out[2]: ['setup.py', 'win32_manual_post_install.py'] | |||
|
2311 | ||||
|
2312 | In [3]: b.s | |||
|
2313 | Out[3]: 'setup.py win32_manual_post_install.py' | |||
|
2314 | ||||
|
2315 | In summary, both the lists and strings used for ouptut capture have | |||
|
2316 | the following special attributes: | |||
|
2317 | ||||
|
2318 | .l (or .list) : value as list. | |||
|
2319 | .n (or .nlstr): value as newline-separated string. | |||
|
2320 | .s (or .spstr): value as space-separated string. | |||
|
2321 | """ | |||
|
2322 | ||||
|
2323 | opts,args = self.parse_options(parameter_s,'lv') | |||
|
2324 | # Try to get a variable name and command to run | |||
|
2325 | try: | |||
|
2326 | # the variable name must be obtained from the parse_options | |||
|
2327 | # output, which uses shlex.split to strip options out. | |||
|
2328 | var,_ = args.split('=',1) | |||
|
2329 | var = var.strip() | |||
|
2330 | # But the the command has to be extracted from the original input | |||
|
2331 | # parameter_s, not on what parse_options returns, to avoid the | |||
|
2332 | # quote stripping which shlex.split performs on it. | |||
|
2333 | _,cmd = parameter_s.split('=',1) | |||
|
2334 | except ValueError: | |||
|
2335 | var,cmd = '','' | |||
|
2336 | if not var: | |||
|
2337 | error('you must specify a variable to assign the command to.') | |||
|
2338 | return | |||
|
2339 | # If all looks ok, proceed | |||
|
2340 | out,err = self.shell.getoutputerror(cmd) | |||
|
2341 | if err: | |||
|
2342 | print >> Term.cerr,err | |||
|
2343 | if opts.has_key('l'): | |||
|
2344 | out = SList(out.split('\n')) | |||
|
2345 | else: | |||
|
2346 | out = LSString(out) | |||
|
2347 | if opts.has_key('v'): | |||
|
2348 | print '%s ==\n%s' % (var,pformat(out)) | |||
|
2349 | self.shell.user_ns.update({var:out}) | |||
|
2350 | ||||
|
2351 | def magic_sx(self, parameter_s=''): | |||
|
2352 | """Shell execute - run a shell command and capture its output. | |||
|
2353 | ||||
|
2354 | %sx command | |||
|
2355 | ||||
|
2356 | IPython will run the given command using commands.getoutput(), and | |||
|
2357 | return the result formatted as a list (split on '\\n'). Since the | |||
|
2358 | output is _returned_, it will be stored in ipython's regular output | |||
|
2359 | cache Out[N] and in the '_N' automatic variables. | |||
|
2360 | ||||
|
2361 | Notes: | |||
|
2362 | ||||
|
2363 | 1) If an input line begins with '!!', then %sx is automatically | |||
|
2364 | invoked. That is, while: | |||
|
2365 | !ls | |||
|
2366 | causes ipython to simply issue system('ls'), typing | |||
|
2367 | !!ls | |||
|
2368 | is a shorthand equivalent to: | |||
|
2369 | %sx ls | |||
|
2370 | ||||
|
2371 | 2) %sx differs from %sc in that %sx automatically splits into a list, | |||
|
2372 | like '%sc -l'. The reason for this is to make it as easy as possible | |||
|
2373 | to process line-oriented shell output via further python commands. | |||
|
2374 | %sc is meant to provide much finer control, but requires more | |||
|
2375 | typing. | |||
|
2376 | ||||
|
2377 | 3) Just like %sc -l, this is a list with special attributes: | |||
|
2378 | ||||
|
2379 | .l (or .list) : value as list. | |||
|
2380 | .n (or .nlstr): value as newline-separated string. | |||
|
2381 | .s (or .spstr): value as whitespace-separated string. | |||
|
2382 | ||||
|
2383 | This is very useful when trying to use such lists as arguments to | |||
|
2384 | system commands.""" | |||
|
2385 | ||||
|
2386 | if parameter_s: | |||
|
2387 | out,err = self.shell.getoutputerror(parameter_s) | |||
|
2388 | if err: | |||
|
2389 | print >> Term.cerr,err | |||
|
2390 | return SList(out.split('\n')) | |||
|
2391 | ||||
|
2392 | def magic_bg(self, parameter_s=''): | |||
|
2393 | """Run a job in the background, in a separate thread. | |||
|
2394 | ||||
|
2395 | For example, | |||
|
2396 | ||||
|
2397 | %bg myfunc(x,y,z=1) | |||
|
2398 | ||||
|
2399 | will execute 'myfunc(x,y,z=1)' in a background thread. As soon as the | |||
|
2400 | execution starts, a message will be printed indicating the job | |||
|
2401 | number. If your job number is 5, you can use | |||
|
2402 | ||||
|
2403 | myvar = jobs.result(5) or myvar = jobs[5].result | |||
|
2404 | ||||
|
2405 | to assign this result to variable 'myvar'. | |||
|
2406 | ||||
|
2407 | IPython has a job manager, accessible via the 'jobs' object. You can | |||
|
2408 | type jobs? to get more information about it, and use jobs.<TAB> to see | |||
|
2409 | its attributes. All attributes not starting with an underscore are | |||
|
2410 | meant for public use. | |||
|
2411 | ||||
|
2412 | In particular, look at the jobs.new() method, which is used to create | |||
|
2413 | new jobs. This magic %bg function is just a convenience wrapper | |||
|
2414 | around jobs.new(), for expression-based jobs. If you want to create a | |||
|
2415 | new job with an explicit function object and arguments, you must call | |||
|
2416 | jobs.new() directly. | |||
|
2417 | ||||
|
2418 | The jobs.new docstring also describes in detail several important | |||
|
2419 | caveats associated with a thread-based model for background job | |||
|
2420 | execution. Type jobs.new? for details. | |||
|
2421 | ||||
|
2422 | You can check the status of all jobs with jobs.status(). | |||
|
2423 | ||||
|
2424 | The jobs variable is set by IPython into the Python builtin namespace. | |||
|
2425 | If you ever declare a variable named 'jobs', you will shadow this | |||
|
2426 | name. You can either delete your global jobs variable to regain | |||
|
2427 | access to the job manager, or make a new name and assign it manually | |||
|
2428 | to the manager (stored in IPython's namespace). For example, to | |||
|
2429 | assign the job manager to the Jobs name, use: | |||
|
2430 | ||||
|
2431 | Jobs = __builtins__.jobs""" | |||
|
2432 | ||||
|
2433 | self.shell.jobs.new(parameter_s,self.shell.user_ns) | |||
|
2434 | ||||
|
2435 | def magic_bookmark(self, parameter_s=''): | |||
|
2436 | """Manage IPython's bookmark system. | |||
|
2437 | ||||
|
2438 | %bookmark <name> - set bookmark to current dir | |||
|
2439 | %bookmark <name> <dir> - set bookmark to <dir> | |||
|
2440 | %bookmark -l - list all bookmarks | |||
|
2441 | %bookmark -d <name> - remove bookmark | |||
|
2442 | %bookmark -r - remove all bookmarks | |||
|
2443 | ||||
|
2444 | You can later on access a bookmarked folder with: | |||
|
2445 | %cd -b <name> | |||
|
2446 | or simply '%cd <name>' if there is no directory called <name> AND | |||
|
2447 | there is such a bookmark defined. | |||
|
2448 | ||||
|
2449 | Your bookmarks persist through IPython sessions, but they are | |||
|
2450 | associated with each profile.""" | |||
|
2451 | ||||
|
2452 | opts,args = self.parse_options(parameter_s,'drl',mode='list') | |||
|
2453 | if len(args) > 2: | |||
|
2454 | error('You can only give at most two arguments') | |||
|
2455 | return | |||
|
2456 | ||||
|
2457 | bkms = self.shell.persist.get('bookmarks',{}) | |||
|
2458 | ||||
|
2459 | if opts.has_key('d'): | |||
|
2460 | try: | |||
|
2461 | todel = args[0] | |||
|
2462 | except IndexError: | |||
|
2463 | error('You must provide a bookmark to delete') | |||
|
2464 | else: | |||
|
2465 | try: | |||
|
2466 | del bkms[todel] | |||
|
2467 | except: | |||
|
2468 | error("Can't delete bookmark '%s'" % todel) | |||
|
2469 | elif opts.has_key('r'): | |||
|
2470 | bkms = {} | |||
|
2471 | elif opts.has_key('l'): | |||
|
2472 | bks = bkms.keys() | |||
|
2473 | bks.sort() | |||
|
2474 | if bks: | |||
|
2475 | size = max(map(len,bks)) | |||
|
2476 | else: | |||
|
2477 | size = 0 | |||
|
2478 | fmt = '%-'+str(size)+'s -> %s' | |||
|
2479 | print 'Current bookmarks:' | |||
|
2480 | for bk in bks: | |||
|
2481 | print fmt % (bk,bkms[bk]) | |||
|
2482 | else: | |||
|
2483 | if not args: | |||
|
2484 | error("You must specify the bookmark name") | |||
|
2485 | elif len(args)==1: | |||
|
2486 | bkms[args[0]] = os.getcwd() | |||
|
2487 | elif len(args)==2: | |||
|
2488 | bkms[args[0]] = args[1] | |||
|
2489 | self.persist['bookmarks'] = bkms | |||
|
2490 | # end Magic |
@@ -0,0 +1,398 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Tools for inspecting Python objects. | |||
|
3 | ||||
|
4 | Uses syntax highlighting for presenting the various information elements. | |||
|
5 | ||||
|
6 | Similar in spirit to the inspect module, but all calls take a name argument to | |||
|
7 | reference the name under which an object is being read. | |||
|
8 | ||||
|
9 | $Id: OInspect.py 575 2005-04-08 14:16:44Z fperez $ | |||
|
10 | """ | |||
|
11 | ||||
|
12 | #***************************************************************************** | |||
|
13 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
14 | # | |||
|
15 | # Distributed under the terms of the BSD License. The full license is in | |||
|
16 | # the file COPYING, distributed as part of this software. | |||
|
17 | #***************************************************************************** | |||
|
18 | ||||
|
19 | from IPython import Release | |||
|
20 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
21 | __license__ = Release.license | |||
|
22 | ||||
|
23 | __all__ = ['Inspector','InspectColors'] | |||
|
24 | ||||
|
25 | # stdlib modules | |||
|
26 | import inspect,linecache,types,StringIO,string | |||
|
27 | ||||
|
28 | # IPython's own | |||
|
29 | from IPython.Itpl import itpl | |||
|
30 | from IPython.genutils import page,indent,Term | |||
|
31 | from IPython import PyColorize | |||
|
32 | from IPython.ColorANSI import * | |||
|
33 | ||||
|
34 | #**************************************************************************** | |||
|
35 | # Builtin color schemes | |||
|
36 | ||||
|
37 | Colors = TermColors # just a shorthand | |||
|
38 | ||||
|
39 | # Build a few color schemes | |||
|
40 | NoColor = ColorScheme( | |||
|
41 | 'NoColor',{ | |||
|
42 | 'header' : Colors.NoColor, | |||
|
43 | 'normal' : Colors.NoColor # color off (usu. Colors.Normal) | |||
|
44 | } ) | |||
|
45 | ||||
|
46 | LinuxColors = ColorScheme( | |||
|
47 | 'Linux',{ | |||
|
48 | 'header' : Colors.LightRed, | |||
|
49 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) | |||
|
50 | } ) | |||
|
51 | ||||
|
52 | LightBGColors = ColorScheme( | |||
|
53 | 'LightBG',{ | |||
|
54 | 'header' : Colors.Red, | |||
|
55 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) | |||
|
56 | } ) | |||
|
57 | ||||
|
58 | # Build table of color schemes (needed by the parser) | |||
|
59 | InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors], | |||
|
60 | 'Linux') | |||
|
61 | ||||
|
62 | #**************************************************************************** | |||
|
63 | # Auxiliary functions | |||
|
64 | def getdoc(obj): | |||
|
65 | """Stable wrapper around inspect.getdoc. | |||
|
66 | ||||
|
67 | This can't crash because of attribute problems. | |||
|
68 | ||||
|
69 | It also attempts to call a getdoc() method on the given object. This | |||
|
70 | allows objects which provide their docstrings via non-standard mechanisms | |||
|
71 | (like Pyro proxies) to still be inspected by ipython's ? system.""" | |||
|
72 | ||||
|
73 | ds = None # default return value | |||
|
74 | try: | |||
|
75 | ds = inspect.getdoc(obj) | |||
|
76 | except: | |||
|
77 | # Harden against an inspect failure, which can occur with | |||
|
78 | # SWIG-wrapped extensions. | |||
|
79 | pass | |||
|
80 | # Allow objects to offer customized documentation via a getdoc method: | |||
|
81 | try: | |||
|
82 | ds2 = obj.getdoc() | |||
|
83 | except: | |||
|
84 | pass | |||
|
85 | else: | |||
|
86 | # if we get extra info, we add it to the normal docstring. | |||
|
87 | if ds is None: | |||
|
88 | ds = ds2 | |||
|
89 | else: | |||
|
90 | ds = '%s\n%s' % (ds,ds2) | |||
|
91 | return ds | |||
|
92 | ||||
|
93 | #**************************************************************************** | |||
|
94 | # Class definitions | |||
|
95 | ||||
|
96 | class myStringIO(StringIO.StringIO): | |||
|
97 | """Adds a writeln method to normal StringIO.""" | |||
|
98 | def writeln(self,*arg,**kw): | |||
|
99 | """Does a write() and then a write('\n')""" | |||
|
100 | self.write(*arg,**kw) | |||
|
101 | self.write('\n') | |||
|
102 | ||||
|
103 | class Inspector: | |||
|
104 | def __init__(self,color_table,code_color_table,scheme): | |||
|
105 | self.color_table = color_table | |||
|
106 | self.parser = PyColorize.Parser(code_color_table,out='str') | |||
|
107 | self.format = self.parser.format | |||
|
108 | self.set_active_scheme(scheme) | |||
|
109 | ||||
|
110 | def __getargspec(self,obj): | |||
|
111 | """Get the names and default values of a function's arguments. | |||
|
112 | ||||
|
113 | A tuple of four things is returned: (args, varargs, varkw, defaults). | |||
|
114 | 'args' is a list of the argument names (it may contain nested lists). | |||
|
115 | 'varargs' and 'varkw' are the names of the * and ** arguments or None. | |||
|
116 | 'defaults' is an n-tuple of the default values of the last n arguments. | |||
|
117 | ||||
|
118 | Modified version of inspect.getargspec from the Python Standard | |||
|
119 | Library.""" | |||
|
120 | ||||
|
121 | if inspect.isfunction(obj): | |||
|
122 | func_obj = obj | |||
|
123 | elif inspect.ismethod(obj): | |||
|
124 | func_obj = obj.im_func | |||
|
125 | else: | |||
|
126 | raise TypeError, 'arg is not a Python function' | |||
|
127 | args, varargs, varkw = inspect.getargs(func_obj.func_code) | |||
|
128 | return args, varargs, varkw, func_obj.func_defaults | |||
|
129 | ||||
|
130 | def __getdef(self,obj,oname=''): | |||
|
131 | """Return the definition header for any callable object. | |||
|
132 | ||||
|
133 | If any exception is generated, None is returned instead and the | |||
|
134 | exception is suppressed.""" | |||
|
135 | ||||
|
136 | try: | |||
|
137 | return oname + inspect.formatargspec(*self.__getargspec(obj)) | |||
|
138 | except: | |||
|
139 | return None | |||
|
140 | ||||
|
141 | def __head(self,h): | |||
|
142 | """Return a header string with proper colors.""" | |||
|
143 | return '%s%s%s' % (self.color_table.active_colors.header,h, | |||
|
144 | self.color_table.active_colors.normal) | |||
|
145 | ||||
|
146 | def set_active_scheme(self,scheme): | |||
|
147 | self.color_table.set_active_scheme(scheme) | |||
|
148 | self.parser.color_table.set_active_scheme(scheme) | |||
|
149 | ||||
|
150 | def noinfo(self,msg,oname): | |||
|
151 | """Generic message when no information is found.""" | |||
|
152 | print 'No %s found' % msg, | |||
|
153 | if oname: | |||
|
154 | print 'for %s' % oname | |||
|
155 | else: | |||
|
156 | ||||
|
157 | ||||
|
158 | def pdef(self,obj,oname=''): | |||
|
159 | """Print the definition header for any callable object. | |||
|
160 | ||||
|
161 | If the object is a class, print the constructor information.""" | |||
|
162 | ||||
|
163 | if not callable(obj): | |||
|
164 | print 'Object is not callable.' | |||
|
165 | return | |||
|
166 | ||||
|
167 | header = '' | |||
|
168 | if type(obj) is types.ClassType: | |||
|
169 | header = self.__head('Class constructor information:\n') | |||
|
170 | obj = obj.__init__ | |||
|
171 | elif type(obj) is types.InstanceType: | |||
|
172 | obj = obj.__call__ | |||
|
173 | ||||
|
174 | output = self.__getdef(obj,oname) | |||
|
175 | if output is None: | |||
|
176 | self.noinfo('definition header',oname) | |||
|
177 | else: | |||
|
178 | print >>Term.cout, header,self.format(output), | |||
|
179 | ||||
|
180 | def pdoc(self,obj,oname='',formatter = None): | |||
|
181 | """Print the docstring for any object. | |||
|
182 | ||||
|
183 | Optional: | |||
|
184 | -formatter: a function to run the docstring through for specially | |||
|
185 | formatted docstrings.""" | |||
|
186 | ||||
|
187 | head = self.__head # so that itpl can find it even if private | |||
|
188 | ds = getdoc(obj) | |||
|
189 | if formatter: | |||
|
190 | ds = formatter(ds) | |||
|
191 | if type(obj) is types.ClassType: | |||
|
192 | init_ds = getdoc(obj.__init__) | |||
|
193 | output = itpl('$head("Class Docstring:")\n' | |||
|
194 | '$indent(ds)\n' | |||
|
195 | '$head("Constructor Docstring"):\n' | |||
|
196 | '$indent(init_ds)') | |||
|
197 | elif type(obj) is types.InstanceType and hasattr(obj,'__call__'): | |||
|
198 | call_ds = getdoc(obj.__call__) | |||
|
199 | if call_ds: | |||
|
200 | output = itpl('$head("Class Docstring:")\n$indent(ds)\n' | |||
|
201 | '$head("Calling Docstring:")\n$indent(call_ds)') | |||
|
202 | else: | |||
|
203 | output = ds | |||
|
204 | else: | |||
|
205 | output = ds | |||
|
206 | if output is None: | |||
|
207 | self.noinfo('documentation',oname) | |||
|
208 | return | |||
|
209 | page(output) | |||
|
210 | ||||
|
211 | def psource(self,obj,oname=''): | |||
|
212 | """Print the source code for an object.""" | |||
|
213 | ||||
|
214 | # Flush the source cache because inspect can return out-of-date source | |||
|
215 | linecache.checkcache() | |||
|
216 | try: | |||
|
217 | src = inspect.getsource(obj) | |||
|
218 | except: | |||
|
219 | self.noinfo('source',oname) | |||
|
220 | else: | |||
|
221 | page(self.format(src)) | |||
|
222 | ||||
|
223 | def pfile(self,obj,oname=''): | |||
|
224 | """Show the whole file where an object was defined.""" | |||
|
225 | try: | |||
|
226 | sourcelines,lineno = inspect.getsourcelines(obj) | |||
|
227 | except: | |||
|
228 | self.noinfo('file',oname) | |||
|
229 | else: | |||
|
230 | # run contents of file through pager starting at line | |||
|
231 | # where the object is defined | |||
|
232 | page(self.format(open(inspect.getabsfile(obj)).read()),lineno) | |||
|
233 | ||||
|
234 | def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0): | |||
|
235 | """Show detailed information about an object. | |||
|
236 | ||||
|
237 | Optional arguments: | |||
|
238 | ||||
|
239 | - oname: name of the variable pointing to the object. | |||
|
240 | ||||
|
241 | - formatter: special formatter for docstrings (see pdoc) | |||
|
242 | ||||
|
243 | - info: a structure with some information fields which may have been | |||
|
244 | precomputed already. | |||
|
245 | ||||
|
246 | - detail_level: if set to 1, more information is given. | |||
|
247 | """ | |||
|
248 | ||||
|
249 | obj_type = type(obj) | |||
|
250 | ||||
|
251 | header = self.__head | |||
|
252 | if info is None: | |||
|
253 | ismagic = 0 | |||
|
254 | isalias = 0 | |||
|
255 | ospace = '' | |||
|
256 | else: | |||
|
257 | ismagic = info.ismagic | |||
|
258 | isalias = info.isalias | |||
|
259 | ospace = info.namespace | |||
|
260 | # Get docstring, special-casing aliases: | |||
|
261 | if isalias: | |||
|
262 | ds = "Alias to the system command:\n %s" % obj[1] | |||
|
263 | else: | |||
|
264 | ds = getdoc(obj) | |||
|
265 | if formatter is not None: | |||
|
266 | ds = formatter(ds) | |||
|
267 | ||||
|
268 | # store output in a list which gets joined with \n at the end. | |||
|
269 | out = myStringIO() | |||
|
270 | ||||
|
271 | string_max = 200 # max size of strings to show (snipped if longer) | |||
|
272 | shalf = int((string_max -5)/2) | |||
|
273 | ||||
|
274 | if ismagic: | |||
|
275 | obj_type_name = 'Magic function' | |||
|
276 | elif isalias: | |||
|
277 | obj_type_name = 'System alias' | |||
|
278 | else: | |||
|
279 | obj_type_name = obj_type.__name__ | |||
|
280 | out.writeln(header('Type:\t\t')+obj_type_name) | |||
|
281 | ||||
|
282 | try: | |||
|
283 | bclass = obj.__class__ | |||
|
284 | out.writeln(header('Base Class:\t')+str(bclass)) | |||
|
285 | except: pass | |||
|
286 | ||||
|
287 | # String form, but snip if too long in ? form (full in ??) | |||
|
288 | try: | |||
|
289 | ostr = str(obj) | |||
|
290 | str_head = 'String Form:' | |||
|
291 | if not detail_level and len(ostr)>string_max: | |||
|
292 | ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] | |||
|
293 | ostr = ("\n" + " " * len(str_head.expandtabs())).\ | |||
|
294 | join(map(string.strip,ostr.split("\n"))) | |||
|
295 | if ostr.find('\n') > -1: | |||
|
296 | # Print multi-line strings starting at the next line. | |||
|
297 | str_sep = '\n' | |||
|
298 | else: | |||
|
299 | str_sep = '\t' | |||
|
300 | out.writeln("%s%s%s" % (header(str_head),str_sep,ostr)) | |||
|
301 | except: | |||
|
302 | pass | |||
|
303 | ||||
|
304 | if ospace: | |||
|
305 | out.writeln(header('Namespace:\t')+ospace) | |||
|
306 | ||||
|
307 | # Length (for strings and lists) | |||
|
308 | try: | |||
|
309 | length = str(len(obj)) | |||
|
310 | out.writeln(header('Length:\t\t')+length) | |||
|
311 | except: pass | |||
|
312 | ||||
|
313 | # Filename where object was defined | |||
|
314 | try: | |||
|
315 | file = inspect.getabsfile(obj) | |||
|
316 | if file.endswith('<string>'): | |||
|
317 | file = 'Dynamically generated function. No source code available.' | |||
|
318 | out.writeln(header('File:\t\t')+file) | |||
|
319 | except: pass | |||
|
320 | ||||
|
321 | # reconstruct the function definition and print it: | |||
|
322 | defln = self.__getdef(obj,oname) | |||
|
323 | if defln: | |||
|
324 | out.write(header('Definition:\t')+self.format(defln)) | |||
|
325 | ||||
|
326 | # Docstrings only in detail 0 mode, since source contains them (we | |||
|
327 | # avoid repetitions). If source fails, we add them back, see below. | |||
|
328 | if ds and detail_level == 0: | |||
|
329 | out.writeln(header('Docstring:\n') + indent(ds)) | |||
|
330 | ||||
|
331 | # Original source code for any callable | |||
|
332 | if detail_level: | |||
|
333 | # Flush the source cache because inspect can return out-of-date source | |||
|
334 | linecache.checkcache() | |||
|
335 | try: | |||
|
336 | source = self.format(inspect.getsource(obj)) | |||
|
337 | out.write(header('Source:\n')+source.rstrip()) | |||
|
338 | except: | |||
|
339 | if ds: | |||
|
340 | out.writeln(header('Docstring:\n') + indent(ds)) | |||
|
341 | ||||
|
342 | # Constructor docstring for classes | |||
|
343 | if obj_type is types.ClassType: | |||
|
344 | # reconstruct the function definition and print it: | |||
|
345 | try: | |||
|
346 | obj_init = obj.__init__ | |||
|
347 | except AttributeError: | |||
|
348 | init_def = init_ds = None | |||
|
349 | else: | |||
|
350 | init_def = self.__getdef(obj_init,oname) | |||
|
351 | init_ds = getdoc(obj_init) | |||
|
352 | ||||
|
353 | if init_def or init_ds: | |||
|
354 | out.writeln(header('\nConstructor information:')) | |||
|
355 | if init_def: | |||
|
356 | out.write(header('Definition:\t')+ self.format(init_def)) | |||
|
357 | if init_ds: | |||
|
358 | out.writeln(header('Docstring:\n') + indent(init_ds)) | |||
|
359 | # and class docstring for instances: | |||
|
360 | elif obj_type is types.InstanceType: | |||
|
361 | ||||
|
362 | # First, check whether the instance docstring is identical to the | |||
|
363 | # class one, and print it separately if they don't coincide. In | |||
|
364 | # most cases they will, but it's nice to print all the info for | |||
|
365 | # objects which use instance-customized docstrings. | |||
|
366 | if ds: | |||
|
367 | class_ds = getdoc(obj.__class__) | |||
|
368 | if class_ds and ds != class_ds: | |||
|
369 | out.writeln(header('Class Docstring:\n') + | |||
|
370 | indent(class_ds)) | |||
|
371 | ||||
|
372 | # Next, try to show constructor docstrings | |||
|
373 | try: | |||
|
374 | init_ds = getdoc(obj.__init__) | |||
|
375 | except AttributeError: | |||
|
376 | init_ds = None | |||
|
377 | if init_ds: | |||
|
378 | out.writeln(header('Constructor Docstring:\n') + | |||
|
379 | indent(init_ds)) | |||
|
380 | ||||
|
381 | # Call form docstring for callable instances | |||
|
382 | if hasattr(obj,'__call__'): | |||
|
383 | out.writeln(header('Callable:\t')+'Yes') | |||
|
384 | call_def = self.__getdef(obj.__call__,oname) | |||
|
385 | if call_def is None: | |||
|
386 | out.write(header('Call def:\t')+ | |||
|
387 | 'Calling definition not available.') | |||
|
388 | else: | |||
|
389 | out.write(header('Call def:\t')+self.format(call_def)) | |||
|
390 | call_ds = getdoc(obj.__call__) | |||
|
391 | if call_ds: | |||
|
392 | out.writeln(header('Call docstring:\n') + indent(call_ds)) | |||
|
393 | ||||
|
394 | # Finally send to printer/pager | |||
|
395 | output = out.getvalue() | |||
|
396 | if output: | |||
|
397 | page(output) | |||
|
398 | # end pinfo |
@@ -0,0 +1,262 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Class to trap stdout and stderr and log them separately. | |||
|
3 | ||||
|
4 | $Id: OutputTrap.py 542 2005-03-18 09:16:04Z fperez $""" | |||
|
5 | ||||
|
6 | #***************************************************************************** | |||
|
7 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
8 | # | |||
|
9 | # Distributed under the terms of the BSD License. The full license is in | |||
|
10 | # the file COPYING, distributed as part of this software. | |||
|
11 | #***************************************************************************** | |||
|
12 | ||||
|
13 | from IPython import Release | |||
|
14 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
15 | __license__ = Release.license | |||
|
16 | ||||
|
17 | import exceptions,sys | |||
|
18 | from cStringIO import StringIO | |||
|
19 | ||||
|
20 | class OutputTrapError(exceptions.Exception): | |||
|
21 | """Exception for OutputTrap class.""" | |||
|
22 | ||||
|
23 | def __init__(self,args=None): | |||
|
24 | exceptions.Exception.__init__(self) | |||
|
25 | self.args = args | |||
|
26 | ||||
|
27 | class OutputTrap: | |||
|
28 | ||||
|
29 | """Class to trap standard output and standard error. They get logged in | |||
|
30 | StringIO objects which are available as <instance>.out and | |||
|
31 | <instance>.err. The class also offers summary methods which format this | |||
|
32 | data a bit. | |||
|
33 | ||||
|
34 | A word of caution: because it blocks messages, using this class can make | |||
|
35 | debugging very tricky. If you are having bizarre problems silently, try | |||
|
36 | turning your output traps off for a while. You can call the constructor | |||
|
37 | with the parameter debug=1 for these cases. This turns actual trapping | |||
|
38 | off, but you can keep the rest of your code unchanged (this has already | |||
|
39 | been a life saver). | |||
|
40 | ||||
|
41 | Example: | |||
|
42 | ||||
|
43 | # config: trapper with a line of dots as log separator (final '\\n' needed) | |||
|
44 | config = OutputTrap('Config','Out ','Err ','.'*80+'\\n') | |||
|
45 | ||||
|
46 | # start trapping output | |||
|
47 | config.trap_all() | |||
|
48 | ||||
|
49 | # now all output is logged ... | |||
|
50 | # do stuff... | |||
|
51 | ||||
|
52 | # output back to normal: | |||
|
53 | config.release_all() | |||
|
54 | ||||
|
55 | # print all that got logged: | |||
|
56 | print config.summary() | |||
|
57 | ||||
|
58 | # print individual raw data: | |||
|
59 | print config.out.getvalue() | |||
|
60 | print config.err.getvalue() | |||
|
61 | """ | |||
|
62 | ||||
|
63 | def __init__(self,name='Generic Output Trap', | |||
|
64 | out_head='Standard Output. ',err_head='Standard Error. ', | |||
|
65 | sum_sep='\n',debug=0,trap_out=0,trap_err=0, | |||
|
66 | quiet_out=0,quiet_err=0): | |||
|
67 | self.name = name | |||
|
68 | self.out_head = out_head | |||
|
69 | self.err_head = err_head | |||
|
70 | self.sum_sep = sum_sep | |||
|
71 | self.out = StringIO() | |||
|
72 | self.err = StringIO() | |||
|
73 | self.out_save = None | |||
|
74 | self.err_save = None | |||
|
75 | self.debug = debug | |||
|
76 | self.quiet_out = quiet_out | |||
|
77 | self.quiet_err = quiet_err | |||
|
78 | if trap_out: | |||
|
79 | self.trap_out() | |||
|
80 | if trap_err: | |||
|
81 | self.trap_err() | |||
|
82 | ||||
|
83 | def trap_out(self): | |||
|
84 | """Trap and log stdout.""" | |||
|
85 | if sys.stdout is self.out: | |||
|
86 | raise OutputTrapError,'You are already trapping stdout.' | |||
|
87 | if not self.debug: | |||
|
88 | self._out_save = sys.stdout | |||
|
89 | sys.stdout = self.out | |||
|
90 | ||||
|
91 | def release_out(self): | |||
|
92 | """Release stdout.""" | |||
|
93 | if not self.debug: | |||
|
94 | if not sys.stdout is self.out: | |||
|
95 | raise OutputTrapError,'You are not trapping stdout.' | |||
|
96 | sys.stdout = self._out_save | |||
|
97 | self.out_save = None | |||
|
98 | ||||
|
99 | def summary_out(self): | |||
|
100 | """Return as a string the log from stdout.""" | |||
|
101 | out = self.out.getvalue() | |||
|
102 | if out: | |||
|
103 | if self.quiet_out: | |||
|
104 | return out | |||
|
105 | else: | |||
|
106 | return self.out_head + 'Log by '+ self.name + ':\n' + out | |||
|
107 | else: | |||
|
108 | return '' | |||
|
109 | ||||
|
110 | def flush_out(self): | |||
|
111 | """Flush the stdout log. All data held in the log is lost.""" | |||
|
112 | ||||
|
113 | self.out.close() | |||
|
114 | self.out = StringIO() | |||
|
115 | ||||
|
116 | def trap_err(self): | |||
|
117 | """Trap and log stderr.""" | |||
|
118 | if sys.stderr is self.err: | |||
|
119 | raise OutputTrapError,'You are already trapping stderr.' | |||
|
120 | if not self.debug: | |||
|
121 | self._err_save = sys.stderr | |||
|
122 | sys.stderr = self.err | |||
|
123 | ||||
|
124 | def release_err(self): | |||
|
125 | """Release stderr.""" | |||
|
126 | if not self.debug: | |||
|
127 | if not sys.stderr is self.err: | |||
|
128 | raise OutputTrapError,'You are not trapping stderr.' | |||
|
129 | sys.stderr = self._err_save | |||
|
130 | self.err_save = None | |||
|
131 | ||||
|
132 | def summary_err(self): | |||
|
133 | """Return as a string the log from stderr.""" | |||
|
134 | err = self.err.getvalue() | |||
|
135 | if err: | |||
|
136 | if self.quiet_err: | |||
|
137 | return err | |||
|
138 | else: | |||
|
139 | return self.err_head + 'Log by '+ self.name + ':\n' + err | |||
|
140 | else: | |||
|
141 | return '' | |||
|
142 | ||||
|
143 | def flush_err(self): | |||
|
144 | """Flush the stdout log. All data held in the log is lost.""" | |||
|
145 | ||||
|
146 | self.err.close() | |||
|
147 | self.err = StringIO() | |||
|
148 | ||||
|
149 | def trap_all(self): | |||
|
150 | """Trap and log both stdout and stderr. | |||
|
151 | ||||
|
152 | Cacthes and discards OutputTrapError exceptions raised.""" | |||
|
153 | try: | |||
|
154 | self.trap_out() | |||
|
155 | except OutputTrapError: | |||
|
156 | pass | |||
|
157 | try: | |||
|
158 | self.trap_err() | |||
|
159 | except OutputTrapError: | |||
|
160 | pass | |||
|
161 | ||||
|
162 | def release_all(self): | |||
|
163 | """Release both stdout and stderr. | |||
|
164 | ||||
|
165 | Cacthes and discards OutputTrapError exceptions raised.""" | |||
|
166 | try: | |||
|
167 | self.release_out() | |||
|
168 | except OutputTrapError: | |||
|
169 | pass | |||
|
170 | try: | |||
|
171 | self.release_err() | |||
|
172 | except OutputTrapError: | |||
|
173 | pass | |||
|
174 | ||||
|
175 | def summary_all(self): | |||
|
176 | """Return as a string the log from stdout and stderr, prepending a separator | |||
|
177 | to each (defined in __init__ as sum_sep).""" | |||
|
178 | sum = '' | |||
|
179 | sout = self.summary_out() | |||
|
180 | if sout: | |||
|
181 | sum += self.sum_sep + sout | |||
|
182 | serr = self.summary_err() | |||
|
183 | if serr: | |||
|
184 | sum += '\n'+self.sum_sep + serr | |||
|
185 | return sum | |||
|
186 | ||||
|
187 | def flush_all(self): | |||
|
188 | """Flush stdout and stderr""" | |||
|
189 | self.flush_out() | |||
|
190 | self.flush_err() | |||
|
191 | ||||
|
192 | # a few shorthands | |||
|
193 | trap = trap_all | |||
|
194 | release = release_all | |||
|
195 | summary = summary_all | |||
|
196 | flush = flush_all | |||
|
197 | # end OutputTrap | |||
|
198 | ||||
|
199 | ||||
|
200 | #**************************************************************************** | |||
|
201 | # Module testing. Incomplete, I'm lazy... | |||
|
202 | ||||
|
203 | def _test_all(): | |||
|
204 | ||||
|
205 | """Module testing functions, activated when the module is called as a | |||
|
206 | script (not imported).""" | |||
|
207 | ||||
|
208 | # Put tests for this module in here. | |||
|
209 | # Define them as nested functions so they don't clobber the | |||
|
210 | # pydoc-generated docs | |||
|
211 | ||||
|
212 | def _test_(): | |||
|
213 | name = '' | |||
|
214 | print '#'*50+'\nRunning test for ' + name | |||
|
215 | # ... | |||
|
216 | print 'Finished test for '+ name +'\n'+'#'*50 | |||
|
217 | ||||
|
218 | def _test_OutputTrap(): | |||
|
219 | trap = OutputTrap(name = 'Test Trap', sum_sep = '.'*50+'\n', | |||
|
220 | out_head = 'SOut. ', err_head = 'SErr. ') | |||
|
221 | ||||
|
222 | name = 'OutputTrap class' | |||
|
223 | print '#'*50+'\nRunning test for ' + name | |||
|
224 | print 'Trapping out' | |||
|
225 | trap.trap_out() | |||
|
226 | print >>sys.stdout, '>>stdout. stdout is trapped.' | |||
|
227 | print >>sys.stderr, '>>stderr. stdout is trapped.' | |||
|
228 | trap.release_out() | |||
|
229 | print trap.summary_out() | |||
|
230 | ||||
|
231 | print 'Trapping err' | |||
|
232 | trap.trap_err() | |||
|
233 | print >>sys.stdout, '>>stdout. stderr is trapped.' | |||
|
234 | print >>sys.stderr, '>>stderr. stderr is trapped.' | |||
|
235 | trap.release_err() | |||
|
236 | print trap.summary_err() | |||
|
237 | ||||
|
238 | print 'Trapping all (no flushing)' | |||
|
239 | trap.trap_all() | |||
|
240 | print >>sys.stdout, '>>stdout. stdout/err is trapped.' | |||
|
241 | print >>sys.stderr, '>>stderr. stdout/err is trapped.' | |||
|
242 | trap.release_all() | |||
|
243 | print trap.summary_all() | |||
|
244 | ||||
|
245 | print 'Trapping all (flushing first)' | |||
|
246 | trap.flush() | |||
|
247 | trap.trap_all() | |||
|
248 | print >>sys.stdout, '>>stdout. stdout/err is trapped.' | |||
|
249 | print >>sys.stderr, '>>stderr. stdout/err is trapped.' | |||
|
250 | trap.release_all() | |||
|
251 | print trap.summary_all() | |||
|
252 | print 'Finished test for '+ name +'\n'+'#'*50 | |||
|
253 | ||||
|
254 | # call the actual tests here: | |||
|
255 | _test_OutputTrap() | |||
|
256 | ||||
|
257 | ||||
|
258 | if __name__=="__main__": | |||
|
259 | # _test_all() # XXX BROKEN. | |||
|
260 | pass | |||
|
261 | ||||
|
262 | #************************ end of file <OutputTrap.py> ************************ |
This diff has been collapsed as it changes many lines, (574 lines changed) Show them Hide them | |||||
@@ -0,0 +1,574 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | Classes for handling input/output prompts. | |||
|
4 | ||||
|
5 | $Id: Prompts.py 564 2005-03-26 22:43:58Z fperez $""" | |||
|
6 | ||||
|
7 | #***************************************************************************** | |||
|
8 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
9 | # | |||
|
10 | # Distributed under the terms of the BSD License. The full license is in | |||
|
11 | # the file COPYING, distributed as part of this software. | |||
|
12 | #***************************************************************************** | |||
|
13 | ||||
|
14 | from IPython import Release | |||
|
15 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
16 | __license__ = Release.license | |||
|
17 | __version__ = Release.version | |||
|
18 | ||||
|
19 | #**************************************************************************** | |||
|
20 | # Required modules | |||
|
21 | import __builtin__ | |||
|
22 | import os,sys,socket | |||
|
23 | import time | |||
|
24 | from pprint import pprint,pformat | |||
|
25 | ||||
|
26 | # IPython's own | |||
|
27 | from IPython.genutils import * | |||
|
28 | from IPython.Struct import Struct | |||
|
29 | from IPython.Magic import Macro | |||
|
30 | from IPython.Itpl import ItplNS | |||
|
31 | from IPython import ColorANSI | |||
|
32 | ||||
|
33 | #**************************************************************************** | |||
|
34 | #Color schemes for Prompts. | |||
|
35 | ||||
|
36 | PromptColors = ColorANSI.ColorSchemeTable() | |||
|
37 | InputColors = ColorANSI.InputTermColors # just a shorthand | |||
|
38 | Colors = ColorANSI.TermColors # just a shorthand | |||
|
39 | ||||
|
40 | PromptColors.add_scheme(ColorANSI.ColorScheme( | |||
|
41 | 'NoColor', | |||
|
42 | in_prompt = InputColors.NoColor, # Input prompt | |||
|
43 | in_number = InputColors.NoColor, # Input prompt number | |||
|
44 | in_prompt2 = InputColors.NoColor, # Continuation prompt | |||
|
45 | in_normal = InputColors.NoColor, # color off (usu. Colors.Normal) | |||
|
46 | ||||
|
47 | out_prompt = Colors.NoColor, # Output prompt | |||
|
48 | out_number = Colors.NoColor, # Output prompt number | |||
|
49 | ||||
|
50 | normal = Colors.NoColor # color off (usu. Colors.Normal) | |||
|
51 | )) | |||
|
52 | # make some schemes as instances so we can copy them for modification easily: | |||
|
53 | __PColLinux = ColorANSI.ColorScheme( | |||
|
54 | 'Linux', | |||
|
55 | in_prompt = InputColors.Green, | |||
|
56 | in_number = InputColors.LightGreen, | |||
|
57 | in_prompt2 = InputColors.Green, | |||
|
58 | in_normal = InputColors.Normal, # color off (usu. Colors.Normal) | |||
|
59 | ||||
|
60 | out_prompt = Colors.Red, | |||
|
61 | out_number = Colors.LightRed, | |||
|
62 | ||||
|
63 | normal = Colors.Normal | |||
|
64 | ) | |||
|
65 | # Don't forget to enter it into the table! | |||
|
66 | PromptColors.add_scheme(__PColLinux) | |||
|
67 | # Slightly modified Linux for light backgrounds | |||
|
68 | __PColLightBG = ColorANSI.ColorScheme('LightBG',**__PColLinux.colors.dict().copy()) | |||
|
69 | ||||
|
70 | __PColLightBG.colors.update( | |||
|
71 | in_prompt = InputColors.Blue, | |||
|
72 | in_number = InputColors.LightBlue, | |||
|
73 | in_prompt2 = InputColors.Blue | |||
|
74 | ) | |||
|
75 | PromptColors.add_scheme(__PColLightBG) | |||
|
76 | ||||
|
77 | del Colors,InputColors | |||
|
78 | ||||
|
79 | #----------------------------------------------------------------------------- | |||
|
80 | def multiple_replace(dict, text): | |||
|
81 | """ Replace in 'text' all occurences of any key in the given | |||
|
82 | dictionary by its corresponding value. Returns the new string.""" | |||
|
83 | ||||
|
84 | # Function by Xavier Defrang, originally found at: | |||
|
85 | # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330 | |||
|
86 | ||||
|
87 | # Create a regular expression from the dictionary keys | |||
|
88 | regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys()))) | |||
|
89 | # For each match, look-up corresponding value in dictionary | |||
|
90 | return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) | |||
|
91 | ||||
|
92 | #----------------------------------------------------------------------------- | |||
|
93 | # Special characters that can be used in prompt templates, mainly bash-like | |||
|
94 | ||||
|
95 | # If $HOME isn't defined (Windows), make it an absurd string so that it can | |||
|
96 | # never be expanded out into '~'. Basically anything which can never be a | |||
|
97 | # reasonable directory name will do, we just want the $HOME -> '~' operation | |||
|
98 | # to become a no-op. We pre-compute $HOME here so it's not done on every | |||
|
99 | # prompt call. | |||
|
100 | ||||
|
101 | # FIXME: | |||
|
102 | ||||
|
103 | # - This should be turned into a class which does proper namespace management, | |||
|
104 | # since the prompt specials need to be evaluated in a certain namespace. | |||
|
105 | # Currently it's just globals, which need to be managed manually by code | |||
|
106 | # below. | |||
|
107 | ||||
|
108 | # - I also need to split up the color schemes from the prompt specials | |||
|
109 | # somehow. I don't have a clean design for that quite yet. | |||
|
110 | ||||
|
111 | HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~") | |||
|
112 | ||||
|
113 | # We precompute a few more strings here for the prompt_specials, which are | |||
|
114 | # fixed once ipython starts. This reduces the runtime overhead of computing | |||
|
115 | # prompt strings. | |||
|
116 | USER = os.environ.get("USER") | |||
|
117 | HOSTNAME = socket.gethostname() | |||
|
118 | HOSTNAME_SHORT = HOSTNAME.split(".")[0] | |||
|
119 | ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0] | |||
|
120 | ||||
|
121 | prompt_specials_color = { | |||
|
122 | # Prompt/history count | |||
|
123 | '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}', | |||
|
124 | '\\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}', | |||
|
125 | # Prompt/history count, with the actual digits replaced by dots. Used | |||
|
126 | # mainly in continuation prompts (prompt_in2) | |||
|
127 | '\\D': '${"."*len(str(self.cache.prompt_count))}', | |||
|
128 | # Current working directory | |||
|
129 | '\\w': '${os.getcwd()}', | |||
|
130 | # Current time | |||
|
131 | '\\t' : '${time.strftime("%H:%M:%S")}', | |||
|
132 | # Basename of current working directory. | |||
|
133 | # (use os.sep to make this portable across OSes) | |||
|
134 | '\\W' : '${os.getcwd().split("%s")[-1]}' % os.sep, | |||
|
135 | # These X<N> are an extension to the normal bash prompts. They return | |||
|
136 | # N terms of the path, after replacing $HOME with '~' | |||
|
137 | '\\X0': '${os.getcwd().replace("%s","~")}' % HOME, | |||
|
138 | '\\X1': '${self.cwd_filt(1)}', | |||
|
139 | '\\X2': '${self.cwd_filt(2)}', | |||
|
140 | '\\X3': '${self.cwd_filt(3)}', | |||
|
141 | '\\X4': '${self.cwd_filt(4)}', | |||
|
142 | '\\X5': '${self.cwd_filt(5)}', | |||
|
143 | # Y<N> are similar to X<N>, but they show '~' if it's the directory | |||
|
144 | # N+1 in the list. Somewhat like %cN in tcsh. | |||
|
145 | '\\Y0': '${self.cwd_filt2(0)}', | |||
|
146 | '\\Y1': '${self.cwd_filt2(1)}', | |||
|
147 | '\\Y2': '${self.cwd_filt2(2)}', | |||
|
148 | '\\Y3': '${self.cwd_filt2(3)}', | |||
|
149 | '\\Y4': '${self.cwd_filt2(4)}', | |||
|
150 | '\\Y5': '${self.cwd_filt2(5)}', | |||
|
151 | # Hostname up to first . | |||
|
152 | '\\h': HOSTNAME_SHORT, | |||
|
153 | # Full hostname | |||
|
154 | '\\H': HOSTNAME, | |||
|
155 | # Username of current user | |||
|
156 | '\\u': USER, | |||
|
157 | # Escaped '\' | |||
|
158 | '\\\\': '\\', | |||
|
159 | # Newline | |||
|
160 | '\\n': '\n', | |||
|
161 | # Carriage return | |||
|
162 | '\\r': '\r', | |||
|
163 | # Release version | |||
|
164 | '\\v': __version__, | |||
|
165 | # Root symbol ($ or #) | |||
|
166 | '\\$': ROOT_SYMBOL, | |||
|
167 | } | |||
|
168 | ||||
|
169 | # A copy of the prompt_specials dictionary but with all color escapes removed, | |||
|
170 | # so we can correctly compute the prompt length for the auto_rewrite method. | |||
|
171 | prompt_specials_nocolor = prompt_specials_color.copy() | |||
|
172 | prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}' | |||
|
173 | prompt_specials_nocolor['\\#'] = '${self.cache.prompt_count}' | |||
|
174 | ||||
|
175 | # Add in all the InputTermColors color escapes as valid prompt characters. | |||
|
176 | # They all get added as \\C_COLORNAME, so that we don't have any conflicts | |||
|
177 | # with a color name which may begin with a letter used by any other of the | |||
|
178 | # allowed specials. This of course means that \\C will never be allowed for | |||
|
179 | # anything else. | |||
|
180 | input_colors = ColorANSI.InputTermColors | |||
|
181 | for _color in dir(input_colors): | |||
|
182 | if _color[0] != '_': | |||
|
183 | c_name = '\\C_'+_color | |||
|
184 | prompt_specials_color[c_name] = getattr(input_colors,_color) | |||
|
185 | prompt_specials_nocolor[c_name] = '' | |||
|
186 | ||||
|
187 | # we default to no color for safety. Note that prompt_specials is a global | |||
|
188 | # variable used by all prompt objects. | |||
|
189 | prompt_specials = prompt_specials_nocolor | |||
|
190 | ||||
|
191 | #----------------------------------------------------------------------------- | |||
|
192 | def str_safe(arg): | |||
|
193 | """Convert to a string, without ever raising an exception. | |||
|
194 | ||||
|
195 | If str(arg) fails, <ERROR: ... > is returned, where ... is the exception | |||
|
196 | error message.""" | |||
|
197 | ||||
|
198 | try: | |||
|
199 | return str(arg) | |||
|
200 | except Exception,msg: | |||
|
201 | return '<ERROR: %s>' % msg | |||
|
202 | ||||
|
203 | class BasePrompt: | |||
|
204 | """Interactive prompt similar to Mathematica's.""" | |||
|
205 | def __init__(self,cache,sep,prompt,pad_left=False): | |||
|
206 | ||||
|
207 | # Hack: we access information about the primary prompt through the | |||
|
208 | # cache argument. We need this, because we want the secondary prompt | |||
|
209 | # to be aligned with the primary one. Color table info is also shared | |||
|
210 | # by all prompt classes through the cache. Nice OO spaghetti code! | |||
|
211 | self.cache = cache | |||
|
212 | self.sep = sep | |||
|
213 | ||||
|
214 | # regexp to count the number of spaces at the end of a prompt | |||
|
215 | # expression, useful for prompt auto-rewriting | |||
|
216 | self.rspace = re.compile(r'(\s*)$') | |||
|
217 | # Flag to left-pad prompt strings to match the length of the primary | |||
|
218 | # prompt | |||
|
219 | self.pad_left = pad_left | |||
|
220 | # Set template to create each actual prompt (where numbers change) | |||
|
221 | self.p_template = prompt | |||
|
222 | self.set_p_str() | |||
|
223 | ||||
|
224 | def set_p_str(self): | |||
|
225 | """ Set the interpolating prompt strings. | |||
|
226 | ||||
|
227 | This must be called every time the color settings change, because the | |||
|
228 | prompt_specials global may have changed.""" | |||
|
229 | ||||
|
230 | import os,time # needed in locals for prompt string handling | |||
|
231 | loc = locals() | |||
|
232 | self.p_str = ItplNS('%s%s%s' % | |||
|
233 | ('${self.sep}${self.col_p}', | |||
|
234 | multiple_replace(prompt_specials, self.p_template), | |||
|
235 | '${self.col_norm}'),self.cache.user_ns,loc) | |||
|
236 | ||||
|
237 | self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor, | |||
|
238 | self.p_template), | |||
|
239 | self.cache.user_ns,loc) | |||
|
240 | ||||
|
241 | def write(self,msg): # dbg | |||
|
242 | sys.stdout.write(msg) | |||
|
243 | return '' | |||
|
244 | ||||
|
245 | def __str__(self): | |||
|
246 | """Return a string form of the prompt. | |||
|
247 | ||||
|
248 | This for is useful for continuation and output prompts, since it is | |||
|
249 | left-padded to match lengths with the primary one (if the | |||
|
250 | self.pad_left attribute is set).""" | |||
|
251 | ||||
|
252 | out_str = str_safe(self.p_str) | |||
|
253 | if self.pad_left: | |||
|
254 | # We must find the amount of padding required to match lengths, | |||
|
255 | # taking the color escapes (which are invisible on-screen) into | |||
|
256 | # account. | |||
|
257 | esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor)) | |||
|
258 | format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad) | |||
|
259 | return format % out_str | |||
|
260 | else: | |||
|
261 | return out_str | |||
|
262 | ||||
|
263 | # these path filters are put in as methods so that we can control the | |||
|
264 | # namespace where the prompt strings get evaluated | |||
|
265 | def cwd_filt(self,depth): | |||
|
266 | """Return the last depth elements of the current working directory. | |||
|
267 | ||||
|
268 | $HOME is always replaced with '~'. | |||
|
269 | If depth==0, the full path is returned.""" | |||
|
270 | ||||
|
271 | cwd = os.getcwd().replace(HOME,"~") | |||
|
272 | out = os.sep.join(cwd.split(os.sep)[-depth:]) | |||
|
273 | if out: | |||
|
274 | return out | |||
|
275 | else: | |||
|
276 | return os.sep | |||
|
277 | ||||
|
278 | def cwd_filt2(self,depth): | |||
|
279 | """Return the last depth elements of the current working directory. | |||
|
280 | ||||
|
281 | $HOME is always replaced with '~'. | |||
|
282 | If depth==0, the full path is returned.""" | |||
|
283 | ||||
|
284 | cwd = os.getcwd().replace(HOME,"~").split(os.sep) | |||
|
285 | if '~' in cwd and len(cwd) == depth+1: | |||
|
286 | depth += 1 | |||
|
287 | out = os.sep.join(cwd[-depth:]) | |||
|
288 | if out: | |||
|
289 | return out | |||
|
290 | else: | |||
|
291 | return os.sep | |||
|
292 | ||||
|
293 | class Prompt1(BasePrompt): | |||
|
294 | """Input interactive prompt similar to Mathematica's.""" | |||
|
295 | ||||
|
296 | def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True): | |||
|
297 | BasePrompt.__init__(self,cache,sep,prompt,pad_left) | |||
|
298 | ||||
|
299 | def set_colors(self): | |||
|
300 | self.set_p_str() | |||
|
301 | Colors = self.cache.color_table.active_colors # shorthand | |||
|
302 | self.col_p = Colors.in_prompt | |||
|
303 | self.col_num = Colors.in_number | |||
|
304 | self.col_norm = Colors.in_normal | |||
|
305 | # We need a non-input version of these escapes for the '--->' | |||
|
306 | # auto-call prompts used in the auto_rewrite() method. | |||
|
307 | self.col_p_ni = self.col_p.replace('\001','').replace('\002','') | |||
|
308 | self.col_norm_ni = Colors.normal | |||
|
309 | ||||
|
310 | def __str__(self): | |||
|
311 | self.cache.prompt_count += 1 | |||
|
312 | self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1] | |||
|
313 | return str_safe(self.p_str) | |||
|
314 | ||||
|
315 | def auto_rewrite(self): | |||
|
316 | """Print a string of the form '--->' which lines up with the previous | |||
|
317 | input string. Useful for systems which re-write the user input when | |||
|
318 | handling automatically special syntaxes.""" | |||
|
319 | ||||
|
320 | curr = str(self.cache.last_prompt) | |||
|
321 | nrspaces = len(self.rspace.search(curr).group()) | |||
|
322 | return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1), | |||
|
323 | ' '*nrspaces,self.col_norm_ni) | |||
|
324 | ||||
|
325 | class PromptOut(BasePrompt): | |||
|
326 | """Output interactive prompt similar to Mathematica's.""" | |||
|
327 | ||||
|
328 | def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True): | |||
|
329 | BasePrompt.__init__(self,cache,sep,prompt,pad_left) | |||
|
330 | if not self.p_template: | |||
|
331 | self.__str__ = lambda: '' | |||
|
332 | ||||
|
333 | def set_colors(self): | |||
|
334 | self.set_p_str() | |||
|
335 | Colors = self.cache.color_table.active_colors # shorthand | |||
|
336 | self.col_p = Colors.out_prompt | |||
|
337 | self.col_num = Colors.out_number | |||
|
338 | self.col_norm = Colors.normal | |||
|
339 | ||||
|
340 | class Prompt2(BasePrompt): | |||
|
341 | """Interactive continuation prompt.""" | |||
|
342 | ||||
|
343 | def __init__(self,cache,prompt=' .\\D.: ',pad_left=True): | |||
|
344 | self.cache = cache | |||
|
345 | self.p_template = prompt | |||
|
346 | self.pad_left = pad_left | |||
|
347 | self.set_p_str() | |||
|
348 | ||||
|
349 | def set_p_str(self): | |||
|
350 | import os,time # needed in locals for prompt string handling | |||
|
351 | loc = locals() | |||
|
352 | self.p_str = ItplNS('%s%s%s' % | |||
|
353 | ('${self.col_p2}', | |||
|
354 | multiple_replace(prompt_specials, self.p_template), | |||
|
355 | '$self.col_norm'), | |||
|
356 | self.cache.user_ns,loc) | |||
|
357 | self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor, | |||
|
358 | self.p_template), | |||
|
359 | self.cache.user_ns,loc) | |||
|
360 | ||||
|
361 | def set_colors(self): | |||
|
362 | self.set_p_str() | |||
|
363 | Colors = self.cache.color_table.active_colors | |||
|
364 | self.col_p2 = Colors.in_prompt2 | |||
|
365 | self.col_norm = Colors.in_normal | |||
|
366 | # FIXME (2004-06-16) HACK: prevent crashes for users who haven't | |||
|
367 | # updated their prompt_in2 definitions. Remove eventually. | |||
|
368 | self.col_p = Colors.out_prompt | |||
|
369 | self.col_num = Colors.out_number | |||
|
370 | ||||
|
371 | #----------------------------------------------------------------------------- | |||
|
372 | class CachedOutput: | |||
|
373 | """Class for printing output from calculations while keeping a cache of | |||
|
374 | reults. It dynamically creates global variables prefixed with _ which | |||
|
375 | contain these results. | |||
|
376 | ||||
|
377 | Meant to be used as a sys.displayhook replacement, providing numbered | |||
|
378 | prompts and cache services. | |||
|
379 | ||||
|
380 | Initialize with initial and final values for cache counter (this defines | |||
|
381 | the maximum size of the cache.""" | |||
|
382 | ||||
|
383 | def __init__(self,cache_size,Pprint,colors='NoColor',input_sep='\n', | |||
|
384 | output_sep='\n',output_sep2='',user_ns={}, | |||
|
385 | ps1 = None, ps2 = None,ps_out = None, | |||
|
386 | input_hist = None,pad_left=True): | |||
|
387 | ||||
|
388 | cache_size_min = 20 | |||
|
389 | if cache_size <= 0: | |||
|
390 | self.do_full_cache = 0 | |||
|
391 | cache_size = 0 | |||
|
392 | elif cache_size < cache_size_min: | |||
|
393 | self.do_full_cache = 0 | |||
|
394 | cache_size = 0 | |||
|
395 | warn('caching was disabled (min value for cache size is %s).' % | |||
|
396 | cache_size_min,level=3) | |||
|
397 | else: | |||
|
398 | self.do_full_cache = 1 | |||
|
399 | ||||
|
400 | self.cache_size = cache_size | |||
|
401 | self.input_sep = input_sep | |||
|
402 | ||||
|
403 | # we need a reference to the user-level namespace | |||
|
404 | self.user_ns = user_ns | |||
|
405 | # and to the user's input | |||
|
406 | self.input_hist = input_hist | |||
|
407 | ||||
|
408 | # Set input prompt strings and colors | |||
|
409 | if cache_size == 0: | |||
|
410 | if ps1.find('%n') > -1 or ps1.find('\\#') > -1: ps1 = '>>> ' | |||
|
411 | if ps2.find('%n') > -1 or ps2.find('\\#') > -1: ps2 = '... ' | |||
|
412 | self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ') | |||
|
413 | self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ') | |||
|
414 | self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','') | |||
|
415 | ||||
|
416 | self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str, | |||
|
417 | pad_left=pad_left) | |||
|
418 | self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left) | |||
|
419 | self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str, | |||
|
420 | pad_left=pad_left) | |||
|
421 | self.color_table = PromptColors | |||
|
422 | self.set_colors(colors) | |||
|
423 | ||||
|
424 | # other more normal stuff | |||
|
425 | # b/c each call to the In[] prompt raises it by 1, even the first. | |||
|
426 | self.prompt_count = 0 | |||
|
427 | self.cache_count = 1 | |||
|
428 | # Store the last prompt string each time, we need it for aligning | |||
|
429 | # continuation and auto-rewrite prompts | |||
|
430 | self.last_prompt = '' | |||
|
431 | self.entries = [None] # output counter starts at 1 for the user | |||
|
432 | self.Pprint = Pprint | |||
|
433 | self.output_sep = output_sep | |||
|
434 | self.output_sep2 = output_sep2 | |||
|
435 | self._,self.__,self.___ = '','','' | |||
|
436 | self.pprint_types = map(type,[(),[],{}]) | |||
|
437 | ||||
|
438 | # these are deliberately global: | |||
|
439 | to_user_ns = {'_':self._,'__':self.__,'___':self.___} | |||
|
440 | self.user_ns.update(to_user_ns) | |||
|
441 | ||||
|
442 | def _set_prompt_str(self,p_str,cache_def,no_cache_def): | |||
|
443 | if p_str is None: | |||
|
444 | if self.do_full_cache: | |||
|
445 | return cache_def | |||
|
446 | else: | |||
|
447 | return no_cache_def | |||
|
448 | else: | |||
|
449 | return p_str | |||
|
450 | ||||
|
451 | def set_colors(self,colors): | |||
|
452 | """Set the active color scheme and configure colors for the three | |||
|
453 | prompt subsystems.""" | |||
|
454 | ||||
|
455 | # FIXME: the prompt_specials global should be gobbled inside this | |||
|
456 | # class instead. Do it when cleaning up the whole 3-prompt system. | |||
|
457 | global prompt_specials | |||
|
458 | if colors.lower()=='nocolor': | |||
|
459 | prompt_specials = prompt_specials_nocolor | |||
|
460 | else: | |||
|
461 | prompt_specials = prompt_specials_color | |||
|
462 | ||||
|
463 | self.color_table.set_active_scheme(colors) | |||
|
464 | self.prompt1.set_colors() | |||
|
465 | self.prompt2.set_colors() | |||
|
466 | self.prompt_out.set_colors() | |||
|
467 | ||||
|
468 | def __call__(self,arg=None): | |||
|
469 | """Printing with history cache management. | |||
|
470 | ||||
|
471 | This is invoked everytime the interpreter needs to print, and is | |||
|
472 | activated by setting the variable sys.displayhook to it.""" | |||
|
473 | ||||
|
474 | # If something injected a '_' variable in __builtin__, delete | |||
|
475 | # ipython's automatic one so we don't clobber that. gettext() in | |||
|
476 | # particular uses _, so we need to stay away from it. | |||
|
477 | if '_' in __builtin__.__dict__: | |||
|
478 | try: | |||
|
479 | del self.user_ns['_'] | |||
|
480 | except KeyError: | |||
|
481 | pass | |||
|
482 | if arg is not None: | |||
|
483 | # first handle the cache and counters | |||
|
484 | self.update(arg) | |||
|
485 | # do not print output if input ends in ';' | |||
|
486 | if self.input_hist[self.prompt_count].endswith(';\n'): | |||
|
487 | return | |||
|
488 | # don't use print, puts an extra space | |||
|
489 | Term.cout.write(self.output_sep) | |||
|
490 | if self.do_full_cache: | |||
|
491 | Term.cout.write(str(self.prompt_out)) | |||
|
492 | ||||
|
493 | if isinstance(arg,Macro): | |||
|
494 | print 'Executing Macro...' | |||
|
495 | # in case the macro takes a long time to execute | |||
|
496 | Term.cout.flush() | |||
|
497 | exec arg.value in self.user_ns | |||
|
498 | return None | |||
|
499 | ||||
|
500 | # and now call a possibly user-defined print mechanism | |||
|
501 | self.display(arg) | |||
|
502 | Term.cout.write(self.output_sep2) | |||
|
503 | Term.cout.flush() | |||
|
504 | ||||
|
505 | def _display(self,arg): | |||
|
506 | """Default printer method, uses pprint. | |||
|
507 | ||||
|
508 | This can be over-ridden by the users to implement special formatting | |||
|
509 | of certain types of output.""" | |||
|
510 | ||||
|
511 | if self.Pprint: | |||
|
512 | # The following is an UGLY kludge, b/c python fails to properly | |||
|
513 | # identify instances of classes imported in the user namespace | |||
|
514 | # (they have different memory locations, I guess). Structs are | |||
|
515 | # essentially dicts but pprint doesn't know what to do with them. | |||
|
516 | try: | |||
|
517 | if arg.__class__.__module__ == 'Struct' and \ | |||
|
518 | arg.__class__.__name__ == 'Struct': | |||
|
519 | out = 'Struct:\n%s' % pformat(arg.dict()) | |||
|
520 | else: | |||
|
521 | out = pformat(arg) | |||
|
522 | except: | |||
|
523 | out = pformat(arg) | |||
|
524 | if '\n' in out: | |||
|
525 | # So that multi-line strings line up with the left column of | |||
|
526 | # the screen, instead of having the output prompt mess up | |||
|
527 | # their first line. | |||
|
528 | Term.cout.write('\n') | |||
|
529 | print >>Term.cout, out | |||
|
530 | else: | |||
|
531 | print >>Term.cout, arg | |||
|
532 | ||||
|
533 | # Assign the default display method: | |||
|
534 | display = _display | |||
|
535 | ||||
|
536 | def update(self,arg): | |||
|
537 | #print '***cache_count', self.cache_count # dbg | |||
|
538 | if self.cache_count >= self.cache_size and self.do_full_cache: | |||
|
539 | self.flush() | |||
|
540 | # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise | |||
|
541 | # we cause buggy behavior for things like gettext). | |||
|
542 | if '_' not in __builtin__.__dict__: | |||
|
543 | self.___ = self.__ | |||
|
544 | self.__ = self._ | |||
|
545 | self._ = arg | |||
|
546 | self.user_ns.update({'_':self._,'__':self.__,'___':self.___}) | |||
|
547 | ||||
|
548 | # hackish access to top-level namespace to create _1,_2... dynamically | |||
|
549 | to_main = {} | |||
|
550 | if self.do_full_cache: | |||
|
551 | self.cache_count += 1 | |||
|
552 | self.entries.append(arg) | |||
|
553 | new_result = '_'+`self.prompt_count` | |||
|
554 | to_main[new_result] = self.entries[-1] | |||
|
555 | self.user_ns.update(to_main) | |||
|
556 | self.user_ns['_oh'][self.prompt_count] = arg | |||
|
557 | ||||
|
558 | def flush(self): | |||
|
559 | if not self.do_full_cache: | |||
|
560 | raise ValueError,"You shouldn't have reached the cache flush "\ | |||
|
561 | "if full caching is not enabled!" | |||
|
562 | warn('Output cache limit (currently '+\ | |||
|
563 | `self.cache_count`+' entries) hit.\n' | |||
|
564 | 'Flushing cache and resetting history counter...\n' | |||
|
565 | 'The only history variables available will be _,__,___ and _1\n' | |||
|
566 | 'with the current result.') | |||
|
567 | # delete auto-generated vars from global namespace | |||
|
568 | for n in range(1,self.prompt_count + 1): | |||
|
569 | key = '_'+`n` | |||
|
570 | try: | |||
|
571 | del self.user_ns[key] | |||
|
572 | except: pass | |||
|
573 | self.prompt_count = 1 | |||
|
574 | self.cache_count = 1 |
@@ -0,0 +1,255 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | Class and program to colorize python source code for ANSI terminals. | |||
|
4 | ||||
|
5 | Based on an HTML code highlighter by Jurgen Hermann found at: | |||
|
6 | http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298 | |||
|
7 | ||||
|
8 | Modifications by Fernando Perez (fperez@colorado.edu). | |||
|
9 | ||||
|
10 | Information on the original HTML highlighter follows: | |||
|
11 | ||||
|
12 | MoinMoin - Python Source Parser | |||
|
13 | ||||
|
14 | Title:olorize Python source using the built-in tokenizer | |||
|
15 | ||||
|
16 | Submitter: Jurgen Hermann | |||
|
17 | Last Updated:2001/04/06 | |||
|
18 | ||||
|
19 | Version no:1.2 | |||
|
20 | ||||
|
21 | Description: | |||
|
22 | ||||
|
23 | This code is part of MoinMoin (http://moin.sourceforge.net/) and converts | |||
|
24 | Python source code to HTML markup, rendering comments, keywords, | |||
|
25 | operators, numeric and string literals in different colors. | |||
|
26 | ||||
|
27 | It shows how to use the built-in keyword, token and tokenize modules to | |||
|
28 | scan Python source code and re-emit it with no changes to its original | |||
|
29 | formatting (which is the hard part). | |||
|
30 | ||||
|
31 | $Id: PyColorize.py 485 2005-01-27 19:15:39Z fperez $""" | |||
|
32 | ||||
|
33 | __all__ = ['ANSICodeColors','Parser'] | |||
|
34 | ||||
|
35 | _scheme_default = 'Linux' | |||
|
36 | ||||
|
37 | # Imports | |||
|
38 | import string, sys, os, cStringIO | |||
|
39 | import keyword, token, tokenize | |||
|
40 | ||||
|
41 | from IPython.ColorANSI import * | |||
|
42 | ||||
|
43 | ############################################################################# | |||
|
44 | ### Python Source Parser (does Hilighting) | |||
|
45 | ############################################################################# | |||
|
46 | ||||
|
47 | _KEYWORD = token.NT_OFFSET + 1 | |||
|
48 | _TEXT = token.NT_OFFSET + 2 | |||
|
49 | ||||
|
50 | #**************************************************************************** | |||
|
51 | # Builtin color schemes | |||
|
52 | ||||
|
53 | Colors = TermColors # just a shorthand | |||
|
54 | ||||
|
55 | # Build a few color schemes | |||
|
56 | NoColor = ColorScheme( | |||
|
57 | 'NoColor',{ | |||
|
58 | token.NUMBER : Colors.NoColor, | |||
|
59 | token.OP : Colors.NoColor, | |||
|
60 | token.STRING : Colors.NoColor, | |||
|
61 | tokenize.COMMENT : Colors.NoColor, | |||
|
62 | token.NAME : Colors.NoColor, | |||
|
63 | token.ERRORTOKEN : Colors.NoColor, | |||
|
64 | ||||
|
65 | _KEYWORD : Colors.NoColor, | |||
|
66 | _TEXT : Colors.NoColor, | |||
|
67 | ||||
|
68 | 'normal' : Colors.NoColor # color off (usu. Colors.Normal) | |||
|
69 | } ) | |||
|
70 | ||||
|
71 | LinuxColors = ColorScheme( | |||
|
72 | 'Linux',{ | |||
|
73 | token.NUMBER : Colors.LightCyan, | |||
|
74 | token.OP : Colors.Yellow, | |||
|
75 | token.STRING : Colors.LightBlue, | |||
|
76 | tokenize.COMMENT : Colors.LightRed, | |||
|
77 | token.NAME : Colors.White, | |||
|
78 | token.ERRORTOKEN : Colors.Red, | |||
|
79 | ||||
|
80 | _KEYWORD : Colors.LightGreen, | |||
|
81 | _TEXT : Colors.Yellow, | |||
|
82 | ||||
|
83 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) | |||
|
84 | } ) | |||
|
85 | ||||
|
86 | LightBGColors = ColorScheme( | |||
|
87 | 'LightBG',{ | |||
|
88 | token.NUMBER : Colors.Cyan, | |||
|
89 | token.OP : Colors.Blue, | |||
|
90 | token.STRING : Colors.Blue, | |||
|
91 | tokenize.COMMENT : Colors.Red, | |||
|
92 | token.NAME : Colors.Black, | |||
|
93 | token.ERRORTOKEN : Colors.Red, | |||
|
94 | ||||
|
95 | _KEYWORD : Colors.Green, | |||
|
96 | _TEXT : Colors.Blue, | |||
|
97 | ||||
|
98 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) | |||
|
99 | } ) | |||
|
100 | ||||
|
101 | # Build table of color schemes (needed by the parser) | |||
|
102 | ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors], | |||
|
103 | _scheme_default) | |||
|
104 | ||||
|
105 | class Parser: | |||
|
106 | """ Format colored Python source. | |||
|
107 | """ | |||
|
108 | ||||
|
109 | def __init__(self, color_table=None,out = sys.stdout): | |||
|
110 | """ Create a parser with a specified color table and output channel. | |||
|
111 | ||||
|
112 | Call format() to process code. | |||
|
113 | """ | |||
|
114 | self.color_table = color_table and color_table or ANSICodeColors | |||
|
115 | self.out = out | |||
|
116 | ||||
|
117 | def format(self, raw, out = None, scheme = ''): | |||
|
118 | """ Parse and send the colored source. | |||
|
119 | ||||
|
120 | If out and scheme are not specified, the defaults (given to | |||
|
121 | constructor) are used. | |||
|
122 | ||||
|
123 | out should be a file-type object. Optionally, out can be given as the | |||
|
124 | string 'str' and the parser will automatically return the output in a | |||
|
125 | string.""" | |||
|
126 | ||||
|
127 | self.raw = string.strip(string.expandtabs(raw)) | |||
|
128 | string_output = 0 | |||
|
129 | if out == 'str' or self.out == 'str': | |||
|
130 | out_old = self.out | |||
|
131 | self.out = cStringIO.StringIO() | |||
|
132 | string_output = 1 | |||
|
133 | elif out is not None: | |||
|
134 | self.out = out | |||
|
135 | # local shorthand | |||
|
136 | colors = self.color_table[scheme].colors | |||
|
137 | self.colors = colors # put in object so __call__ sees it | |||
|
138 | # store line offsets in self.lines | |||
|
139 | self.lines = [0, 0] | |||
|
140 | pos = 0 | |||
|
141 | while 1: | |||
|
142 | pos = string.find(self.raw, '\n', pos) + 1 | |||
|
143 | if not pos: break | |||
|
144 | self.lines.append(pos) | |||
|
145 | self.lines.append(len(self.raw)) | |||
|
146 | ||||
|
147 | # parse the source and write it | |||
|
148 | self.pos = 0 | |||
|
149 | text = cStringIO.StringIO(self.raw) | |||
|
150 | #self.out.write('<pre><font face="Courier New">') | |||
|
151 | try: | |||
|
152 | tokenize.tokenize(text.readline, self) | |||
|
153 | except tokenize.TokenError, ex: | |||
|
154 | msg = ex[0] | |||
|
155 | line = ex[1][0] | |||
|
156 | self.out.write("%s\n\n*** ERROR: %s%s%s\n" % | |||
|
157 | (colors[token.ERRORTOKEN], | |||
|
158 | msg, self.raw[self.lines[line]:], | |||
|
159 | colors.normal) | |||
|
160 | ) | |||
|
161 | self.out.write(colors.normal+'\n') | |||
|
162 | if string_output: | |||
|
163 | output = self.out.getvalue() | |||
|
164 | self.out = out_old | |||
|
165 | return output | |||
|
166 | ||||
|
167 | def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line): | |||
|
168 | """ Token handler, with syntax highlighting.""" | |||
|
169 | ||||
|
170 | # local shorthand | |||
|
171 | colors = self.colors | |||
|
172 | ||||
|
173 | # line separator, so this works across platforms | |||
|
174 | linesep = os.linesep | |||
|
175 | ||||
|
176 | # calculate new positions | |||
|
177 | oldpos = self.pos | |||
|
178 | newpos = self.lines[srow] + scol | |||
|
179 | self.pos = newpos + len(toktext) | |||
|
180 | ||||
|
181 | # handle newlines | |||
|
182 | if toktype in [token.NEWLINE, tokenize.NL]: | |||
|
183 | self.out.write(linesep) | |||
|
184 | return | |||
|
185 | ||||
|
186 | # send the original whitespace, if needed | |||
|
187 | if newpos > oldpos: | |||
|
188 | self.out.write(self.raw[oldpos:newpos]) | |||
|
189 | ||||
|
190 | # skip indenting tokens | |||
|
191 | if toktype in [token.INDENT, token.DEDENT]: | |||
|
192 | self.pos = newpos | |||
|
193 | return | |||
|
194 | ||||
|
195 | # map token type to a color group | |||
|
196 | if token.LPAR <= toktype and toktype <= token.OP: | |||
|
197 | toktype = token.OP | |||
|
198 | elif toktype == token.NAME and keyword.iskeyword(toktext): | |||
|
199 | toktype = _KEYWORD | |||
|
200 | color = colors.get(toktype, colors[_TEXT]) | |||
|
201 | ||||
|
202 | #print '<%s>' % toktext, # dbg | |||
|
203 | ||||
|
204 | # Triple quoted strings must be handled carefully so that backtracking | |||
|
205 | # in pagers works correctly. We need color terminators on _each_ line. | |||
|
206 | if linesep in toktext: | |||
|
207 | toktext = toktext.replace(linesep, '%s%s%s' % | |||
|
208 | (colors.normal,linesep,color)) | |||
|
209 | ||||
|
210 | # send text | |||
|
211 | self.out.write('%s%s%s' % (color,toktext,colors.normal)) | |||
|
212 | ||||
|
213 | def main(): | |||
|
214 | """Colorize a python file using ANSI color escapes and print to stdout. | |||
|
215 | ||||
|
216 | Usage: | |||
|
217 | %s [-s scheme] filename | |||
|
218 | ||||
|
219 | Options: | |||
|
220 | ||||
|
221 | -s scheme: give the color scheme to use. Currently only 'Linux' | |||
|
222 | (default) and 'LightBG' and 'NoColor' are implemented (give without | |||
|
223 | quotes). """ | |||
|
224 | ||||
|
225 | def usage(): | |||
|
226 | print >> sys.stderr, main.__doc__ % sys.argv[0] | |||
|
227 | sys.exit(1) | |||
|
228 | ||||
|
229 | # FIXME: rewrite this to at least use getopt | |||
|
230 | try: | |||
|
231 | if sys.argv[1] == '-s': | |||
|
232 | scheme_name = sys.argv[2] | |||
|
233 | del sys.argv[1:3] | |||
|
234 | else: | |||
|
235 | scheme_name = _scheme_default | |||
|
236 | ||||
|
237 | except: | |||
|
238 | usage() | |||
|
239 | ||||
|
240 | try: | |||
|
241 | fname = sys.argv[1] | |||
|
242 | except: | |||
|
243 | usage() | |||
|
244 | ||||
|
245 | # write colorized version to stdout | |||
|
246 | parser = Parser() | |||
|
247 | try: | |||
|
248 | parser.format(file(fname).read(),scheme = scheme_name) | |||
|
249 | except IOError,msg: | |||
|
250 | # if user reads through a pager and quits, don't print traceback | |||
|
251 | if msg.args != (32,'Broken pipe'): | |||
|
252 | raise | |||
|
253 | ||||
|
254 | if __name__ == "__main__": | |||
|
255 | main() |
@@ -0,0 +1,69 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Release data for the IPython project. | |||
|
3 | ||||
|
4 | $Id: Release.py 605 2005-06-09 14:09:03Z fperez $""" | |||
|
5 | ||||
|
6 | #***************************************************************************** | |||
|
7 | # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu> | |||
|
8 | # | |||
|
9 | # Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray | |||
|
10 | # <n8gray@caltech.edu> | |||
|
11 | # | |||
|
12 | # Distributed under the terms of the BSD License. The full license is in | |||
|
13 | # the file COPYING, distributed as part of this software. | |||
|
14 | #***************************************************************************** | |||
|
15 | ||||
|
16 | # Name of the package for release purposes. This is the name which labels | |||
|
17 | # the tarballs and RPMs made by distutils, so it's best to lowercase it. | |||
|
18 | name = 'ipython' | |||
|
19 | ||||
|
20 | # For versions with substrings (like 0.6.7_rc1), use _ but NOT -, since | |||
|
21 | # bdist_rpm chokes on dashes in the version string. | |||
|
22 | version = '0.6.16_cvs' | |||
|
23 | ||||
|
24 | description = "An enhanced interactive Python shell." | |||
|
25 | ||||
|
26 | long_description = \ | |||
|
27 | """ | |||
|
28 | IPython provides a replacement for the interactive Python interpreter with | |||
|
29 | extra functionality. | |||
|
30 | ||||
|
31 | Main features: | |||
|
32 | ||||
|
33 | * Comprehensive object introspection. | |||
|
34 | ||||
|
35 | * Input history, persistent across sessions. | |||
|
36 | ||||
|
37 | * Caching of output results during a session with automatically generated | |||
|
38 | references. | |||
|
39 | ||||
|
40 | * Readline based name completion. | |||
|
41 | ||||
|
42 | * Extensible system of 'magic' commands for controlling the environment and | |||
|
43 | performing many tasks related either to IPython or the operating system. | |||
|
44 | ||||
|
45 | * Configuration system with easy switching between different setups (simpler | |||
|
46 | than changing $PYTHONSTARTUP environment variables every time). | |||
|
47 | ||||
|
48 | * Session logging and reloading. | |||
|
49 | ||||
|
50 | * Extensible syntax processing for special purpose situations. | |||
|
51 | ||||
|
52 | * Access to the system shell with user-extensible alias system. | |||
|
53 | ||||
|
54 | * Easily embeddable in other Python programs. | |||
|
55 | ||||
|
56 | * Integrated access to the pdb debugger and the Python profiler. """ | |||
|
57 | ||||
|
58 | license = 'BSD' | |||
|
59 | ||||
|
60 | authors = {'Fernando' : ('Fernando Perez','fperez@colorado.edu'), | |||
|
61 | 'Janko' : ('Janko Hauser','jhauser@zscout.de'), | |||
|
62 | 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu') | |||
|
63 | } | |||
|
64 | ||||
|
65 | url = 'http://ipython.scipy.org' | |||
|
66 | ||||
|
67 | platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME'] | |||
|
68 | ||||
|
69 | keywords = ['Interactive','Interpreter','Shell'] |
This diff has been collapsed as it changes many lines, (894 lines changed) Show them Hide them | |||||
@@ -0,0 +1,894 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """IPython Shell classes. | |||
|
3 | ||||
|
4 | All the matplotlib support code was co-developed with John Hunter, | |||
|
5 | matplotlib's author. | |||
|
6 | ||||
|
7 | $Id: Shell.py 605 2005-06-09 14:09:03Z fperez $""" | |||
|
8 | ||||
|
9 | #***************************************************************************** | |||
|
10 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
11 | # | |||
|
12 | # Distributed under the terms of the BSD License. The full license is in | |||
|
13 | # the file COPYING, distributed as part of this software. | |||
|
14 | #***************************************************************************** | |||
|
15 | ||||
|
16 | from IPython import Release | |||
|
17 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
18 | __license__ = Release.license | |||
|
19 | ||||
|
20 | # Code begins | |||
|
21 | import __main__ | |||
|
22 | import __builtin__ | |||
|
23 | import sys | |||
|
24 | import os | |||
|
25 | import code | |||
|
26 | import threading | |||
|
27 | import signal | |||
|
28 | ||||
|
29 | import IPython | |||
|
30 | from IPython.iplib import InteractiveShell | |||
|
31 | from IPython.ipmaker import make_IPython | |||
|
32 | from IPython.genutils import Term,warn,error,flag_calls | |||
|
33 | from IPython.Struct import Struct | |||
|
34 | from IPython.Magic import Magic | |||
|
35 | from IPython import ultraTB | |||
|
36 | ||||
|
37 | # global flag to pass around information about Ctrl-C without exceptions | |||
|
38 | KBINT = False | |||
|
39 | ||||
|
40 | # global flag to turn on/off Tk support. | |||
|
41 | USE_TK = False | |||
|
42 | ||||
|
43 | #----------------------------------------------------------------------------- | |||
|
44 | # This class is trivial now, but I want to have it in to publish a clean | |||
|
45 | # interface. Later when the internals are reorganized, code that uses this | |||
|
46 | # shouldn't have to change. | |||
|
47 | ||||
|
48 | class IPShell: | |||
|
49 | """Create an IPython instance.""" | |||
|
50 | ||||
|
51 | def __init__(self,argv=None,user_ns=None,debug=1, | |||
|
52 | shell_class=InteractiveShell): | |||
|
53 | self.IP = make_IPython(argv,user_ns=user_ns,debug=debug, | |||
|
54 | shell_class=shell_class) | |||
|
55 | ||||
|
56 | def mainloop(self,sys_exit=0,banner=None): | |||
|
57 | self.IP.mainloop(banner) | |||
|
58 | if sys_exit: | |||
|
59 | sys.exit() | |||
|
60 | ||||
|
61 | #----------------------------------------------------------------------------- | |||
|
62 | class IPShellEmbed: | |||
|
63 | """Allow embedding an IPython shell into a running program. | |||
|
64 | ||||
|
65 | Instances of this class are callable, with the __call__ method being an | |||
|
66 | alias to the embed() method of an InteractiveShell instance. | |||
|
67 | ||||
|
68 | Usage (see also the example-embed.py file for a running example): | |||
|
69 | ||||
|
70 | ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override]) | |||
|
71 | ||||
|
72 | - argv: list containing valid command-line options for IPython, as they | |||
|
73 | would appear in sys.argv[1:]. | |||
|
74 | ||||
|
75 | For example, the following command-line options: | |||
|
76 | ||||
|
77 | $ ipython -prompt_in1 'Input <\\#>' -colors LightBG | |||
|
78 | ||||
|
79 | would be passed in the argv list as: | |||
|
80 | ||||
|
81 | ['-prompt_in1','Input <\\#>','-colors','LightBG'] | |||
|
82 | ||||
|
83 | - banner: string which gets printed every time the interpreter starts. | |||
|
84 | ||||
|
85 | - exit_msg: string which gets printed every time the interpreter exits. | |||
|
86 | ||||
|
87 | - rc_override: a dict or Struct of configuration options such as those | |||
|
88 | used by IPython. These options are read from your ~/.ipython/ipythonrc | |||
|
89 | file when the Shell object is created. Passing an explicit rc_override | |||
|
90 | dict with any options you want allows you to override those values at | |||
|
91 | creation time without having to modify the file. This way you can create | |||
|
92 | embeddable instances configured in any way you want without editing any | |||
|
93 | global files (thus keeping your interactive IPython configuration | |||
|
94 | unchanged). | |||
|
95 | ||||
|
96 | Then the ipshell instance can be called anywhere inside your code: | |||
|
97 | ||||
|
98 | ipshell(header='') -> Opens up an IPython shell. | |||
|
99 | ||||
|
100 | - header: string printed by the IPython shell upon startup. This can let | |||
|
101 | you know where in your code you are when dropping into the shell. Note | |||
|
102 | that 'banner' gets prepended to all calls, so header is used for | |||
|
103 | location-specific information. | |||
|
104 | ||||
|
105 | For more details, see the __call__ method below. | |||
|
106 | ||||
|
107 | When the IPython shell is exited with Ctrl-D, normal program execution | |||
|
108 | resumes. | |||
|
109 | ||||
|
110 | This functionality was inspired by a posting on comp.lang.python by cmkl | |||
|
111 | <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and | |||
|
112 | by the IDL stop/continue commands.""" | |||
|
113 | ||||
|
114 | def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None): | |||
|
115 | """Note that argv here is a string, NOT a list.""" | |||
|
116 | self.set_banner(banner) | |||
|
117 | self.set_exit_msg(exit_msg) | |||
|
118 | self.set_dummy_mode(0) | |||
|
119 | ||||
|
120 | # sys.displayhook is a global, we need to save the user's original | |||
|
121 | # Don't rely on __displayhook__, as the user may have changed that. | |||
|
122 | self.sys_displayhook_ori = sys.displayhook | |||
|
123 | ||||
|
124 | # save readline completer status | |||
|
125 | try: | |||
|
126 | #print 'Save completer',sys.ipcompleter # dbg | |||
|
127 | self.sys_ipcompleter_ori = sys.ipcompleter | |||
|
128 | except: | |||
|
129 | pass # not nested with IPython | |||
|
130 | ||||
|
131 | # FIXME. Passing user_ns breaks namespace handling. | |||
|
132 | #self.IP = make_IPython(argv,user_ns=__main__.__dict__) | |||
|
133 | self.IP = make_IPython(argv,rc_override=rc_override,embedded=True) | |||
|
134 | ||||
|
135 | self.IP.name_space_init() | |||
|
136 | # mark this as an embedded instance so we know if we get a crash | |||
|
137 | # post-mortem | |||
|
138 | self.IP.rc.embedded = 1 | |||
|
139 | # copy our own displayhook also | |||
|
140 | self.sys_displayhook_embed = sys.displayhook | |||
|
141 | # and leave the system's display hook clean | |||
|
142 | sys.displayhook = self.sys_displayhook_ori | |||
|
143 | # don't use the ipython crash handler so that user exceptions aren't | |||
|
144 | # trapped | |||
|
145 | sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors, | |||
|
146 | mode = self.IP.rc.xmode, | |||
|
147 | call_pdb = self.IP.rc.pdb) | |||
|
148 | self.restore_system_completer() | |||
|
149 | ||||
|
150 | def restore_system_completer(self): | |||
|
151 | """Restores the readline completer which was in place. | |||
|
152 | ||||
|
153 | This allows embedded IPython within IPython not to disrupt the | |||
|
154 | parent's completion. | |||
|
155 | """ | |||
|
156 | ||||
|
157 | try: | |||
|
158 | self.IP.readline.set_completer(self.sys_ipcompleter_ori) | |||
|
159 | sys.ipcompleter = self.sys_ipcompleter_ori | |||
|
160 | except: | |||
|
161 | pass | |||
|
162 | ||||
|
163 | def __call__(self,header='',local_ns=None,global_ns=None,dummy=None): | |||
|
164 | """Activate the interactive interpreter. | |||
|
165 | ||||
|
166 | __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start | |||
|
167 | the interpreter shell with the given local and global namespaces, and | |||
|
168 | optionally print a header string at startup. | |||
|
169 | ||||
|
170 | The shell can be globally activated/deactivated using the | |||
|
171 | set/get_dummy_mode methods. This allows you to turn off a shell used | |||
|
172 | for debugging globally. | |||
|
173 | ||||
|
174 | However, *each* time you call the shell you can override the current | |||
|
175 | state of dummy_mode with the optional keyword parameter 'dummy'. For | |||
|
176 | example, if you set dummy mode on with IPShell.set_dummy_mode(1), you | |||
|
177 | can still have a specific call work by making it as IPShell(dummy=0). | |||
|
178 | ||||
|
179 | The optional keyword parameter dummy controls whether the call | |||
|
180 | actually does anything. """ | |||
|
181 | ||||
|
182 | # Allow the dummy parameter to override the global __dummy_mode | |||
|
183 | if dummy or (dummy != 0 and self.__dummy_mode): | |||
|
184 | return | |||
|
185 | ||||
|
186 | # Set global subsystems (display,completions) to our values | |||
|
187 | sys.displayhook = self.sys_displayhook_embed | |||
|
188 | if self.IP.has_readline: | |||
|
189 | self.IP.readline.set_completer(self.IP.Completer.complete) | |||
|
190 | ||||
|
191 | if self.banner and header: | |||
|
192 | format = '%s\n%s\n' | |||
|
193 | else: | |||
|
194 | format = '%s%s\n' | |||
|
195 | banner = format % (self.banner,header) | |||
|
196 | ||||
|
197 | # Call the embedding code with a stack depth of 1 so it can skip over | |||
|
198 | # our call and get the original caller's namespaces. | |||
|
199 | self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1) | |||
|
200 | ||||
|
201 | if self.exit_msg: | |||
|
202 | print self.exit_msg | |||
|
203 | ||||
|
204 | # Restore global systems (display, completion) | |||
|
205 | sys.displayhook = self.sys_displayhook_ori | |||
|
206 | self.restore_system_completer() | |||
|
207 | ||||
|
208 | def set_dummy_mode(self,dummy): | |||
|
209 | """Sets the embeddable shell's dummy mode parameter. | |||
|
210 | ||||
|
211 | set_dummy_mode(dummy): dummy = 0 or 1. | |||
|
212 | ||||
|
213 | This parameter is persistent and makes calls to the embeddable shell | |||
|
214 | silently return without performing any action. This allows you to | |||
|
215 | globally activate or deactivate a shell you're using with a single call. | |||
|
216 | ||||
|
217 | If you need to manually""" | |||
|
218 | ||||
|
219 | if dummy not in [0,1]: | |||
|
220 | raise ValueError,'dummy parameter must be 0 or 1' | |||
|
221 | self.__dummy_mode = dummy | |||
|
222 | ||||
|
223 | def get_dummy_mode(self): | |||
|
224 | """Return the current value of the dummy mode parameter. | |||
|
225 | """ | |||
|
226 | return self.__dummy_mode | |||
|
227 | ||||
|
228 | def set_banner(self,banner): | |||
|
229 | """Sets the global banner. | |||
|
230 | ||||
|
231 | This banner gets prepended to every header printed when the shell | |||
|
232 | instance is called.""" | |||
|
233 | ||||
|
234 | self.banner = banner | |||
|
235 | ||||
|
236 | def set_exit_msg(self,exit_msg): | |||
|
237 | """Sets the global exit_msg. | |||
|
238 | ||||
|
239 | This exit message gets printed upon exiting every time the embedded | |||
|
240 | shell is called. It is None by default. """ | |||
|
241 | ||||
|
242 | self.exit_msg = exit_msg | |||
|
243 | ||||
|
244 | #----------------------------------------------------------------------------- | |||
|
245 | def sigint_handler (signum,stack_frame): | |||
|
246 | """Sigint handler for threaded apps. | |||
|
247 | ||||
|
248 | This is a horrible hack to pass information about SIGINT _without_ using | |||
|
249 | exceptions, since I haven't been able to properly manage cross-thread | |||
|
250 | exceptions in GTK/WX. In fact, I don't think it can be done (or at least | |||
|
251 | that's my understanding from a c.l.py thread where this was discussed).""" | |||
|
252 | ||||
|
253 | global KBINT | |||
|
254 | ||||
|
255 | print '\nKeyboardInterrupt - Press <Enter> to continue.', | |||
|
256 | Term.cout.flush() | |||
|
257 | # Set global flag so that runsource can know that Ctrl-C was hit | |||
|
258 | KBINT = True | |||
|
259 | ||||
|
260 | class MTInteractiveShell(InteractiveShell): | |||
|
261 | """Simple multi-threaded shell.""" | |||
|
262 | ||||
|
263 | # Threading strategy taken from: | |||
|
264 | # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian | |||
|
265 | # McErlean and John Finlay. Modified with corrections by Antoon Pardon, | |||
|
266 | # from the pygtk mailing list, to avoid lockups with system calls. | |||
|
267 | ||||
|
268 | def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), | |||
|
269 | user_ns = None, banner2='',**kw): | |||
|
270 | """Similar to the normal InteractiveShell, but with threading control""" | |||
|
271 | ||||
|
272 | IPython.iplib.InteractiveShell.__init__(self,name,usage,rc,user_ns,banner2) | |||
|
273 | ||||
|
274 | # Locking control variable | |||
|
275 | self.thread_ready = threading.Condition() | |||
|
276 | ||||
|
277 | # Stuff to do at closing time | |||
|
278 | self._kill = False | |||
|
279 | on_kill = kw.get('on_kill') | |||
|
280 | if on_kill is None: | |||
|
281 | on_kill = [] | |||
|
282 | # Check that all things to kill are callable: | |||
|
283 | for t in on_kill: | |||
|
284 | if not callable(t): | |||
|
285 | raise TypeError,'on_kill must be a list of callables' | |||
|
286 | self.on_kill = on_kill | |||
|
287 | ||||
|
288 | def runsource(self, source, filename="<input>", symbol="single"): | |||
|
289 | """Compile and run some source in the interpreter. | |||
|
290 | ||||
|
291 | Modified version of code.py's runsource(), to handle threading issues. | |||
|
292 | See the original for full docstring details.""" | |||
|
293 | ||||
|
294 | global KBINT | |||
|
295 | ||||
|
296 | # If Ctrl-C was typed, we reset the flag and return right away | |||
|
297 | if KBINT: | |||
|
298 | KBINT = False | |||
|
299 | return False | |||
|
300 | ||||
|
301 | try: | |||
|
302 | code = self.compile(source, filename, symbol) | |||
|
303 | except (OverflowError, SyntaxError, ValueError): | |||
|
304 | # Case 1 | |||
|
305 | self.showsyntaxerror(filename) | |||
|
306 | return False | |||
|
307 | ||||
|
308 | if code is None: | |||
|
309 | # Case 2 | |||
|
310 | return True | |||
|
311 | ||||
|
312 | # Case 3 | |||
|
313 | # Store code in self, so the execution thread can handle it | |||
|
314 | self.thread_ready.acquire() | |||
|
315 | self.code_to_run_src = source | |||
|
316 | self.code_to_run = code | |||
|
317 | self.thread_ready.wait() # Wait until processed in timeout interval | |||
|
318 | self.thread_ready.release() | |||
|
319 | ||||
|
320 | return False | |||
|
321 | ||||
|
322 | def runcode(self): | |||
|
323 | """Execute a code object. | |||
|
324 | ||||
|
325 | Multithreaded wrapper around IPython's runcode().""" | |||
|
326 | ||||
|
327 | # lock thread-protected stuff | |||
|
328 | self.thread_ready.acquire() | |||
|
329 | ||||
|
330 | # Install sigint handler | |||
|
331 | try: | |||
|
332 | signal.signal(signal.SIGINT, sigint_handler) | |||
|
333 | except SystemError: | |||
|
334 | # This happens under Windows, which seems to have all sorts | |||
|
335 | # of problems with signal handling. Oh well... | |||
|
336 | pass | |||
|
337 | ||||
|
338 | if self._kill: | |||
|
339 | print >>Term.cout, 'Closing threads...', | |||
|
340 | Term.cout.flush() | |||
|
341 | for tokill in self.on_kill: | |||
|
342 | tokill() | |||
|
343 | print >>Term.cout, 'Done.' | |||
|
344 | ||||
|
345 | # Run pending code by calling parent class | |||
|
346 | if self.code_to_run is not None: | |||
|
347 | self.thread_ready.notify() | |||
|
348 | InteractiveShell.runcode(self,self.code_to_run) | |||
|
349 | ||||
|
350 | # We're done with thread-protected variables | |||
|
351 | self.thread_ready.release() | |||
|
352 | # This MUST return true for gtk threading to work | |||
|
353 | return True | |||
|
354 | ||||
|
355 | def kill (self): | |||
|
356 | """Kill the thread, returning when it has been shut down.""" | |||
|
357 | self.thread_ready.acquire() | |||
|
358 | self._kill = True | |||
|
359 | self.thread_ready.release() | |||
|
360 | ||||
|
361 | class MatplotlibShellBase: | |||
|
362 | """Mixin class to provide the necessary modifications to regular IPython | |||
|
363 | shell classes for matplotlib support. | |||
|
364 | ||||
|
365 | Given Python's MRO, this should be used as the FIRST class in the | |||
|
366 | inheritance hierarchy, so that it overrides the relevant methods.""" | |||
|
367 | ||||
|
368 | def _matplotlib_config(self,name): | |||
|
369 | """Return various items needed to setup the user's shell with matplotlib""" | |||
|
370 | ||||
|
371 | # Initialize matplotlib to interactive mode always | |||
|
372 | import matplotlib | |||
|
373 | from matplotlib import backends | |||
|
374 | matplotlib.interactive(True) | |||
|
375 | ||||
|
376 | def use(arg): | |||
|
377 | """IPython wrapper for matplotlib's backend switcher. | |||
|
378 | ||||
|
379 | In interactive use, we can not allow switching to a different | |||
|
380 | interactive backend, since thread conflicts will most likely crash | |||
|
381 | the python interpreter. This routine does a safety check first, | |||
|
382 | and refuses to perform a dangerous switch. It still allows | |||
|
383 | switching to non-interactive backends.""" | |||
|
384 | ||||
|
385 | if arg in backends.interactive_bk and arg != self.mpl_backend: | |||
|
386 | m=('invalid matplotlib backend switch.\n' | |||
|
387 | 'This script attempted to switch to the interactive ' | |||
|
388 | 'backend: `%s`\n' | |||
|
389 | 'Your current choice of interactive backend is: `%s`\n\n' | |||
|
390 | 'Switching interactive matplotlib backends at runtime\n' | |||
|
391 | 'would crash the python interpreter, ' | |||
|
392 | 'and IPython has blocked it.\n\n' | |||
|
393 | 'You need to either change your choice of matplotlib backend\n' | |||
|
394 | 'by editing your .matplotlibrc file, or run this script as a \n' | |||
|
395 | 'standalone file from the command line, not using IPython.\n' % | |||
|
396 | (arg,self.mpl_backend) ) | |||
|
397 | raise RuntimeError, m | |||
|
398 | else: | |||
|
399 | self.mpl_use(arg) | |||
|
400 | self.mpl_use._called = True | |||
|
401 | ||||
|
402 | self.matplotlib = matplotlib | |||
|
403 | ||||
|
404 | # Take control of matplotlib's error handling, which can normally | |||
|
405 | # lock up the python interpreter when raw_input() is called | |||
|
406 | import matplotlib.backends as backend | |||
|
407 | backend.error_msg = error | |||
|
408 | ||||
|
409 | # we'll handle the mainloop, tell show not to | |||
|
410 | import matplotlib.backends | |||
|
411 | matplotlib.backends.show._needmain = False | |||
|
412 | self.mpl_backend = matplotlib.rcParams['backend'] | |||
|
413 | ||||
|
414 | # we also need to block switching of interactive backends by use() | |||
|
415 | self.mpl_use = matplotlib.use | |||
|
416 | self.mpl_use._called = False | |||
|
417 | # overwrite the original matplotlib.use with our wrapper | |||
|
418 | matplotlib.use = use | |||
|
419 | ||||
|
420 | # We need to detect at runtime whether show() is called by the user. | |||
|
421 | # For this, we wrap it into a decorator which adds a 'called' flag. | |||
|
422 | backend.draw_if_interactive = flag_calls(backend.draw_if_interactive) | |||
|
423 | ||||
|
424 | # This must be imported last in the matplotlib series, after | |||
|
425 | # backend/interactivity choices have been made | |||
|
426 | try: | |||
|
427 | import matplotlib.pylab as pylab | |||
|
428 | self.pylab = pylab | |||
|
429 | self.pylab_name = 'pylab' | |||
|
430 | except ImportError: | |||
|
431 | import matplotlib.matlab as matlab | |||
|
432 | self.pylab = matlab | |||
|
433 | self.pylab_name = 'matlab' | |||
|
434 | ||||
|
435 | # Build a user namespace initialized with matplotlib/matlab features. | |||
|
436 | user_ns = {'__name__':'__main__', | |||
|
437 | '__builtins__' : __builtin__ } | |||
|
438 | ||||
|
439 | # Be careful not to remove the final \n in the code string below, or | |||
|
440 | # things will break badly with py22 (I think it's a python bug, 2.3 is | |||
|
441 | # OK). | |||
|
442 | pname = self.pylab_name # Python can't interpolate dotted var names | |||
|
443 | exec ("import matplotlib\n" | |||
|
444 | "import matplotlib.%(pname)s as %(pname)s\n" | |||
|
445 | "from matplotlib.%(pname)s import *\n" % locals()) in user_ns | |||
|
446 | ||||
|
447 | # Build matplotlib info banner | |||
|
448 | b=""" | |||
|
449 | Welcome to pylab, a matplotlib-based Python environment. | |||
|
450 | For more information, type 'help(pylab)'. | |||
|
451 | """ | |||
|
452 | return user_ns,b | |||
|
453 | ||||
|
454 | def mplot_exec(self,fname,*where,**kw): | |||
|
455 | """Execute a matplotlib script. | |||
|
456 | ||||
|
457 | This is a call to execfile(), but wrapped in safeties to properly | |||
|
458 | handle interactive rendering and backend switching.""" | |||
|
459 | ||||
|
460 | #print '*** Matplotlib runner ***' # dbg | |||
|
461 | # turn off rendering until end of script | |||
|
462 | isInteractive = self.matplotlib.rcParams['interactive'] | |||
|
463 | self.matplotlib.interactive(False) | |||
|
464 | self.safe_execfile(fname,*where,**kw) | |||
|
465 | self.matplotlib.interactive(isInteractive) | |||
|
466 | # make rendering call now, if the user tried to do it | |||
|
467 | if self.pylab.draw_if_interactive.called: | |||
|
468 | self.pylab.draw() | |||
|
469 | self.pylab.draw_if_interactive.called = False | |||
|
470 | ||||
|
471 | # if a backend switch was performed, reverse it now | |||
|
472 | if self.mpl_use._called: | |||
|
473 | self.matplotlib.rcParams['backend'] = self.mpl_backend | |||
|
474 | ||||
|
475 | def magic_run(self,parameter_s=''): | |||
|
476 | Magic.magic_run(self,parameter_s,runner=self.mplot_exec) | |||
|
477 | ||||
|
478 | # Fix the docstring so users see the original as well | |||
|
479 | magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__, | |||
|
480 | "\n *** Modified %run for Matplotlib," | |||
|
481 | " with proper interactive handling ***") | |||
|
482 | ||||
|
483 | # Now we provide 2 versions of a matplotlib-aware IPython base shells, single | |||
|
484 | # and multithreaded. Note that these are meant for internal use, the IPShell* | |||
|
485 | # classes below are the ones meant for public consumption. | |||
|
486 | ||||
|
487 | class MatplotlibShell(MatplotlibShellBase,InteractiveShell): | |||
|
488 | """Single-threaded shell with matplotlib support.""" | |||
|
489 | ||||
|
490 | def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), | |||
|
491 | user_ns = None, **kw): | |||
|
492 | user_ns,b2 = self._matplotlib_config(name) | |||
|
493 | InteractiveShell.__init__(self,name,usage,rc,user_ns,banner2=b2,**kw) | |||
|
494 | ||||
|
495 | class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell): | |||
|
496 | """Multi-threaded shell with matplotlib support.""" | |||
|
497 | ||||
|
498 | def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), | |||
|
499 | user_ns = None, **kw): | |||
|
500 | user_ns,b2 = self._matplotlib_config(name) | |||
|
501 | MTInteractiveShell.__init__(self,name,usage,rc,user_ns,banner2=b2,**kw) | |||
|
502 | ||||
|
503 | #----------------------------------------------------------------------------- | |||
|
504 | # Utility functions for the different GUI enabled IPShell* classes. | |||
|
505 | ||||
|
506 | def get_tk(): | |||
|
507 | """Tries to import Tkinter and returns a withdrawn Tkinter root | |||
|
508 | window. If Tkinter is already imported or not available, this | |||
|
509 | returns None. This function calls `hijack_tk` underneath. | |||
|
510 | """ | |||
|
511 | if not USE_TK or sys.modules.has_key('Tkinter'): | |||
|
512 | return None | |||
|
513 | else: | |||
|
514 | try: | |||
|
515 | import Tkinter | |||
|
516 | except ImportError: | |||
|
517 | return None | |||
|
518 | else: | |||
|
519 | hijack_tk() | |||
|
520 | r = Tkinter.Tk() | |||
|
521 | r.withdraw() | |||
|
522 | return r | |||
|
523 | ||||
|
524 | def hijack_tk(): | |||
|
525 | """Modifies Tkinter's mainloop with a dummy so when a module calls | |||
|
526 | mainloop, it does not block. | |||
|
527 | ||||
|
528 | """ | |||
|
529 | def misc_mainloop(self, n=0): | |||
|
530 | pass | |||
|
531 | def tkinter_mainloop(n=0): | |||
|
532 | pass | |||
|
533 | ||||
|
534 | import Tkinter | |||
|
535 | Tkinter.Misc.mainloop = misc_mainloop | |||
|
536 | Tkinter.mainloop = tkinter_mainloop | |||
|
537 | ||||
|
538 | def update_tk(tk): | |||
|
539 | """Updates the Tkinter event loop. This is typically called from | |||
|
540 | the respective WX or GTK mainloops. | |||
|
541 | """ | |||
|
542 | if tk: | |||
|
543 | tk.update() | |||
|
544 | ||||
|
545 | def hijack_wx(): | |||
|
546 | """Modifies wxPython's MainLoop with a dummy so user code does not | |||
|
547 | block IPython. The hijacked mainloop function is returned. | |||
|
548 | """ | |||
|
549 | def dummy_mainloop(*args, **kw): | |||
|
550 | pass | |||
|
551 | import wxPython | |||
|
552 | ver = wxPython.__version__ | |||
|
553 | orig_mainloop = None | |||
|
554 | if ver[:3] >= '2.5': | |||
|
555 | import wx | |||
|
556 | if hasattr(wx, '_core_'): core = getattr(wx, '_core_') | |||
|
557 | elif hasattr(wx, '_core'): core = getattr(wx, '_core') | |||
|
558 | else: raise AttributeError('Could not find wx core module') | |||
|
559 | orig_mainloop = core.PyApp_MainLoop | |||
|
560 | core.PyApp_MainLoop = dummy_mainloop | |||
|
561 | elif ver[:3] == '2.4': | |||
|
562 | orig_mainloop = wxPython.wxc.wxPyApp_MainLoop | |||
|
563 | wxPython.wxc.wxPyApp_MainLoop = dummy_mainloop | |||
|
564 | else: | |||
|
565 | warn("Unable to find either wxPython version 2.4 or >= 2.5.") | |||
|
566 | return orig_mainloop | |||
|
567 | ||||
|
568 | def hijack_gtk(): | |||
|
569 | """Modifies pyGTK's mainloop with a dummy so user code does not | |||
|
570 | block IPython. This function returns the original `gtk.mainloop` | |||
|
571 | function that has been hijacked. | |||
|
572 | ||||
|
573 | NOTE: Make sure you import this *AFTER* you call | |||
|
574 | pygtk.require(...). | |||
|
575 | """ | |||
|
576 | def dummy_mainloop(*args, **kw): | |||
|
577 | pass | |||
|
578 | import gtk | |||
|
579 | if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main | |||
|
580 | else: orig_mainloop = gtk.mainloop | |||
|
581 | gtk.mainloop = dummy_mainloop | |||
|
582 | gtk.main = dummy_mainloop | |||
|
583 | return orig_mainloop | |||
|
584 | ||||
|
585 | #----------------------------------------------------------------------------- | |||
|
586 | # The IPShell* classes below are the ones meant to be run by external code as | |||
|
587 | # IPython instances. Note that unless a specific threading strategy is | |||
|
588 | # desired, the factory function start() below should be used instead (it | |||
|
589 | # selects the proper threaded class). | |||
|
590 | ||||
|
591 | class IPShellGTK(threading.Thread): | |||
|
592 | """Run a gtk mainloop() in a separate thread. | |||
|
593 | ||||
|
594 | Python commands can be passed to the thread where they will be executed. | |||
|
595 | This is implemented by periodically checking for passed code using a | |||
|
596 | GTK timeout callback.""" | |||
|
597 | ||||
|
598 | TIMEOUT = 100 # Millisecond interval between timeouts. | |||
|
599 | ||||
|
600 | def __init__(self,argv=None,user_ns=None,debug=1, | |||
|
601 | shell_class=MTInteractiveShell): | |||
|
602 | ||||
|
603 | import pygtk | |||
|
604 | pygtk.require("2.0") | |||
|
605 | import gtk | |||
|
606 | ||||
|
607 | self.gtk = gtk | |||
|
608 | self.gtk_mainloop = hijack_gtk() | |||
|
609 | ||||
|
610 | # Allows us to use both Tk and GTK. | |||
|
611 | self.tk = get_tk() | |||
|
612 | ||||
|
613 | if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit | |||
|
614 | else: mainquit = self.gtk.mainquit | |||
|
615 | ||||
|
616 | self.IP = make_IPython(argv,user_ns=user_ns,debug=debug, | |||
|
617 | shell_class=shell_class, | |||
|
618 | on_kill=[mainquit]) | |||
|
619 | threading.Thread.__init__(self) | |||
|
620 | ||||
|
621 | def run(self): | |||
|
622 | self.IP.mainloop() | |||
|
623 | self.IP.kill() | |||
|
624 | ||||
|
625 | def mainloop(self): | |||
|
626 | ||||
|
627 | if self.gtk.pygtk_version >= (2,4,0): | |||
|
628 | import gobject | |||
|
629 | gobject.timeout_add(self.TIMEOUT, self.on_timer) | |||
|
630 | else: | |||
|
631 | self.gtk.timeout_add(self.TIMEOUT, self.on_timer) | |||
|
632 | ||||
|
633 | if sys.platform != 'win32': | |||
|
634 | try: | |||
|
635 | if self.gtk.gtk_version[0] >= 2: | |||
|
636 | self.gtk.threads_init() | |||
|
637 | except AttributeError: | |||
|
638 | pass | |||
|
639 | except RuntimeError: | |||
|
640 | error('Your pyGTK likely has not been compiled with ' | |||
|
641 | 'threading support.\n' | |||
|
642 | 'The exception printout is below.\n' | |||
|
643 | 'You can either rebuild pyGTK with threads, or ' | |||
|
644 | 'try using \n' | |||
|
645 | 'matplotlib with a different backend (like Tk or WX).\n' | |||
|
646 | 'Note that matplotlib will most likely not work in its ' | |||
|
647 | 'current state!') | |||
|
648 | self.IP.InteractiveTB() | |||
|
649 | self.start() | |||
|
650 | self.gtk.threads_enter() | |||
|
651 | self.gtk_mainloop() | |||
|
652 | self.gtk.threads_leave() | |||
|
653 | self.join() | |||
|
654 | ||||
|
655 | def on_timer(self): | |||
|
656 | update_tk(self.tk) | |||
|
657 | return self.IP.runcode() | |||
|
658 | ||||
|
659 | ||||
|
660 | class IPShellWX(threading.Thread): | |||
|
661 | """Run a wx mainloop() in a separate thread. | |||
|
662 | ||||
|
663 | Python commands can be passed to the thread where they will be executed. | |||
|
664 | This is implemented by periodically checking for passed code using a | |||
|
665 | GTK timeout callback.""" | |||
|
666 | ||||
|
667 | TIMEOUT = 100 # Millisecond interval between timeouts. | |||
|
668 | ||||
|
669 | def __init__(self,argv=None,user_ns=None,debug=1, | |||
|
670 | shell_class=MTInteractiveShell): | |||
|
671 | ||||
|
672 | import wxPython.wx as wx | |||
|
673 | ||||
|
674 | threading.Thread.__init__(self) | |||
|
675 | self.wx = wx | |||
|
676 | self.wx_mainloop = hijack_wx() | |||
|
677 | ||||
|
678 | # Allows us to use both Tk and GTK. | |||
|
679 | self.tk = get_tk() | |||
|
680 | ||||
|
681 | self.IP = make_IPython(argv,user_ns=user_ns,debug=debug, | |||
|
682 | shell_class=shell_class, | |||
|
683 | on_kill=[self.wxexit]) | |||
|
684 | self.app = None | |||
|
685 | ||||
|
686 | def wxexit(self, *args): | |||
|
687 | if self.app is not None: | |||
|
688 | self.app.agent.timer.Stop() | |||
|
689 | self.app.ExitMainLoop() | |||
|
690 | ||||
|
691 | def run(self): | |||
|
692 | self.IP.mainloop() | |||
|
693 | self.IP.kill() | |||
|
694 | ||||
|
695 | def mainloop(self): | |||
|
696 | ||||
|
697 | self.start() | |||
|
698 | ||||
|
699 | class TimerAgent(self.wx.wxMiniFrame): | |||
|
700 | wx = self.wx | |||
|
701 | IP = self.IP | |||
|
702 | tk = self.tk | |||
|
703 | def __init__(self, parent, interval): | |||
|
704 | style = self.wx.wxDEFAULT_FRAME_STYLE | self.wx.wxTINY_CAPTION_HORIZ | |||
|
705 | self.wx.wxMiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200), | |||
|
706 | size=(100, 100),style=style) | |||
|
707 | self.Show(False) | |||
|
708 | self.interval = interval | |||
|
709 | self.timerId = self.wx.wxNewId() | |||
|
710 | ||||
|
711 | def StartWork(self): | |||
|
712 | self.timer = self.wx.wxTimer(self, self.timerId) | |||
|
713 | self.wx.EVT_TIMER(self, self.timerId, self.OnTimer) | |||
|
714 | self.timer.Start(self.interval) | |||
|
715 | ||||
|
716 | def OnTimer(self, event): | |||
|
717 | update_tk(self.tk) | |||
|
718 | self.IP.runcode() | |||
|
719 | ||||
|
720 | class App(self.wx.wxApp): | |||
|
721 | wx = self.wx | |||
|
722 | TIMEOUT = self.TIMEOUT | |||
|
723 | def OnInit(self): | |||
|
724 | 'Create the main window and insert the custom frame' | |||
|
725 | self.agent = TimerAgent(None, self.TIMEOUT) | |||
|
726 | self.agent.Show(self.wx.false) | |||
|
727 | self.agent.StartWork() | |||
|
728 | return self.wx.true | |||
|
729 | ||||
|
730 | self.app = App(redirect=False) | |||
|
731 | self.wx_mainloop(self.app) | |||
|
732 | self.join() | |||
|
733 | ||||
|
734 | ||||
|
735 | class IPShellQt(threading.Thread): | |||
|
736 | """Run a Qt event loop in a separate thread. | |||
|
737 | ||||
|
738 | Python commands can be passed to the thread where they will be executed. | |||
|
739 | This is implemented by periodically checking for passed code using a | |||
|
740 | Qt timer / slot.""" | |||
|
741 | ||||
|
742 | TIMEOUT = 100 # Millisecond interval between timeouts. | |||
|
743 | ||||
|
744 | def __init__(self,argv=None,user_ns=None,debug=0, | |||
|
745 | shell_class=MTInteractiveShell): | |||
|
746 | ||||
|
747 | import qt | |||
|
748 | ||||
|
749 | class newQApplication: | |||
|
750 | def __init__( self ): | |||
|
751 | self.QApplication = qt.QApplication | |||
|
752 | ||||
|
753 | def __call__( *args, **kwargs ): | |||
|
754 | return qt.qApp | |||
|
755 | ||||
|
756 | def exec_loop( *args, **kwargs ): | |||
|
757 | pass | |||
|
758 | ||||
|
759 | def __getattr__( self, name ): | |||
|
760 | return getattr( self.QApplication, name ) | |||
|
761 | ||||
|
762 | qt.QApplication = newQApplication() | |||
|
763 | ||||
|
764 | # Allows us to use both Tk and QT. | |||
|
765 | self.tk = get_tk() | |||
|
766 | ||||
|
767 | self.IP = make_IPython(argv,user_ns=user_ns,debug=debug, | |||
|
768 | shell_class=shell_class, | |||
|
769 | on_kill=[qt.qApp.exit]) | |||
|
770 | ||||
|
771 | threading.Thread.__init__(self) | |||
|
772 | ||||
|
773 | def run(self): | |||
|
774 | #sys.excepthook = self.IP.excepthook # dbg | |||
|
775 | self.IP.mainloop() | |||
|
776 | self.IP.kill() | |||
|
777 | ||||
|
778 | def mainloop(self): | |||
|
779 | import qt, sys | |||
|
780 | if qt.QApplication.startingUp(): | |||
|
781 | a = qt.QApplication.QApplication( sys.argv ) | |||
|
782 | self.timer = qt.QTimer() | |||
|
783 | qt.QObject.connect( self.timer, qt.SIGNAL( 'timeout()' ), self.on_timer ) | |||
|
784 | ||||
|
785 | self.start() | |||
|
786 | self.timer.start( self.TIMEOUT, True ) | |||
|
787 | while True: | |||
|
788 | if self.IP._kill: break | |||
|
789 | qt.qApp.exec_loop() | |||
|
790 | self.join() | |||
|
791 | ||||
|
792 | def on_timer(self): | |||
|
793 | update_tk(self.tk) | |||
|
794 | result = self.IP.runcode() | |||
|
795 | self.timer.start( self.TIMEOUT, True ) | |||
|
796 | return result | |||
|
797 | ||||
|
798 | # A set of matplotlib public IPython shell classes, for single-threaded | |||
|
799 | # (Tk* and FLTK* backends) and multithreaded (GTK* and WX* backends) use. | |||
|
800 | class IPShellMatplotlib(IPShell): | |||
|
801 | """Subclass IPShell with MatplotlibShell as the internal shell. | |||
|
802 | ||||
|
803 | Single-threaded class, meant for the Tk* and FLTK* backends. | |||
|
804 | ||||
|
805 | Having this on a separate class simplifies the external driver code.""" | |||
|
806 | ||||
|
807 | def __init__(self,argv=None,user_ns=None,debug=1): | |||
|
808 | IPShell.__init__(self,argv,user_ns,debug,shell_class=MatplotlibShell) | |||
|
809 | ||||
|
810 | class IPShellMatplotlibGTK(IPShellGTK): | |||
|
811 | """Subclass IPShellGTK with MatplotlibMTShell as the internal shell. | |||
|
812 | ||||
|
813 | Multi-threaded class, meant for the GTK* backends.""" | |||
|
814 | ||||
|
815 | def __init__(self,argv=None,user_ns=None,debug=1): | |||
|
816 | IPShellGTK.__init__(self,argv,user_ns,debug,shell_class=MatplotlibMTShell) | |||
|
817 | ||||
|
818 | class IPShellMatplotlibWX(IPShellWX): | |||
|
819 | """Subclass IPShellWX with MatplotlibMTShell as the internal shell. | |||
|
820 | ||||
|
821 | Multi-threaded class, meant for the WX* backends.""" | |||
|
822 | ||||
|
823 | def __init__(self,argv=None,user_ns=None,debug=1): | |||
|
824 | IPShellWX.__init__(self,argv,user_ns,debug,shell_class=MatplotlibMTShell) | |||
|
825 | ||||
|
826 | class IPShellMatplotlibQt(IPShellQt): | |||
|
827 | """Subclass IPShellQt with MatplotlibMTShell as the internal shell. | |||
|
828 | ||||
|
829 | Multi-threaded class, meant for the Qt* backends.""" | |||
|
830 | ||||
|
831 | def __init__(self,argv=None,user_ns=None,debug=1): | |||
|
832 | IPShellQt.__init__(self,argv,user_ns,debug,shell_class=MatplotlibMTShell) | |||
|
833 | ||||
|
834 | #----------------------------------------------------------------------------- | |||
|
835 | # Factory functions to actually start the proper thread-aware shell | |||
|
836 | ||||
|
837 | def _matplotlib_shell_class(): | |||
|
838 | """Factory function to handle shell class selection for matplotlib. | |||
|
839 | ||||
|
840 | The proper shell class to use depends on the matplotlib backend, since | |||
|
841 | each backend requires a different threading strategy.""" | |||
|
842 | ||||
|
843 | try: | |||
|
844 | import matplotlib | |||
|
845 | except ImportError: | |||
|
846 | error('matplotlib could NOT be imported! Starting normal IPython.') | |||
|
847 | sh_class = IPShell | |||
|
848 | else: | |||
|
849 | backend = matplotlib.rcParams['backend'] | |||
|
850 | if backend.startswith('GTK'): | |||
|
851 | sh_class = IPShellMatplotlibGTK | |||
|
852 | elif backend.startswith('WX'): | |||
|
853 | sh_class = IPShellMatplotlibWX | |||
|
854 | elif backend.startswith('Qt'): | |||
|
855 | sh_class = IPShellMatplotlibQt | |||
|
856 | else: | |||
|
857 | sh_class = IPShellMatplotlib | |||
|
858 | #print 'Using %s with the %s backend.' % (sh_class,backend) # dbg | |||
|
859 | return sh_class | |||
|
860 | ||||
|
861 | # This is the one which should be called by external code. | |||
|
862 | def start(): | |||
|
863 | """Return a running shell instance, dealing with threading options. | |||
|
864 | ||||
|
865 | This is a factory function which will instantiate the proper IPython shell | |||
|
866 | based on the user's threading choice. Such a selector is needed because | |||
|
867 | different GUI toolkits require different thread handling details.""" | |||
|
868 | ||||
|
869 | global USE_TK | |||
|
870 | # Crude sys.argv hack to extract the threading options. | |||
|
871 | if len(sys.argv) > 1: | |||
|
872 | if len(sys.argv) > 2: | |||
|
873 | arg2 = sys.argv[2] | |||
|
874 | if arg2.endswith('-tk'): | |||
|
875 | USE_TK = True | |||
|
876 | arg1 = sys.argv[1] | |||
|
877 | if arg1.endswith('-gthread'): | |||
|
878 | shell = IPShellGTK | |||
|
879 | elif arg1.endswith( '-qthread' ): | |||
|
880 | shell = IPShellQt | |||
|
881 | elif arg1.endswith('-wthread'): | |||
|
882 | shell = IPShellWX | |||
|
883 | elif arg1.endswith('-pylab'): | |||
|
884 | shell = _matplotlib_shell_class() | |||
|
885 | else: | |||
|
886 | shell = IPShell | |||
|
887 | else: | |||
|
888 | shell = IPShell | |||
|
889 | return shell() | |||
|
890 | ||||
|
891 | # Some aliases for backwards compatibility | |||
|
892 | IPythonShell = IPShell | |||
|
893 | IPythonShellEmbed = IPShellEmbed | |||
|
894 | #************************ End of file <Shell.py> *************************** |
@@ -0,0 +1,376 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Mimic C structs with lots of extra functionality. | |||
|
3 | ||||
|
4 | $Id: Struct.py 410 2004-11-04 07:58:17Z fperez $""" | |||
|
5 | ||||
|
6 | #***************************************************************************** | |||
|
7 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |||
|
8 | # | |||
|
9 | # Distributed under the terms of the BSD License. The full license is in | |||
|
10 | # the file COPYING, distributed as part of this software. | |||
|
11 | #***************************************************************************** | |||
|
12 | ||||
|
13 | from IPython import Release | |||
|
14 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
15 | __license__ = Release.license | |||
|
16 | ||||
|
17 | __all__ = ['Struct'] | |||
|
18 | ||||
|
19 | import types | |||
|
20 | from IPython.genutils import list2dict2 | |||
|
21 | ||||
|
22 | class Struct: | |||
|
23 | """Class to mimic C structs but also provide convenient dictionary-like | |||
|
24 | functionality. | |||
|
25 | ||||
|
26 | Instances can be initialized with a dictionary, a list of key=value pairs | |||
|
27 | or both. If both are present, the dictionary must come first. | |||
|
28 | ||||
|
29 | Because Python classes provide direct assignment to their members, it's | |||
|
30 | easy to overwrite normal methods (S.copy = 1 would destroy access to | |||
|
31 | S.copy()). For this reason, all builtin method names are protected and | |||
|
32 | can't be assigned to. An attempt to do s.copy=1 or s['copy']=1 will raise | |||
|
33 | a KeyError exception. If you really want to, you can bypass this | |||
|
34 | protection by directly assigning to __dict__: s.__dict__['copy']=1 will | |||
|
35 | still work. Doing this will break functionality, though. As in most of | |||
|
36 | Python, namespace protection is weakly enforced, so feel free to shoot | |||
|
37 | yourself if you really want to. | |||
|
38 | ||||
|
39 | Note that this class uses more memory and is *much* slower than a regular | |||
|
40 | dictionary, so be careful in situations where memory or performance are | |||
|
41 | critical. But for day to day use it should behave fine. It is particularly | |||
|
42 | convenient for storing configuration data in programs. | |||
|
43 | ||||
|
44 | +,+=,- and -= are implemented. +/+= do merges (non-destructive updates), | |||
|
45 | -/-= remove keys from the original. See the method descripitions. | |||
|
46 | ||||
|
47 | This class allows a quick access syntax: both s.key and s['key'] are | |||
|
48 | valid. This syntax has a limitation: each 'key' has to be explicitly | |||
|
49 | accessed by its original name. The normal s.key syntax doesn't provide | |||
|
50 | access to the keys via variables whose values evaluate to the desired | |||
|
51 | keys. An example should clarify this: | |||
|
52 | ||||
|
53 | Define a dictionary and initialize both with dict and k=v pairs: | |||
|
54 | >>> d={'a':1,'b':2} | |||
|
55 | >>> s=Struct(d,hi=10,ho=20) | |||
|
56 | The return of __repr__ can be used to create a new instance: | |||
|
57 | >>> s | |||
|
58 | Struct({'ho': 20, 'b': 2, 'hi': 10, 'a': 1}) | |||
|
59 | __str__ (called by print) shows it's not quite a regular dictionary: | |||
|
60 | >>> print s | |||
|
61 | Struct {a: 1, b: 2, hi: 10, ho: 20} | |||
|
62 | Access by explicitly named key with dot notation: | |||
|
63 | >>> s.a | |||
|
64 | 1 | |||
|
65 | Or like a dictionary: | |||
|
66 | >>> s['a'] | |||
|
67 | 1 | |||
|
68 | If you want a variable to hold the key value, only dictionary access works: | |||
|
69 | >>> key='hi' | |||
|
70 | >>> s.key | |||
|
71 | Traceback (most recent call last): | |||
|
72 | File "<stdin>", line 1, in ? | |||
|
73 | AttributeError: Struct instance has no attribute 'key' | |||
|
74 | >>> s[key] | |||
|
75 | 10 | |||
|
76 | ||||
|
77 | Another limitation of the s.key syntax (and Struct(key=val) | |||
|
78 | initialization): keys can't be numbers. But numeric keys can be used and | |||
|
79 | accessed using the dictionary syntax. Again, an example: | |||
|
80 | ||||
|
81 | This doesn't work: | |||
|
82 | >>> s=Struct(4='hi') | |||
|
83 | SyntaxError: keyword can't be an expression | |||
|
84 | But this does: | |||
|
85 | >>> s=Struct() | |||
|
86 | >>> s[4]='hi' | |||
|
87 | >>> s | |||
|
88 | Struct({4: 'hi'}) | |||
|
89 | >>> s[4] | |||
|
90 | 'hi' | |||
|
91 | """ | |||
|
92 | ||||
|
93 | # Attributes to which __setitem__ and __setattr__ will block access. | |||
|
94 | # Note: much of this will be moot in Python 2.2 and will be done in a much | |||
|
95 | # cleaner way. | |||
|
96 | __protected = ('copy dict dictcopy get has_attr has_key items keys ' | |||
|
97 | 'merge popitem setdefault update values ' | |||
|
98 | '__make_dict __dict_invert ').split() | |||
|
99 | ||||
|
100 | def __init__(self,dict=None,**kw): | |||
|
101 | """Initialize with a dictionary, another Struct, or by giving | |||
|
102 | explicitly the list of attributes. | |||
|
103 | ||||
|
104 | Both can be used, but the dictionary must come first: | |||
|
105 | Struct(dict), Struct(k1=v1,k2=v2) or Struct(dict,k1=v1,k2=v2). | |||
|
106 | """ | |||
|
107 | if dict is None: | |||
|
108 | dict = {} | |||
|
109 | if isinstance(dict,Struct): | |||
|
110 | dict = dict.dict() | |||
|
111 | elif dict and type(dict) is not types.DictType: | |||
|
112 | raise TypeError,\ | |||
|
113 | 'Initialize with a dictionary or key=val pairs.' | |||
|
114 | dict.update(kw) | |||
|
115 | # do the updating by hand to guarantee that we go through the | |||
|
116 | # safety-checked __setitem__ | |||
|
117 | for k,v in dict.items(): | |||
|
118 | self[k] = v | |||
|
119 | ||||
|
120 | def __setitem__(self,key,value): | |||
|
121 | """Used when struct[key] = val calls are made.""" | |||
|
122 | if key in Struct.__protected: | |||
|
123 | raise KeyError,'Key '+`key`+' is a protected key of class Struct.' | |||
|
124 | self.__dict__[key] = value | |||
|
125 | ||||
|
126 | def __setattr__(self, key, value): | |||
|
127 | """Used when struct.key = val calls are made.""" | |||
|
128 | self.__setitem__(key,value) | |||
|
129 | ||||
|
130 | def __str__(self): | |||
|
131 | """Gets called by print.""" | |||
|
132 | ||||
|
133 | return 'Struct('+str(self.__dict__)+')' | |||
|
134 | ||||
|
135 | def __repr__(self): | |||
|
136 | """Gets called by repr. | |||
|
137 | ||||
|
138 | A Struct can be recreated with S_new=eval(repr(S_old)).""" | |||
|
139 | return 'Struct('+str(self.__dict__)+')' | |||
|
140 | ||||
|
141 | def __getitem__(self,key): | |||
|
142 | """Allows struct[key] access.""" | |||
|
143 | return self.__dict__[key] | |||
|
144 | ||||
|
145 | def __contains__(self,key): | |||
|
146 | """Allows use of the 'in' operator.""" | |||
|
147 | return self.__dict__.has_key(key) | |||
|
148 | ||||
|
149 | def __iadd__(self,other): | |||
|
150 | """S += S2 is a shorthand for S.merge(S2).""" | |||
|
151 | self.merge(other) | |||
|
152 | return self | |||
|
153 | ||||
|
154 | def __add__(self,other): | |||
|
155 | """S + S2 -> New Struct made form S and S.merge(S2)""" | |||
|
156 | Sout = self.copy() | |||
|
157 | Sout.merge(other) | |||
|
158 | return Sout | |||
|
159 | ||||
|
160 | def __sub__(self,other): | |||
|
161 | """Return S1-S2, where all keys in S2 have been deleted (if present) | |||
|
162 | from S1.""" | |||
|
163 | Sout = self.copy() | |||
|
164 | Sout -= other | |||
|
165 | return Sout | |||
|
166 | ||||
|
167 | def __isub__(self,other): | |||
|
168 | """Do in place S = S - S2, meaning all keys in S2 have been deleted | |||
|
169 | (if present) from S1.""" | |||
|
170 | ||||
|
171 | for k in other.keys(): | |||
|
172 | if self.has_key(k): | |||
|
173 | del self.__dict__[k] | |||
|
174 | ||||
|
175 | def __make_dict(self,__loc_data__,**kw): | |||
|
176 | "Helper function for update and merge. Return a dict from data." | |||
|
177 | ||||
|
178 | if __loc_data__ == None: | |||
|
179 | dict = {} | |||
|
180 | elif type(__loc_data__) is types.DictType: | |||
|
181 | dict = __loc_data__ | |||
|
182 | elif isinstance(__loc_data__,Struct): | |||
|
183 | dict = __loc_data__.__dict__ | |||
|
184 | else: | |||
|
185 | raise TypeError, 'Update with a dict, a Struct or key=val pairs.' | |||
|
186 | if kw: | |||
|
187 | dict.update(kw) | |||
|
188 | return dict | |||
|
189 | ||||
|
190 | def __dict_invert(self,dict): | |||
|
191 | """Helper function for merge. Takes a dictionary whose values are | |||
|
192 | lists and returns a dict. with the elements of each list as keys and | |||
|
193 | the original keys as values.""" | |||
|
194 | ||||
|
195 | outdict = {} | |||
|
196 | for k,lst in dict.items(): | |||
|
197 | if type(lst) is types.StringType: | |||
|
198 | lst = lst.split() | |||
|
199 | for entry in lst: | |||
|
200 | outdict[entry] = k | |||
|
201 | return outdict | |||
|
202 | ||||
|
203 | def clear(self): | |||
|
204 | """Clear all attributes.""" | |||
|
205 | self.__dict__.clear() | |||
|
206 | ||||
|
207 | def copy(self): | |||
|
208 | """Return a (shallow) copy of a Struct.""" | |||
|
209 | return Struct(self.__dict__.copy()) | |||
|
210 | ||||
|
211 | def dict(self): | |||
|
212 | """Return the Struct's dictionary.""" | |||
|
213 | return self.__dict__ | |||
|
214 | ||||
|
215 | def dictcopy(self): | |||
|
216 | """Return a (shallow) copy of the Struct's dictionary.""" | |||
|
217 | return self.__dict__.copy() | |||
|
218 | ||||
|
219 | def popitem(self): | |||
|
220 | """S.popitem() -> (k, v), remove and return some (key, value) pair as | |||
|
221 | a 2-tuple; but raise KeyError if S is empty.""" | |||
|
222 | return self.__dict__.popitem() | |||
|
223 | ||||
|
224 | def update(self,__loc_data__=None,**kw): | |||
|
225 | """Update (merge) with data from another Struct or from a dictionary. | |||
|
226 | Optionally, one or more key=value pairs can be given at the end for | |||
|
227 | direct update.""" | |||
|
228 | ||||
|
229 | # The funny name __loc_data__ is to prevent a common variable name which | |||
|
230 | # could be a fieled of a Struct to collide with this parameter. The problem | |||
|
231 | # would arise if the function is called with a keyword with this same name | |||
|
232 | # that a user means to add as a Struct field. | |||
|
233 | newdict = Struct.__make_dict(self,__loc_data__,**kw) | |||
|
234 | for k,v in newdict.items(): | |||
|
235 | self[k] = v | |||
|
236 | ||||
|
237 | def merge(self,__loc_data__=None,__conflict_solve=None,**kw): | |||
|
238 | """S.merge(data,conflict,k=v1,k=v2,...) -> merge data and k=v into S. | |||
|
239 | ||||
|
240 | This is similar to update(), but much more flexible. First, a dict is | |||
|
241 | made from data+key=value pairs. When merging this dict with the Struct | |||
|
242 | S, the optional dictionary 'conflict' is used to decide what to do. | |||
|
243 | ||||
|
244 | If conflict is not given, the default behavior is to preserve any keys | |||
|
245 | with their current value (the opposite of the update method's | |||
|
246 | behavior). | |||
|
247 | ||||
|
248 | conflict is a dictionary of binary functions which will be used to | |||
|
249 | solve key conflicts. It must have the following structure: | |||
|
250 | ||||
|
251 | conflict == { fn1 : [Skey1,Skey2,...], fn2 : [Skey3], etc } | |||
|
252 | ||||
|
253 | Values must be lists or whitespace separated strings which are | |||
|
254 | automatically converted to lists of strings by calling string.split(). | |||
|
255 | ||||
|
256 | Each key of conflict is a function which defines a policy for | |||
|
257 | resolving conflicts when merging with the input data. Each fn must be | |||
|
258 | a binary function which returns the desired outcome for a key | |||
|
259 | conflict. These functions will be called as fn(old,new). | |||
|
260 | ||||
|
261 | An example is probably in order. Suppose you are merging the struct S | |||
|
262 | with a dict D and the following conflict policy dict: | |||
|
263 | ||||
|
264 | S.merge(D,{fn1:['a','b',4], fn2:'key_c key_d'}) | |||
|
265 | ||||
|
266 | If the key 'a' is found in both S and D, the merge method will call: | |||
|
267 | ||||
|
268 | S['a'] = fn1(S['a'],D['a']) | |||
|
269 | ||||
|
270 | As a convenience, merge() provides five (the most commonly needed) | |||
|
271 | pre-defined policies: preserve, update, add, add_flip and add_s. The | |||
|
272 | easiest explanation is their implementation: | |||
|
273 | ||||
|
274 | preserve = lambda old,new: old | |||
|
275 | update = lambda old,new: new | |||
|
276 | add = lambda old,new: old + new | |||
|
277 | add_flip = lambda old,new: new + old # note change of order! | |||
|
278 | add_s = lambda old,new: old + ' ' + new # only works for strings! | |||
|
279 | ||||
|
280 | You can use those four words (as strings) as keys in conflict instead | |||
|
281 | of defining them as functions, and the merge method will substitute | |||
|
282 | the appropriate functions for you. That is, the call | |||
|
283 | ||||
|
284 | S.merge(D,{'preserve':'a b c','add':[4,5,'d'],my_function:[6]}) | |||
|
285 | ||||
|
286 | will automatically substitute the functions preserve and add for the | |||
|
287 | names 'preserve' and 'add' before making any function calls. | |||
|
288 | ||||
|
289 | For more complicated conflict resolution policies, you still need to | |||
|
290 | construct your own functions. """ | |||
|
291 | ||||
|
292 | data_dict = Struct.__make_dict(self,__loc_data__,**kw) | |||
|
293 | ||||
|
294 | # policies for conflict resolution: two argument functions which return | |||
|
295 | # the value that will go in the new struct | |||
|
296 | preserve = lambda old,new: old | |||
|
297 | update = lambda old,new: new | |||
|
298 | add = lambda old,new: old + new | |||
|
299 | add_flip = lambda old,new: new + old # note change of order! | |||
|
300 | add_s = lambda old,new: old + ' ' + new | |||
|
301 | ||||
|
302 | # default policy is to keep current keys when there's a conflict | |||
|
303 | conflict_solve = list2dict2(self.keys(),default = preserve) | |||
|
304 | ||||
|
305 | # the conflict_solve dictionary is given by the user 'inverted': we | |||
|
306 | # need a name-function mapping, it comes as a function -> names | |||
|
307 | # dict. Make a local copy (b/c we'll make changes), replace user | |||
|
308 | # strings for the three builtin policies and invert it. | |||
|
309 | if __conflict_solve: | |||
|
310 | inv_conflict_solve_user = __conflict_solve.copy() | |||
|
311 | for name, func in [('preserve',preserve), ('update',update), | |||
|
312 | ('add',add), ('add_flip',add_flip), ('add_s',add_s)]: | |||
|
313 | if name in inv_conflict_solve_user.keys(): | |||
|
314 | inv_conflict_solve_user[func] = inv_conflict_solve_user[name] | |||
|
315 | del inv_conflict_solve_user[name] | |||
|
316 | conflict_solve.update(Struct.__dict_invert(self,inv_conflict_solve_user)) | |||
|
317 | #print 'merge. conflict_solve: '; pprint(conflict_solve) # dbg | |||
|
318 | # after Python 2.2, use iterators: for key in data_dict will then work | |||
|
319 | #print '*'*50,'in merger. conflict_solver:'; pprint(conflict_solve) | |||
|
320 | for key in data_dict.keys(): | |||
|
321 | if key not in self: | |||
|
322 | self[key] = data_dict[key] | |||
|
323 | else: | |||
|
324 | self[key] = conflict_solve[key](self[key],data_dict[key]) | |||
|
325 | ||||
|
326 | def has_key(self,key): | |||
|
327 | """Like has_key() dictionary method.""" | |||
|
328 | return self.__dict__.has_key(key) | |||
|
329 | ||||
|
330 | def hasattr(self,key): | |||
|
331 | """hasattr function available as a method. | |||
|
332 | ||||
|
333 | Implemented like has_key, to make sure that all available keys in the | |||
|
334 | internal dictionary of the Struct appear also as attributes (even | |||
|
335 | numeric keys).""" | |||
|
336 | return self.__dict__.has_key(key) | |||
|
337 | ||||
|
338 | def items(self): | |||
|
339 | """Return the items in the Struct's dictionary, in the same format | |||
|
340 | as a call to {}.items().""" | |||
|
341 | return self.__dict__.items() | |||
|
342 | ||||
|
343 | def keys(self): | |||
|
344 | """Return the keys in the Struct's dictionary, in the same format | |||
|
345 | as a call to {}.keys().""" | |||
|
346 | return self.__dict__.keys() | |||
|
347 | ||||
|
348 | def values(self,keys=None): | |||
|
349 | """Return the values in the Struct's dictionary, in the same format | |||
|
350 | as a call to {}.values(). | |||
|
351 | ||||
|
352 | Can be called with an optional argument keys, which must be a list or | |||
|
353 | tuple of keys. In this case it returns only the values corresponding | |||
|
354 | to those keys (allowing a form of 'slicing' for Structs).""" | |||
|
355 | if not keys: | |||
|
356 | return self.__dict__.values() | |||
|
357 | else: | |||
|
358 | ret=[] | |||
|
359 | for k in keys: | |||
|
360 | ret.append(self[k]) | |||
|
361 | return ret | |||
|
362 | ||||
|
363 | def get(self,attr,val=None): | |||
|
364 | """S.get(k[,d]) -> S[k] if S.has_key(k), else d. d defaults to None.""" | |||
|
365 | try: | |||
|
366 | return self[attr] | |||
|
367 | except KeyError: | |||
|
368 | return val | |||
|
369 | ||||
|
370 | def setdefault(self,attr,val=None): | |||
|
371 | """S.setdefault(k[,d]) -> S.get(k,d), also set S[k]=d if not S.has_key(k)""" | |||
|
372 | if not self.has_key(attr): | |||
|
373 | self[attr] = val | |||
|
374 | return self.get(attr,val) | |||
|
375 | # end class Struct | |||
|
376 |
This diff has been collapsed as it changes many lines, (546 lines changed) Show them Hide them | |||||
@@ -0,0 +1,546 | |||||
|
1 | # -*- Mode: Shell-Script -*- Not really, but shows comments correctly | |||
|
2 | # $Id: ipythonrc 596 2005-06-01 17:01:13Z fperez $ | |||
|
3 | ||||
|
4 | #*************************************************************************** | |||
|
5 | # | |||
|
6 | # Configuration file for IPython -- ipythonrc format | |||
|
7 | # | |||
|
8 | # The format of this file is simply one of 'key value' lines. | |||
|
9 | # Lines containing only whitespace at the beginning and then a # are ignored | |||
|
10 | # as comments. But comments can NOT be put on lines with data. | |||
|
11 | ||||
|
12 | # The meaning and use of each key are explained below. | |||
|
13 | ||||
|
14 | #--------------------------------------------------------------------------- | |||
|
15 | # Section: included files | |||
|
16 | ||||
|
17 | # Put one or more *config* files (with the syntax of this file) you want to | |||
|
18 | # include. For keys with a unique value the outermost file has precedence. For | |||
|
19 | # keys with multiple values, they all get assembled into a list which then | |||
|
20 | # gets loaded by IPython. | |||
|
21 | ||||
|
22 | # In this file, all lists of things should simply be space-separated. | |||
|
23 | ||||
|
24 | # This allows you to build hierarchies of files which recursively load | |||
|
25 | # lower-level services. If this is your main ~/.ipython/ipythonrc file, you | |||
|
26 | # should only keep here basic things you always want available. Then you can | |||
|
27 | # include it in every other special-purpose config file you create. | |||
|
28 | include | |||
|
29 | ||||
|
30 | #--------------------------------------------------------------------------- | |||
|
31 | # Section: startup setup | |||
|
32 | ||||
|
33 | # These are mostly things which parallel a command line option of the same | |||
|
34 | # name. | |||
|
35 | ||||
|
36 | # Keys in this section should only appear once. If any key from this section | |||
|
37 | # is encountered more than once, the last value remains, all earlier ones get | |||
|
38 | # discarded. | |||
|
39 | ||||
|
40 | # Automatic calling of callable objects. If set to true, callable objects are | |||
|
41 | # automatically called when invoked at the command line, even if you don't | |||
|
42 | # type parentheses. IPython adds the parentheses for you. For example: | |||
|
43 | ||||
|
44 | #In [1]: str 45 | |||
|
45 | #------> str(45) | |||
|
46 | #Out[1]: '45' | |||
|
47 | ||||
|
48 | # IPython reprints your line with '---->' indicating that it added | |||
|
49 | # parentheses. While this option is very convenient for interactive use, it | |||
|
50 | # may occasionally cause problems with objects which have side-effects if | |||
|
51 | # called unexpectedly. Set it to 0 if you want to disable it. | |||
|
52 | ||||
|
53 | # Note that even with autocall off, you can still use '/' at the start of a | |||
|
54 | # line to treat the first argument on the command line as a function and add | |||
|
55 | # parentheses to it: | |||
|
56 | ||||
|
57 | #In [8]: /str 43 | |||
|
58 | #------> str(43) | |||
|
59 | #Out[8]: '43' | |||
|
60 | ||||
|
61 | autocall 1 | |||
|
62 | ||||
|
63 | # Auto-indent. IPython can recognize lines ending in ':' and indent the next | |||
|
64 | # line, while also un-indenting automatically after 'raise' or 'return'. | |||
|
65 | ||||
|
66 | # This feature uses the readline library, so it will honor your ~/.inputrc | |||
|
67 | # configuration (or whatever file your INPUTRC variable points to). Adding | |||
|
68 | # the following lines to your .inputrc file can make indent/unindenting more | |||
|
69 | # convenient (M-i indents, M-u unindents): | |||
|
70 | ||||
|
71 | # $if Python | |||
|
72 | # "\M-i": " " | |||
|
73 | # "\M-u": "\d\d\d\d" | |||
|
74 | # $endif | |||
|
75 | ||||
|
76 | # The feature is potentially a bit dangerous, because it can cause problems | |||
|
77 | # with pasting of indented code (the pasted code gets re-indented on each | |||
|
78 | # line). But it's a huge time-saver when working interactively. The magic | |||
|
79 | # function @autoindent allows you to toggle it on/off at runtime. | |||
|
80 | ||||
|
81 | autoindent 1 | |||
|
82 | ||||
|
83 | # Auto-magic. This gives you access to all the magic functions without having | |||
|
84 | # to prepend them with an @ sign. If you define a variable with the same name | |||
|
85 | # as a magic function (say who=1), you will need to access the magic function | |||
|
86 | # with @ (@who in this example). However, if later you delete your variable | |||
|
87 | # (del who), you'll recover the automagic calling form. | |||
|
88 | ||||
|
89 | # Considering that many magic functions provide a lot of shell-like | |||
|
90 | # functionality, automagic gives you something close to a full Python+system | |||
|
91 | # shell environment (and you can extend it further if you want). | |||
|
92 | ||||
|
93 | automagic 1 | |||
|
94 | ||||
|
95 | # Size of the output cache. After this many entries are stored, the cache will | |||
|
96 | # get flushed. Depending on the size of your intermediate calculations, you | |||
|
97 | # may have memory problems if you make it too big, since keeping things in the | |||
|
98 | # cache prevents Python from reclaiming the memory for old results. Experiment | |||
|
99 | # with a value that works well for you. | |||
|
100 | ||||
|
101 | # If you choose cache_size 0 IPython will revert to python's regular >>> | |||
|
102 | # unnumbered prompt. You will still have _, __ and ___ for your last three | |||
|
103 | # results, but that will be it. No dynamic _1, _2, etc. will be created. If | |||
|
104 | # you are running on a slow machine or with very limited memory, this may | |||
|
105 | # help. | |||
|
106 | ||||
|
107 | cache_size 1000 | |||
|
108 | ||||
|
109 | # Classic mode: Setting 'classic 1' you lose many of IPython niceties, | |||
|
110 | # but that's your choice! Classic 1 -> same as IPython -classic. | |||
|
111 | # Note that this is _not_ the normal python interpreter, it's simply | |||
|
112 | # IPython emulating most of the classic interpreter's behavior. | |||
|
113 | classic 0 | |||
|
114 | ||||
|
115 | # colors - Coloring option for prompts and traceback printouts. | |||
|
116 | ||||
|
117 | # Currently available schemes: NoColor, Linux, LightBG. | |||
|
118 | ||||
|
119 | # This option allows coloring the prompts and traceback printouts. This | |||
|
120 | # requires a terminal which can properly handle color escape sequences. If you | |||
|
121 | # are having problems with this, use the NoColor scheme (uses no color escapes | |||
|
122 | # at all). | |||
|
123 | ||||
|
124 | # The Linux option works well in linux console type environments: dark | |||
|
125 | # background with light fonts. | |||
|
126 | ||||
|
127 | # LightBG is similar to Linux but swaps dark/light colors to be more readable | |||
|
128 | # in light background terminals. | |||
|
129 | ||||
|
130 | # keep uncommented only the one you want: | |||
|
131 | colors Linux | |||
|
132 | #colors LightBG | |||
|
133 | #colors NoColor | |||
|
134 | ||||
|
135 | ######################## | |||
|
136 | # Note to Windows users | |||
|
137 | # | |||
|
138 | # Color and readline support is avaialble to Windows users via Gary Bishop's | |||
|
139 | # readline library. You can find Gary's tools at | |||
|
140 | # http://sourceforge.net/projects/uncpythontools. | |||
|
141 | # Note that his readline module requires in turn the ctypes library, available | |||
|
142 | # at http://starship.python.net/crew/theller/ctypes. | |||
|
143 | ######################## | |||
|
144 | ||||
|
145 | # color_info: IPython can display information about objects via a set of | |||
|
146 | # functions, and optionally can use colors for this, syntax highlighting | |||
|
147 | # source code and various other elements. This information is passed through a | |||
|
148 | # pager (it defaults to 'less' if $PAGER is not set). | |||
|
149 | ||||
|
150 | # If your pager has problems, try to setting it to properly handle escapes | |||
|
151 | # (see the less manpage for detail), or disable this option. The magic | |||
|
152 | # function @color_info allows you to toggle this interactively for testing. | |||
|
153 | ||||
|
154 | color_info 1 | |||
|
155 | ||||
|
156 | # confirm_exit: set to 1 if you want IPython to confirm when you try to exit | |||
|
157 | # with an EOF (Control-d in Unix, Control-Z/Enter in Windows). Note that using | |||
|
158 | # the magic functions @Exit or @Quit you can force a direct exit, bypassing | |||
|
159 | # any confirmation. | |||
|
160 | ||||
|
161 | confirm_exit 1 | |||
|
162 | ||||
|
163 | # Use deep_reload() as a substitute for reload() by default. deep_reload() is | |||
|
164 | # still available as dreload() and appears as a builtin. | |||
|
165 | ||||
|
166 | deep_reload 0 | |||
|
167 | ||||
|
168 | # Which editor to use with the @edit command. If you leave this at 0, IPython | |||
|
169 | # will honor your EDITOR environment variable. Since this editor is invoked on | |||
|
170 | # the fly by ipython and is meant for editing small code snippets, you may | |||
|
171 | # want to use a small, lightweight editor here. | |||
|
172 | ||||
|
173 | # For Emacs users, setting up your Emacs server properly as described in the | |||
|
174 | # manual is a good idea. An alternative is to use jed, a very light editor | |||
|
175 | # with much of the feel of Emacs (though not as powerful for heavy-duty work). | |||
|
176 | ||||
|
177 | editor 0 | |||
|
178 | ||||
|
179 | # log 1 -> same as ipython -log. This automatically logs to ./ipython.log | |||
|
180 | log 0 | |||
|
181 | ||||
|
182 | # Same as ipython -Logfile YourLogfileName. | |||
|
183 | # Don't use with log 1 (use one or the other) | |||
|
184 | logfile '' | |||
|
185 | ||||
|
186 | # banner 0 -> same as ipython -nobanner | |||
|
187 | banner 1 | |||
|
188 | ||||
|
189 | # messages 0 -> same as ipython -nomessages | |||
|
190 | messages 1 | |||
|
191 | ||||
|
192 | # Automatically call the pdb debugger after every uncaught exception. If you | |||
|
193 | # are used to debugging using pdb, this puts you automatically inside of it | |||
|
194 | # after any call (either in IPython or in code called by it) which triggers an | |||
|
195 | # exception which goes uncaught. | |||
|
196 | pdb 0 | |||
|
197 | ||||
|
198 | # Enable the pprint module for printing. pprint tends to give a more readable | |||
|
199 | # display (than print) for complex nested data structures. | |||
|
200 | pprint 1 | |||
|
201 | ||||
|
202 | # Prompt strings | |||
|
203 | ||||
|
204 | # Most bash-like escapes can be used to customize IPython's prompts, as well as | |||
|
205 | # a few additional ones which are IPython-specific. All valid prompt escapes | |||
|
206 | # are described in detail in the Customization section of the IPython HTML/PDF | |||
|
207 | # manual. | |||
|
208 | ||||
|
209 | # Use \# to represent the current prompt number, and quote them to protect | |||
|
210 | # spaces. | |||
|
211 | prompt_in1 'In [\#]: ' | |||
|
212 | ||||
|
213 | # \D is replaced by as many dots as there are digits in the | |||
|
214 | # current value of \#. | |||
|
215 | prompt_in2 ' .\D.: ' | |||
|
216 | ||||
|
217 | prompt_out 'Out[\#]: ' | |||
|
218 | ||||
|
219 | # Select whether to left-pad the output prompts to match the length of the | |||
|
220 | # input ones. This allows you for example to use a simple '>' as an output | |||
|
221 | # prompt, and yet have the output line up with the input. If set to false, | |||
|
222 | # the output prompts will be unpadded (flush left). | |||
|
223 | prompts_pad_left 1 | |||
|
224 | ||||
|
225 | # quick 1 -> same as ipython -quick | |||
|
226 | quick 0 | |||
|
227 | ||||
|
228 | # Use the readline library (1) or not (0). Most users will want this on, but | |||
|
229 | # if you experience strange problems with line management (mainly when using | |||
|
230 | # IPython inside Emacs buffers) you may try disabling it. Not having it on | |||
|
231 | # prevents you from getting command history with the arrow keys, searching and | |||
|
232 | # name completion using TAB. | |||
|
233 | ||||
|
234 | readline 1 | |||
|
235 | ||||
|
236 | # Screen Length: number of lines of your screen. This is used to control | |||
|
237 | # printing of very long strings. Strings longer than this number of lines will | |||
|
238 | # be paged with the less command instead of directly printed. | |||
|
239 | ||||
|
240 | # The default value for this is 0, which means IPython will auto-detect your | |||
|
241 | # screen size every time it needs to print. If for some reason this isn't | |||
|
242 | # working well (it needs curses support), specify it yourself. Otherwise don't | |||
|
243 | # change the default. | |||
|
244 | ||||
|
245 | screen_length 0 | |||
|
246 | ||||
|
247 | # Prompt separators for input and output. | |||
|
248 | # Use \n for newline explicitly, without quotes. | |||
|
249 | # Use 0 (like at the cmd line) to turn off a given separator. | |||
|
250 | ||||
|
251 | # The structure of prompt printing is: | |||
|
252 | # (SeparateIn)Input.... | |||
|
253 | # (SeparateOut)Output... | |||
|
254 | # (SeparateOut2), # that is, no newline is printed after Out2 | |||
|
255 | # By choosing these you can organize your output any way you want. | |||
|
256 | ||||
|
257 | separate_in \n | |||
|
258 | separate_out 0 | |||
|
259 | separate_out2 0 | |||
|
260 | ||||
|
261 | # 'nosep 1' is a shorthand for '-SeparateIn 0 -SeparateOut 0 -SeparateOut2 0'. | |||
|
262 | # Simply removes all input/output separators, overriding the choices above. | |||
|
263 | nosep 0 | |||
|
264 | ||||
|
265 | # xmode - Exception reporting mode. | |||
|
266 | ||||
|
267 | # Valid modes: Plain, Context and Verbose. | |||
|
268 | ||||
|
269 | # Plain: similar to python's normal traceback printing. | |||
|
270 | ||||
|
271 | # Context: prints 5 lines of context source code around each line in the | |||
|
272 | # traceback. | |||
|
273 | ||||
|
274 | # Verbose: similar to Context, but additionally prints the variables currently | |||
|
275 | # visible where the exception happened (shortening their strings if too | |||
|
276 | # long). This can potentially be very slow, if you happen to have a huge data | |||
|
277 | # structure whose string representation is complex to compute. Your computer | |||
|
278 | # may appear to freeze for a while with cpu usage at 100%. If this occurs, you | |||
|
279 | # can cancel the traceback with Ctrl-C (maybe hitting it more than once). | |||
|
280 | ||||
|
281 | #xmode Plain | |||
|
282 | xmode Context | |||
|
283 | #xmode Verbose | |||
|
284 | ||||
|
285 | # multi_line_specials: if true, allow magics, aliases and shell escapes (via | |||
|
286 | # !cmd) to be used in multi-line input (like for loops). For example, if you | |||
|
287 | # have this active, the following is valid in IPython: | |||
|
288 | # | |||
|
289 | #In [17]: for i in range(3): | |||
|
290 | # ....: mkdir $i | |||
|
291 | # ....: !touch $i/hello | |||
|
292 | # ....: ls -l $i | |||
|
293 | ||||
|
294 | multi_line_specials 1 | |||
|
295 | ||||
|
296 | #--------------------------------------------------------------------------- | |||
|
297 | # Section: Readline configuration (readline is not available for MS-Windows) | |||
|
298 | ||||
|
299 | # This is done via the following options: | |||
|
300 | ||||
|
301 | # (i) readline_parse_and_bind: this option can appear as many times as you | |||
|
302 | # want, each time defining a string to be executed via a | |||
|
303 | # readline.parse_and_bind() command. The syntax for valid commands of this | |||
|
304 | # kind can be found by reading the documentation for the GNU readline library, | |||
|
305 | # as these commands are of the kind which readline accepts in its | |||
|
306 | # configuration file. | |||
|
307 | ||||
|
308 | # The TAB key can be used to complete names at the command line in one of two | |||
|
309 | # ways: 'complete' and 'menu-complete'. The difference is that 'complete' only | |||
|
310 | # completes as much as possible while 'menu-complete' cycles through all | |||
|
311 | # possible completions. Leave the one you prefer uncommented. | |||
|
312 | ||||
|
313 | readline_parse_and_bind tab: complete | |||
|
314 | #readline_parse_and_bind tab: menu-complete | |||
|
315 | ||||
|
316 | # This binds Control-l to printing the list of all possible completions when | |||
|
317 | # there is more than one (what 'complete' does when hitting TAB twice, or at | |||
|
318 | # the first TAB if show-all-if-ambiguous is on) | |||
|
319 | readline_parse_and_bind "\C-l": possible-completions | |||
|
320 | ||||
|
321 | # This forces readline to automatically print the above list when tab | |||
|
322 | # completion is set to 'complete'. You can still get this list manually by | |||
|
323 | # using the key bound to 'possible-completions' (Control-l by default) or by | |||
|
324 | # hitting TAB twice. Turning this on makes the printing happen at the first | |||
|
325 | # TAB. | |||
|
326 | readline_parse_and_bind set show-all-if-ambiguous on | |||
|
327 | ||||
|
328 | # If you have TAB set to complete names, you can rebind any key (Control-o by | |||
|
329 | # default) to insert a true TAB character. | |||
|
330 | readline_parse_and_bind "\C-o": tab-insert | |||
|
331 | ||||
|
332 | # These commands allow you to indent/unindent easily, with the 4-space | |||
|
333 | # convention of the Python coding standards. Since IPython's internal | |||
|
334 | # auto-indent system also uses 4 spaces, you should not change the number of | |||
|
335 | # spaces in the code below. | |||
|
336 | readline_parse_and_bind "\M-i": " " | |||
|
337 | readline_parse_and_bind "\M-o": "\d\d\d\d" | |||
|
338 | readline_parse_and_bind "\M-I": "\d\d\d\d" | |||
|
339 | ||||
|
340 | # Bindings for incremental searches in the history. These searches use the | |||
|
341 | # string typed so far on the command line and search anything in the previous | |||
|
342 | # input history containing them. | |||
|
343 | readline_parse_and_bind "\C-r": reverse-search-history | |||
|
344 | readline_parse_and_bind "\C-s": forward-search-history | |||
|
345 | ||||
|
346 | # Bindings for completing the current line in the history of previous | |||
|
347 | # commands. This allows you to recall any previous command by typing its first | |||
|
348 | # few letters and hitting Control-p, bypassing all intermediate commands which | |||
|
349 | # may be in the history (much faster than hitting up-arrow 50 times!) | |||
|
350 | readline_parse_and_bind "\C-p": history-search-backward | |||
|
351 | readline_parse_and_bind "\C-n": history-search-forward | |||
|
352 | ||||
|
353 | # I also like to have the same functionality on the plain arrow keys. If you'd | |||
|
354 | # rather have the arrows use all the history (and not just match what you've | |||
|
355 | # typed so far), comment out or delete the next two lines. | |||
|
356 | readline_parse_and_bind "\e[A": history-search-backward | |||
|
357 | readline_parse_and_bind "\e[B": history-search-forward | |||
|
358 | ||||
|
359 | # (ii) readline_remove_delims: a string of characters to be removed from the | |||
|
360 | # default word-delimiters list used by readline, so that completions may be | |||
|
361 | # performed on strings which contain them. | |||
|
362 | ||||
|
363 | readline_remove_delims -/~ | |||
|
364 | ||||
|
365 | # (iii) readline_merge_completions: whether to merge the result of all | |||
|
366 | # possible completions or not. If true, IPython will complete filenames, | |||
|
367 | # python names and aliases and return all possible completions. If you set it | |||
|
368 | # to false, each completer is used at a time, and only if it doesn't return | |||
|
369 | # any completions is the next one used. | |||
|
370 | ||||
|
371 | # The default order is: [python_matches, file_matches, alias_matches] | |||
|
372 | ||||
|
373 | readline_merge_completions 1 | |||
|
374 | ||||
|
375 | # (iv) readline_omit__names: normally hitting <tab> after a '.' in a name | |||
|
376 | # will complete all attributes of an object, including all the special methods | |||
|
377 | # whose names start with single or double underscores (like __getitem__ or | |||
|
378 | # __class__). | |||
|
379 | ||||
|
380 | # This variable allows you to control this completion behavior: | |||
|
381 | ||||
|
382 | # readline_omit__names 1 -> completion will omit showing any names starting | |||
|
383 | # with two __, but it will still show names starting with one _. | |||
|
384 | ||||
|
385 | # readline_omit__names 2 -> completion will omit all names beginning with one | |||
|
386 | # _ (which obviously means filtering out the double __ ones). | |||
|
387 | ||||
|
388 | # Even when this option is set, you can still see those names by explicitly | |||
|
389 | # typing a _ after the period and hitting <tab>: 'name._<tab>' will always | |||
|
390 | # complete attribute names starting with '_'. | |||
|
391 | ||||
|
392 | # This option is off by default so that new users see all attributes of any | |||
|
393 | # objects they are dealing with. | |||
|
394 | ||||
|
395 | readline_omit__names 0 | |||
|
396 | ||||
|
397 | #--------------------------------------------------------------------------- | |||
|
398 | # Section: modules to be loaded with 'import ...' | |||
|
399 | ||||
|
400 | # List, separated by spaces, the names of the modules you want to import | |||
|
401 | ||||
|
402 | # Example: | |||
|
403 | # import_mod sys os | |||
|
404 | # will produce internally the statements | |||
|
405 | # import sys | |||
|
406 | # import os | |||
|
407 | ||||
|
408 | # Each import is executed in its own try/except block, so if one module | |||
|
409 | # fails to load the others will still be ok. | |||
|
410 | ||||
|
411 | import_mod | |||
|
412 | ||||
|
413 | #--------------------------------------------------------------------------- | |||
|
414 | # Section: modules to import some functions from: 'from ... import ...' | |||
|
415 | ||||
|
416 | # List, one per line, the modules for which you want only to import some | |||
|
417 | # functions. Give the module name first and then the name of functions to be | |||
|
418 | # imported from that module. | |||
|
419 | ||||
|
420 | # Example: | |||
|
421 | ||||
|
422 | # import_some IPython.genutils timing timings | |||
|
423 | # will produce internally the statement | |||
|
424 | # from IPython.genutils import timing, timings | |||
|
425 | ||||
|
426 | # timing() and timings() are two IPython utilities for timing the execution of | |||
|
427 | # your own functions, which you may find useful. Just commment out the above | |||
|
428 | # line if you want to test them. | |||
|
429 | ||||
|
430 | # If you have more than one modules_some line, each gets its own try/except | |||
|
431 | # block (like modules, see above). | |||
|
432 | ||||
|
433 | import_some | |||
|
434 | ||||
|
435 | #--------------------------------------------------------------------------- | |||
|
436 | # Section: modules to import all from : 'from ... import *' | |||
|
437 | ||||
|
438 | # List (same syntax as import_mod above) those modules for which you want to | |||
|
439 | # import all functions. Remember, this is a potentially dangerous thing to do, | |||
|
440 | # since it is very easy to overwrite names of things you need. Use with | |||
|
441 | # caution. | |||
|
442 | ||||
|
443 | # Example: | |||
|
444 | # import_all sys os | |||
|
445 | # will produce internally the statements | |||
|
446 | # from sys import * | |||
|
447 | # from os import * | |||
|
448 | ||||
|
449 | # As before, each will be called in a separate try/except block. | |||
|
450 | ||||
|
451 | import_all | |||
|
452 | ||||
|
453 | #--------------------------------------------------------------------------- | |||
|
454 | # Section: Python code to execute. | |||
|
455 | ||||
|
456 | # Put here code to be explicitly executed (keep it simple!) | |||
|
457 | # Put one line of python code per line. All whitespace is removed (this is a | |||
|
458 | # feature, not a bug), so don't get fancy building loops here. | |||
|
459 | # This is just for quick convenient creation of things you want available. | |||
|
460 | ||||
|
461 | # Example: | |||
|
462 | # execute x = 1 | |||
|
463 | # execute print 'hello world'; y = z = 'a' | |||
|
464 | # will produce internally | |||
|
465 | # x = 1 | |||
|
466 | # print 'hello world'; y = z = 'a' | |||
|
467 | # and each *line* (not each statement, we don't do python syntax parsing) is | |||
|
468 | # executed in its own try/except block. | |||
|
469 | ||||
|
470 | execute | |||
|
471 | ||||
|
472 | # Note for the adventurous: you can use this to define your own names for the | |||
|
473 | # magic functions, by playing some namespace tricks: | |||
|
474 | ||||
|
475 | # execute __IPYTHON__.magic_pf = __IPYTHON__.magic_profile | |||
|
476 | ||||
|
477 | # defines @pf as a new name for @profile. | |||
|
478 | ||||
|
479 | #--------------------------------------------------------------------------- | |||
|
480 | # Section: Pyhton files to load and execute. | |||
|
481 | ||||
|
482 | # Put here the full names of files you want executed with execfile(file). If | |||
|
483 | # you want complicated initialization, just write whatever you want in a | |||
|
484 | # regular python file and load it from here. | |||
|
485 | ||||
|
486 | # Filenames defined here (which *must* include the extension) are searched for | |||
|
487 | # through all of sys.path. Since IPython adds your .ipython directory to | |||
|
488 | # sys.path, they can also be placed in your .ipython dir and will be | |||
|
489 | # found. Otherwise (if you want to execute things not in .ipyton nor in | |||
|
490 | # sys.path) give a full path (you can use ~, it gets expanded) | |||
|
491 | ||||
|
492 | # Example: | |||
|
493 | # execfile file1.py ~/file2.py | |||
|
494 | # will generate | |||
|
495 | # execfile('file1.py') | |||
|
496 | # execfile('_path_to_your_home/file2.py') | |||
|
497 | ||||
|
498 | # As before, each file gets its own try/except block. | |||
|
499 | ||||
|
500 | execfile | |||
|
501 | ||||
|
502 | # If you are feeling adventurous, you can even add functionality to IPython | |||
|
503 | # through here. IPython works through a global variable called __ip which | |||
|
504 | # exists at the time when these files are read. If you know what you are doing | |||
|
505 | # (read the source) you can add functions to __ip in files loaded here. | |||
|
506 | ||||
|
507 | # The file example-magic.py contains a simple but correct example. Try it: | |||
|
508 | ||||
|
509 | # execfile example-magic.py | |||
|
510 | ||||
|
511 | # Look at the examples in IPython/iplib.py for more details on how these magic | |||
|
512 | # functions need to process their arguments. | |||
|
513 | ||||
|
514 | #--------------------------------------------------------------------------- | |||
|
515 | # Section: aliases for system shell commands | |||
|
516 | ||||
|
517 | # Here you can define your own names for system commands. The syntax is | |||
|
518 | # similar to that of the builtin @alias function: | |||
|
519 | ||||
|
520 | # alias alias_name command_string | |||
|
521 | ||||
|
522 | # The resulting aliases are auto-generated magic functions (hence usable as | |||
|
523 | # @alias_name) | |||
|
524 | ||||
|
525 | # For example: | |||
|
526 | ||||
|
527 | # alias myls ls -la | |||
|
528 | ||||
|
529 | # will define 'myls' as an alias for executing the system command 'ls -la'. | |||
|
530 | # This allows you to customize IPython's environment to have the same aliases | |||
|
531 | # you are accustomed to from your own shell. | |||
|
532 | ||||
|
533 | # You can also define aliases with parameters using %s specifiers (one per | |||
|
534 | # parameter): | |||
|
535 | ||||
|
536 | # alias parts echo first %s second %s | |||
|
537 | ||||
|
538 | # will give you in IPython: | |||
|
539 | # >>> @parts A B | |||
|
540 | # first A second B | |||
|
541 | ||||
|
542 | # Use one 'alias' statement per alias you wish to define. | |||
|
543 | ||||
|
544 | # alias | |||
|
545 | ||||
|
546 | #************************* end of file <ipythonrc> ************************ |
@@ -0,0 +1,36 | |||||
|
1 | # -*- Mode: Shell-Script -*- Not really, but shows comments correctly | |||
|
2 | #*************************************************************************** | |||
|
3 | # | |||
|
4 | # Configuration file for ipython -- ipythonrc format | |||
|
5 | # | |||
|
6 | # The format of this file is one of 'key value' lines. | |||
|
7 | # Lines containing only whitespace at the beginning and then a # are ignored | |||
|
8 | # as comments. But comments can NOT be put on lines with data. | |||
|
9 | #*************************************************************************** | |||
|
10 | ||||
|
11 | # This is an example of a 'profile' file which includes a base file and adds | |||
|
12 | # some customizaton for a particular purpose. | |||
|
13 | ||||
|
14 | # If this file is found in the user's ~/.ipython directory as ipythonrc-math, | |||
|
15 | # it can be loaded by calling passing the '-profile math' (or '-p math') | |||
|
16 | # option to IPython. | |||
|
17 | ||||
|
18 | # This example is a light customization to have ipython have basic math functions | |||
|
19 | # readily available, effectively making the python prompt a very capable scientific | |||
|
20 | # calculator | |||
|
21 | ||||
|
22 | # include base config and only add some extras | |||
|
23 | include ipythonrc | |||
|
24 | ||||
|
25 | # load the complex math functions but keep them in a separate namespace | |||
|
26 | import_mod cmath | |||
|
27 | ||||
|
28 | # from ... import * | |||
|
29 | # load the real math functions in the global namespace for convenience | |||
|
30 | import_all math | |||
|
31 | ||||
|
32 | # from ... import ... | |||
|
33 | import_some | |||
|
34 | ||||
|
35 | # code to execute | |||
|
36 | execute print "*** math functions available globally, cmath as a module" |
@@ -0,0 +1,57 | |||||
|
1 | # -*- Mode: Shell-Script -*- Not really, but shows comments correctly | |||
|
2 | #*************************************************************************** | |||
|
3 | # | |||
|
4 | # Configuration file for ipython -- ipythonrc format | |||
|
5 | # | |||
|
6 | # The format of this file is one of 'key value' lines. | |||
|
7 | # Lines containing only whitespace at the beginning and then a # are ignored | |||
|
8 | # as comments. But comments can NOT be put on lines with data. | |||
|
9 | #*************************************************************************** | |||
|
10 | ||||
|
11 | # This is an example of a 'profile' file which includes a base file and adds | |||
|
12 | # some customizaton for a particular purpose. | |||
|
13 | ||||
|
14 | # If this file is found in the user's ~/.ipython directory as | |||
|
15 | # ipythonrc-numeric, it can be loaded by calling passing the '-profile | |||
|
16 | # numeric' (or '-p numeric') option to IPython. | |||
|
17 | ||||
|
18 | # A simple alias numpy -> 'ipython -p numeric' makes life very convenient. | |||
|
19 | ||||
|
20 | # This example is meant to load several modules to turn IPython into a very | |||
|
21 | # capable environment for high-end numerical work, similar to IDL or MatLab | |||
|
22 | # but with the beauty and flexibility of the Python language. | |||
|
23 | ||||
|
24 | # Load the user's basic configuration | |||
|
25 | include ipythonrc | |||
|
26 | ||||
|
27 | # import ... | |||
|
28 | ||||
|
29 | # Load Numeric by itself so that 'help Numeric' works | |||
|
30 | import_mod Numeric | |||
|
31 | ||||
|
32 | # from ... import * | |||
|
33 | # GnuplotRuntime loads Gnuplot and adds enhancements for use in IPython | |||
|
34 | import_all Numeric IPython.numutils IPython.GnuplotInteractive | |||
|
35 | ||||
|
36 | # a simple line at zero, often useful for an x-axis | |||
|
37 | execute xaxis=gpfunc('0',title='',with='lines lt -1') | |||
|
38 | ||||
|
39 | # Below are optional things off by default. Uncomment them if desired. | |||
|
40 | ||||
|
41 | # MA (MaskedArray) modifies the Numeric printing mechanism so that huge arrays | |||
|
42 | # are only summarized and not printed (which may freeze the machine for a | |||
|
43 | # _long_ time). | |||
|
44 | ||||
|
45 | #import_mod MA | |||
|
46 | ||||
|
47 | ||||
|
48 | # gracePlot is a Python interface to the plotting package Grace. | |||
|
49 | # For more details go to: http://www.idyll.org/~n8gray/code/index.html | |||
|
50 | # Uncomment lines below if you have grace and its python support code | |||
|
51 | ||||
|
52 | #import_mod gracePlot | |||
|
53 | #execute grace = gracePlot.gracePlot # alias to make gracePlot instances | |||
|
54 | #execute print '*** grace is an alias for gracePlot.gracePlot' | |||
|
55 | ||||
|
56 | # Files to execute | |||
|
57 | execfile |
@@ -0,0 +1,43 | |||||
|
1 | # -*- Mode: Shell-Script -*- Not really, but shows comments correctly | |||
|
2 | #*************************************************************************** | |||
|
3 | # | |||
|
4 | # Configuration file for ipython -- ipythonrc format | |||
|
5 | # | |||
|
6 | # The format of this file is one of 'key value' lines. | |||
|
7 | # Lines containing only whitespace at the beginning and then a # are ignored | |||
|
8 | # as comments. But comments can NOT be put on lines with data. | |||
|
9 | #*************************************************************************** | |||
|
10 | ||||
|
11 | # If this file is found in the user's ~/.ipython directory as | |||
|
12 | # ipythonrc-physics, it can be loaded by calling passing the '-profile | |||
|
13 | # physics' (or '-p physics') option to IPython. | |||
|
14 | ||||
|
15 | # This profile loads modules useful for doing interactive calculations with | |||
|
16 | # physical quantities (with units). It relies on modules from Konrad Hinsen's | |||
|
17 | # ScientificPython (http://starship.python.net/crew/hinsen/) | |||
|
18 | ||||
|
19 | # First load basic user configuration | |||
|
20 | include ipythonrc | |||
|
21 | ||||
|
22 | # import ... | |||
|
23 | # Module with alternate input syntax for PhysicalQuantity objects. | |||
|
24 | import_mod IPython.Extensions.PhysicalQInput | |||
|
25 | ||||
|
26 | # from ... import * | |||
|
27 | # math CANNOT be imported after PhysicalQInteractive. It will override the | |||
|
28 | # functions defined there. | |||
|
29 | import_all math IPython.Extensions.PhysicalQInteractive | |||
|
30 | ||||
|
31 | # from ... import ... | |||
|
32 | import_some | |||
|
33 | ||||
|
34 | # code | |||
|
35 | execute q = PhysicalQuantityInteractive | |||
|
36 | execute g = PhysicalQuantityInteractive('9.8 m/s**2') | |||
|
37 | ececute rad = pi/180. | |||
|
38 | execute print '*** q is an alias for PhysicalQuantityInteractive' | |||
|
39 | execute print '*** g = 9.8 m/s^2 has been defined' | |||
|
40 | execute print '*** rad = pi/180 has been defined' | |||
|
41 | ||||
|
42 | # Files to execute | |||
|
43 | execfile |
@@ -0,0 +1,94 | |||||
|
1 | # -*- Mode: Shell-Script -*- Not really, but shows comments correctly | |||
|
2 | #*************************************************************************** | |||
|
3 | # Configuration file for ipython -- ipythonrc format | |||
|
4 | # | |||
|
5 | # The format of this file is one of 'key value' lines. | |||
|
6 | # Lines containing only whitespace at the beginning and then a # are ignored | |||
|
7 | # as comments. But comments can NOT be put on lines with data. | |||
|
8 | #*************************************************************************** | |||
|
9 | ||||
|
10 | # If this file is found in the user's ~/.ipython directory as ipythonrc-pysh, | |||
|
11 | # it can be loaded by calling passing the '-profile pysh' (or '-p pysh') | |||
|
12 | # option to IPython. | |||
|
13 | ||||
|
14 | # This profile turns IPython into a lightweight system shell with python | |||
|
15 | # syntax. | |||
|
16 | ||||
|
17 | # We only set a few options here, the rest is done in the companion pysh.py | |||
|
18 | # file. In the future _all_ of IPython's configuration will be done via | |||
|
19 | # proper python code. | |||
|
20 | ||||
|
21 | ############################################################################ | |||
|
22 | # First load common user configuration | |||
|
23 | include ipythonrc | |||
|
24 | ||||
|
25 | ############################################################################ | |||
|
26 | # Load all the actual syntax extensions for shell-like operation, which live | |||
|
27 | # in the InterpreterExec standard extension. | |||
|
28 | import_all IPython.Extensions.InterpreterExec | |||
|
29 | ||||
|
30 | ############################################################################ | |||
|
31 | # PROMPTS | |||
|
32 | # | |||
|
33 | # Configure prompt for more shell-like usage. | |||
|
34 | ||||
|
35 | # Most bash-like escapes can be used to customize IPython's prompts, as well as | |||
|
36 | # a few additional ones which are IPython-specific. All valid prompt escapes | |||
|
37 | # are described in detail in the Customization section of the IPython HTML/PDF | |||
|
38 | # manual. | |||
|
39 | ||||
|
40 | prompt_in1 '\C_LightGreen\u@\h\C_LightBlue[\C_LightCyan\Y1\C_LightBlue]\C_Green|\#> ' | |||
|
41 | prompt_in2 '\C_Green|\C_LightGreen\D\C_Green> ' | |||
|
42 | prompt_out '<\#> ' | |||
|
43 | ||||
|
44 | # Here's a more complex prompt, showing the hostname and more path depth (\Y3) | |||
|
45 | #prompt_in1 '\C_LightRed\u\C_Blue@\C_Red\h\C_LightBlue[\C_LightCyan\Y3\C_LightBlue]\C_LightGreen\#> ' | |||
|
46 | ||||
|
47 | # Select whether to left-pad the output prompts to match the length of the | |||
|
48 | # input ones. This allows you for example to use a simple '>' as an output | |||
|
49 | # prompt, and yet have the output line up with the input. If set to false, | |||
|
50 | # the output prompts will be unpadded (flush left). | |||
|
51 | prompts_pad_left 1 | |||
|
52 | ||||
|
53 | ||||
|
54 | # Remove all blank lines in between prompts, like a normal shell. | |||
|
55 | separate_in 0 | |||
|
56 | separate_out 0 | |||
|
57 | separate_out2 0 | |||
|
58 | ||||
|
59 | # Allow special syntax (!, magics and aliases) in multiline input | |||
|
60 | multi_line_specials 1 | |||
|
61 | ||||
|
62 | ############################################################################ | |||
|
63 | # ALIASES | |||
|
64 | ||||
|
65 | # Declare some common aliases. Type alias? at an ipython prompt for details on | |||
|
66 | # the syntax, use @unalias to delete existing aliases. | |||
|
67 | ||||
|
68 | # Don't go too crazy here, the file pysh.py called below runs @rehash, which | |||
|
69 | # loads ALL of your $PATH as aliases (except for Python keywords and | |||
|
70 | # builtins). | |||
|
71 | ||||
|
72 | # Some examples: | |||
|
73 | ||||
|
74 | # A simple alias without arguments | |||
|
75 | #alias cl clear | |||
|
76 | ||||
|
77 | # An alias which expands the full line before the end of the alias. This | |||
|
78 | # lists only directories: | |||
|
79 | #alias ldir pwd;ls -oF --color %l | grep /$ | |||
|
80 | ||||
|
81 | # An alias with two positional arguments: | |||
|
82 | #alias parts echo 'First <%s> Second <%s>' | |||
|
83 | ||||
|
84 | # In use these two aliases give (note that ldir is already built into IPython | |||
|
85 | # for Unix): | |||
|
86 | ||||
|
87 | #fperez[IPython]16> ldir | |||
|
88 | #/usr/local/home/fperez/ipython/ipython/IPython | |||
|
89 | #drwxr-xr-x 2 fperez 4096 Jun 21 01:01 CVS/ | |||
|
90 | #drwxr-xr-x 3 fperez 4096 Jun 21 01:10 Extensions/ | |||
|
91 | #drwxr-xr-x 3 fperez 4096 Jun 21 01:27 UserConfig/ | |||
|
92 | ||||
|
93 | #fperez[IPython]17> parts Hello world and goodbye | |||
|
94 | #First <Hello> Second <world> and goodbye |
@@ -0,0 +1,43 | |||||
|
1 | # -*- Mode: Shell-Script -*- Not really, but shows comments correctly | |||
|
2 | #*************************************************************************** | |||
|
3 | # | |||
|
4 | # Configuration file for ipython -- ipythonrc format | |||
|
5 | # | |||
|
6 | # The format of this file is one of 'key value' lines. | |||
|
7 | # Lines containing only whitespace at the beginning and then a # are ignored | |||
|
8 | # as comments. But comments can NOT be put on lines with data. | |||
|
9 | #*************************************************************************** | |||
|
10 | ||||
|
11 | # This is an example of a 'profile' file which includes a base file and adds | |||
|
12 | # some customizaton for a particular purpose. | |||
|
13 | ||||
|
14 | # If this file is found in the user's ~/.ipython directory as ipythonrc-scipy, | |||
|
15 | # it can be loaded by calling passing the '-profile scipy' (or '-p scipy') | |||
|
16 | # option to IPython. | |||
|
17 | ||||
|
18 | # This example is meant to load several modules to turn ipython into a very | |||
|
19 | # capable environment for high-end numerical work, similar to IDL or MatLab | |||
|
20 | # but with the beauty of the Python language. | |||
|
21 | ||||
|
22 | # load our basic configuration with generic options | |||
|
23 | include ipythonrc | |||
|
24 | ||||
|
25 | # import ... | |||
|
26 | # Load SciPy by itself so that 'help scipy' works | |||
|
27 | import_mod scipy | |||
|
28 | ||||
|
29 | # from ... import ... | |||
|
30 | import_some | |||
|
31 | ||||
|
32 | # Now we load all of SciPy | |||
|
33 | # from ... import * | |||
|
34 | import_all scipy IPython.numutils | |||
|
35 | ||||
|
36 | # code | |||
|
37 | execute print 'Welcome to the SciPy Scientific Computing Environment.' | |||
|
38 | execute scipy.alter_numeric() | |||
|
39 | ||||
|
40 | # File with alternate printer system for Numeric Arrays. | |||
|
41 | # Files in the 'Extensions' directory will be found by IPython automatically | |||
|
42 | # (otherwise give the explicit path): | |||
|
43 | execfile Extensions/numeric_formats.py |
@@ -0,0 +1,37 | |||||
|
1 | # -*- Mode: Shell-Script -*- Not really, but shows comments correctly | |||
|
2 | #*************************************************************************** | |||
|
3 | # | |||
|
4 | # Configuration file for ipython -- ipythonrc format | |||
|
5 | # | |||
|
6 | # The format of this file is one of 'key value' lines. | |||
|
7 | # Lines containing only whitespace at the beginning and then a # are ignored | |||
|
8 | # as comments. But comments can NOT be put on lines with data. | |||
|
9 | #*************************************************************************** | |||
|
10 | ||||
|
11 | # If this file is found in the user's ~/.ipython directory as | |||
|
12 | # ipythonrc-tutorial, it can be loaded by calling passing the '-profile | |||
|
13 | # tutorial' (or '-p tutorial') option to IPython. | |||
|
14 | ||||
|
15 | # This profile loads a special input line filter to allow typing lines which | |||
|
16 | # begin with '>>> ' or '... '. These two strings, if present at the start of | |||
|
17 | # the input line, are stripped. This allows for direct pasting of code from | |||
|
18 | # examples such as those available in the standard Python tutorial. | |||
|
19 | ||||
|
20 | # First load basic user configuration | |||
|
21 | include ipythonrc | |||
|
22 | ||||
|
23 | # import ... | |||
|
24 | # Module with alternate input syntax for pasting python input | |||
|
25 | import_mod IPython.Extensions.InterpreterPasteInput | |||
|
26 | ||||
|
27 | # from ... import * | |||
|
28 | import_all | |||
|
29 | ||||
|
30 | # from ... import ... | |||
|
31 | import_some | |||
|
32 | ||||
|
33 | # code | |||
|
34 | execute | |||
|
35 | ||||
|
36 | # Files to execute | |||
|
37 | execfile |
@@ -0,0 +1,63 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | IPython -- An enhanced Interactive Python | |||
|
4 | ||||
|
5 | One of Python's nicest features is its interactive interpreter. This allows | |||
|
6 | very fast testing of ideas without the overhead of creating test files as is | |||
|
7 | typical in most programming languages. However, the interpreter supplied with | |||
|
8 | the standard Python distribution is fairly primitive (and IDLE isn't really | |||
|
9 | much better). | |||
|
10 | ||||
|
11 | IPython tries to: | |||
|
12 | ||||
|
13 | i - provide an efficient environment for interactive work in Python | |||
|
14 | programming. It tries to address what we see as shortcomings of the standard | |||
|
15 | Python prompt, and adds many features to make interactive work much more | |||
|
16 | efficient. | |||
|
17 | ||||
|
18 | ii - offer a flexible framework so that it can be used as the base | |||
|
19 | environment for other projects and problems where Python can be the | |||
|
20 | underlying language. Specifically scientific environments like Mathematica, | |||
|
21 | IDL and Mathcad inspired its design, but similar ideas can be useful in many | |||
|
22 | fields. Python is a fabulous language for implementing this kind of system | |||
|
23 | (due to its dynamic and introspective features), and with suitable libraries | |||
|
24 | entire systems could be built leveraging Python's power. | |||
|
25 | ||||
|
26 | iii - serve as an embeddable, ready to go interpreter for your own programs. | |||
|
27 | ||||
|
28 | IPython requires Python 2.2 or newer. | |||
|
29 | ||||
|
30 | $Id: __init__.py 530 2005-03-02 07:11:15Z fperez $""" | |||
|
31 | ||||
|
32 | #***************************************************************************** | |||
|
33 | # Copyright (C) 2001-2004 Fernando Perez. <fperez@colorado.edu> | |||
|
34 | # | |||
|
35 | # Distributed under the terms of the BSD License. The full license is in | |||
|
36 | # the file COPYING, distributed as part of this software. | |||
|
37 | #***************************************************************************** | |||
|
38 | ||||
|
39 | # Enforce proper version requirements | |||
|
40 | import sys | |||
|
41 | if sys.version[0:3] < '2.2': | |||
|
42 | raise ImportError, 'Python Version 2.2 or above is required.' | |||
|
43 | ||||
|
44 | # Define what gets imported with a 'from IPython import *' | |||
|
45 | __all__ = ['deep_reload','genutils','ultraTB','DPyGetOpt','Itpl','hooks', | |||
|
46 | 'ConfigLoader','OutputTrap','Release','Struct','Shell'] | |||
|
47 | ||||
|
48 | # Load __all__ in IPython namespace so that a simple 'import IPython' gives | |||
|
49 | # access to them via IPython.<name> | |||
|
50 | glob,loc = globals(),locals() | |||
|
51 | for name in __all__: | |||
|
52 | __import__(name,glob,loc,[]) | |||
|
53 | ||||
|
54 | # Release data | |||
|
55 | from IPython import Release # do it explicitly so pydoc can see it - pydoc bug | |||
|
56 | __author__ = '%s <%s>\n%s <%s>\n%s <%s>' % \ | |||
|
57 | ( Release.authors['Fernando'] + Release.authors['Janko'] + \ | |||
|
58 | Release.authors['Nathan'] ) | |||
|
59 | __license__ = Release.license | |||
|
60 | __version__ = Release.version | |||
|
61 | ||||
|
62 | # Namespace cleanup | |||
|
63 | del name,glob,loc |
This diff has been collapsed as it changes many lines, (504 lines changed) Show them Hide them | |||||
@@ -0,0 +1,504 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Manage background (threaded) jobs conveniently from an interactive shell. | |||
|
3 | ||||
|
4 | This module provides a BackgroundJobManager class. This is the main class | |||
|
5 | meant for public usage, it implements an object which can create and manage | |||
|
6 | new background jobs. | |||
|
7 | ||||
|
8 | It also provides the actual job classes managed by these BackgroundJobManager | |||
|
9 | objects, see their docstrings below. | |||
|
10 | ||||
|
11 | ||||
|
12 | This system was inspired by discussions with B. Granger and the | |||
|
13 | BackgroundCommand class described in the book Python Scripting for | |||
|
14 | Computational Science, by H. P. Langtangen: | |||
|
15 | ||||
|
16 | http://folk.uio.no/hpl/scripting | |||
|
17 | ||||
|
18 | (although ultimately no code from this text was used, as IPython's system is a | |||
|
19 | separate implementation). | |||
|
20 | ||||
|
21 | $Id: background_jobs.py 515 2005-02-15 07:41:41Z fperez $ | |||
|
22 | """ | |||
|
23 | ||||
|
24 | #***************************************************************************** | |||
|
25 | # Copyright (C) 2005 Fernando Perez <fperez@colorado.edu> | |||
|
26 | # | |||
|
27 | # Distributed under the terms of the BSD License. The full license is in | |||
|
28 | # the file COPYING, distributed as part of this software. | |||
|
29 | #***************************************************************************** | |||
|
30 | ||||
|
31 | from IPython import Release | |||
|
32 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
33 | __license__ = Release.license | |||
|
34 | ||||
|
35 | # Code begins | |||
|
36 | import threading,sys | |||
|
37 | ||||
|
38 | from IPython.ultraTB import AutoFormattedTB | |||
|
39 | from IPython.genutils import warn,error | |||
|
40 | ||||
|
41 | # declares Python 2.2 compatibility symbols: | |||
|
42 | try: | |||
|
43 | basestring | |||
|
44 | except NameError: | |||
|
45 | import types | |||
|
46 | basestring = (types.StringType, types.UnicodeType) | |||
|
47 | True = 1==1 | |||
|
48 | False = 1==0 | |||
|
49 | ||||
|
50 | class BackgroundJobManager: | |||
|
51 | """Class to manage a pool of backgrounded threaded jobs. | |||
|
52 | ||||
|
53 | Below, we assume that 'jobs' is a BackgroundJobManager instance. | |||
|
54 | ||||
|
55 | Usage summary (see the method docstrings for details): | |||
|
56 | ||||
|
57 | jobs.new(...) -> start a new job | |||
|
58 | ||||
|
59 | jobs() or jobs.status() -> print status summary of all jobs | |||
|
60 | ||||
|
61 | jobs[N] -> returns job number N. | |||
|
62 | ||||
|
63 | foo = jobs[N].result -> assign to variable foo the result of job N | |||
|
64 | ||||
|
65 | jobs[N].traceback() -> print the traceback of dead job N | |||
|
66 | ||||
|
67 | jobs.remove(N) -> remove (finished) job N | |||
|
68 | ||||
|
69 | jobs.flush_finished() -> remove all finished jobs | |||
|
70 | ||||
|
71 | As a convenience feature, BackgroundJobManager instances provide the | |||
|
72 | utility result and traceback methods which retrieve the corresponding | |||
|
73 | information from the jobs list: | |||
|
74 | ||||
|
75 | jobs.result(N) <--> jobs[N].result | |||
|
76 | jobs.traceback(N) <--> jobs[N].traceback() | |||
|
77 | ||||
|
78 | While this appears minor, it allows you to use tab completion | |||
|
79 | interactively on the job manager instance. | |||
|
80 | ||||
|
81 | In interactive mode, IPython provides the magic fuction %bg for quick | |||
|
82 | creation of backgrounded expression-based jobs. Type bg? for details.""" | |||
|
83 | ||||
|
84 | def __init__(self): | |||
|
85 | # Lists for job management | |||
|
86 | self.jobs_run = [] | |||
|
87 | self.jobs_comp = [] | |||
|
88 | self.jobs_dead = [] | |||
|
89 | # A dict of all jobs, so users can easily access any of them | |||
|
90 | self.jobs_all = {} | |||
|
91 | # For reporting | |||
|
92 | self._comp_report = [] | |||
|
93 | self._dead_report = [] | |||
|
94 | # Store status codes locally for fast lookups | |||
|
95 | self._s_created = BackgroundJobBase.stat_created_c | |||
|
96 | self._s_running = BackgroundJobBase.stat_running_c | |||
|
97 | self._s_completed = BackgroundJobBase.stat_completed_c | |||
|
98 | self._s_dead = BackgroundJobBase.stat_dead_c | |||
|
99 | ||||
|
100 | def new(self,func_or_exp,*args,**kwargs): | |||
|
101 | """Add a new background job and start it in a separate thread. | |||
|
102 | ||||
|
103 | There are two types of jobs which can be created: | |||
|
104 | ||||
|
105 | 1. Jobs based on expressions which can be passed to an eval() call. | |||
|
106 | The expression must be given as a string. For example: | |||
|
107 | ||||
|
108 | job_manager.new('myfunc(x,y,z=1)'[,glob[,loc]]) | |||
|
109 | ||||
|
110 | The given expression is passed to eval(), along with the optional | |||
|
111 | global/local dicts provided. If no dicts are given, they are | |||
|
112 | extracted automatically from the caller's frame. | |||
|
113 | ||||
|
114 | A Python statement is NOT a valid eval() expression. Basically, you | |||
|
115 | can only use as an eval() argument something which can go on the right | |||
|
116 | of an '=' sign and be assigned to a variable. | |||
|
117 | ||||
|
118 | For example,"print 'hello'" is not valid, but '2+3' is. | |||
|
119 | ||||
|
120 | 2. Jobs given a function object, optionally passing additional | |||
|
121 | positional arguments: | |||
|
122 | ||||
|
123 | job_manager.new(myfunc,x,y) | |||
|
124 | ||||
|
125 | The function is called with the given arguments. | |||
|
126 | ||||
|
127 | If you need to pass keyword arguments to your function, you must | |||
|
128 | supply them as a dict named kw: | |||
|
129 | ||||
|
130 | job_manager.new(myfunc,x,y,kw=dict(z=1)) | |||
|
131 | ||||
|
132 | The reason for this assymmetry is that the new() method needs to | |||
|
133 | maintain access to its own keywords, and this prevents name collisions | |||
|
134 | between arguments to new() and arguments to your own functions. | |||
|
135 | ||||
|
136 | In both cases, the result is stored in the job.result field of the | |||
|
137 | background job object. | |||
|
138 | ||||
|
139 | ||||
|
140 | Notes and caveats: | |||
|
141 | ||||
|
142 | 1. All threads running share the same standard output. Thus, if your | |||
|
143 | background jobs generate output, it will come out on top of whatever | |||
|
144 | you are currently writing. For this reason, background jobs are best | |||
|
145 | used with silent functions which simply return their output. | |||
|
146 | ||||
|
147 | 2. Threads also all work within the same global namespace, and this | |||
|
148 | system does not lock interactive variables. So if you send job to the | |||
|
149 | background which operates on a mutable object for a long time, and | |||
|
150 | start modifying that same mutable object interactively (or in another | |||
|
151 | backgrounded job), all sorts of bizarre behaviour will occur. | |||
|
152 | ||||
|
153 | 3. If a background job is spending a lot of time inside a C extension | |||
|
154 | module which does not release the Python Global Interpreter Lock | |||
|
155 | (GIL), this will block the IPython prompt. This is simply because the | |||
|
156 | Python interpreter can only switch between threads at Python | |||
|
157 | bytecodes. While the execution is inside C code, the interpreter must | |||
|
158 | simply wait unless the extension module releases the GIL. | |||
|
159 | ||||
|
160 | 4. There is no way, due to limitations in the Python threads library, | |||
|
161 | to kill a thread once it has started.""" | |||
|
162 | ||||
|
163 | if callable(func_or_exp): | |||
|
164 | kw = kwargs.get('kw',{}) | |||
|
165 | job = BackgroundJobFunc(func_or_exp,*args,**kw) | |||
|
166 | elif isinstance(func_or_exp,basestring): | |||
|
167 | if not args: | |||
|
168 | frame = sys._getframe(1) | |||
|
169 | glob, loc = frame.f_globals, frame.f_locals | |||
|
170 | elif len(args)==1: | |||
|
171 | glob = loc = args[0] | |||
|
172 | elif len(args)==2: | |||
|
173 | glob,loc = args | |||
|
174 | else: | |||
|
175 | raise ValueError,\ | |||
|
176 | 'Expression jobs take at most 2 args (globals,locals)' | |||
|
177 | job = BackgroundJobExpr(func_or_exp,glob,loc) | |||
|
178 | else: | |||
|
179 | raise | |||
|
180 | jkeys = self.jobs_all.keys() | |||
|
181 | if jkeys: | |||
|
182 | job.num = max(jkeys)+1 | |||
|
183 | else: | |||
|
184 | job.num = 0 | |||
|
185 | self.jobs_run.append(job) | |||
|
186 | self.jobs_all[job.num] = job | |||
|
187 | print 'Starting job # %s in a separate thread.' % job.num | |||
|
188 | job.start() | |||
|
189 | return job | |||
|
190 | ||||
|
191 | def __getitem__(self,key): | |||
|
192 | return self.jobs_all[key] | |||
|
193 | ||||
|
194 | def __call__(self): | |||
|
195 | """An alias to self.status(), | |||
|
196 | ||||
|
197 | This allows you to simply call a job manager instance much like the | |||
|
198 | Unix jobs shell command.""" | |||
|
199 | ||||
|
200 | return self.status() | |||
|
201 | ||||
|
202 | def _update_status(self): | |||
|
203 | """Update the status of the job lists. | |||
|
204 | ||||
|
205 | This method moves finished jobs to one of two lists: | |||
|
206 | - self.jobs_comp: jobs which completed successfully | |||
|
207 | - self.jobs_dead: jobs which finished but died. | |||
|
208 | ||||
|
209 | It also copies those jobs to corresponding _report lists. These lists | |||
|
210 | are used to report jobs completed/dead since the last update, and are | |||
|
211 | then cleared by the reporting function after each call.""" | |||
|
212 | ||||
|
213 | run,comp,dead = self._s_running,self._s_completed,self._s_dead | |||
|
214 | jobs_run = self.jobs_run | |||
|
215 | for num in range(len(jobs_run)): | |||
|
216 | job = jobs_run[num] | |||
|
217 | stat = job.stat_code | |||
|
218 | if stat == run: | |||
|
219 | continue | |||
|
220 | elif stat == comp: | |||
|
221 | self.jobs_comp.append(job) | |||
|
222 | self._comp_report.append(job) | |||
|
223 | jobs_run[num] = False | |||
|
224 | elif stat == dead: | |||
|
225 | self.jobs_dead.append(job) | |||
|
226 | self._dead_report.append(job) | |||
|
227 | jobs_run[num] = False | |||
|
228 | self.jobs_run = filter(None,self.jobs_run) | |||
|
229 | ||||
|
230 | def _group_report(self,group,name): | |||
|
231 | """Report summary for a given job group. | |||
|
232 | ||||
|
233 | Return True if the group had any elements.""" | |||
|
234 | ||||
|
235 | if group: | |||
|
236 | print '%s jobs:' % name | |||
|
237 | for job in group: | |||
|
238 | print '%s : %s' % (job.num,job) | |||
|
239 | ||||
|
240 | return True | |||
|
241 | ||||
|
242 | def _group_flush(self,group,name): | |||
|
243 | """Flush a given job group | |||
|
244 | ||||
|
245 | Return True if the group had any elements.""" | |||
|
246 | ||||
|
247 | njobs = len(group) | |||
|
248 | if njobs: | |||
|
249 | plural = {1:''}.setdefault(njobs,'s') | |||
|
250 | print 'Flushing %s %s job%s.' % (njobs,name,plural) | |||
|
251 | group[:] = [] | |||
|
252 | return True | |||
|
253 | ||||
|
254 | def _status_new(self): | |||
|
255 | """Print the status of newly finished jobs. | |||
|
256 | ||||
|
257 | Return True if any new jobs are reported. | |||
|
258 | ||||
|
259 | This call resets its own state every time, so it only reports jobs | |||
|
260 | which have finished since the last time it was called.""" | |||
|
261 | ||||
|
262 | self._update_status() | |||
|
263 | new_comp = self._group_report(self._comp_report,'Completed') | |||
|
264 | new_dead = self._group_report(self._dead_report, | |||
|
265 | 'Dead, call job.traceback() for details') | |||
|
266 | self._comp_report[:] = [] | |||
|
267 | self._dead_report[:] = [] | |||
|
268 | return new_comp or new_dead | |||
|
269 | ||||
|
270 | def status(self,verbose=0): | |||
|
271 | """Print a status of all jobs currently being managed.""" | |||
|
272 | ||||
|
273 | self._update_status() | |||
|
274 | self._group_report(self.jobs_run,'Running') | |||
|
275 | self._group_report(self.jobs_comp,'Completed') | |||
|
276 | self._group_report(self.jobs_dead,'Dead') | |||
|
277 | # Also flush the report queues | |||
|
278 | self._comp_report[:] = [] | |||
|
279 | self._dead_report[:] = [] | |||
|
280 | ||||
|
281 | def remove(self,num): | |||
|
282 | """Remove a finished (completed or dead) job.""" | |||
|
283 | ||||
|
284 | try: | |||
|
285 | job = self.jobs_all[num] | |||
|
286 | except KeyError: | |||
|
287 | error('Job #%s not found' % num) | |||
|
288 | else: | |||
|
289 | stat_code = job.stat_code | |||
|
290 | if stat_code == self._s_running: | |||
|
291 | error('Job #%s is still running, it can not be removed.' % num) | |||
|
292 | return | |||
|
293 | elif stat_code == self._s_completed: | |||
|
294 | self.jobs_comp.remove(job) | |||
|
295 | elif stat_code == self._s_dead: | |||
|
296 | self.jobs_dead.remove(job) | |||
|
297 | ||||
|
298 | def flush_finished(self): | |||
|
299 | """Flush all jobs finished (completed and dead) from lists. | |||
|
300 | ||||
|
301 | Running jobs are never flushed. | |||
|
302 | ||||
|
303 | It first calls _status_new(), to update info. If any jobs have | |||
|
304 | completed since the last _status_new() call, the flush operation | |||
|
305 | aborts.""" | |||
|
306 | ||||
|
307 | if self._status_new(): | |||
|
308 | error('New jobs completed since last '\ | |||
|
309 | '_status_new(), aborting flush.') | |||
|
310 | return | |||
|
311 | ||||
|
312 | # Remove the finished jobs from the master dict | |||
|
313 | jobs_all = self.jobs_all | |||
|
314 | for job in self.jobs_comp+self.jobs_dead: | |||
|
315 | del(jobs_all[job.num]) | |||
|
316 | ||||
|
317 | # Now flush these lists completely | |||
|
318 | fl_comp = self._group_flush(self.jobs_comp,'Completed') | |||
|
319 | fl_dead = self._group_flush(self.jobs_dead,'Dead') | |||
|
320 | if not (fl_comp or fl_dead): | |||
|
321 | print 'No jobs to flush.' | |||
|
322 | ||||
|
323 | def result(self,num): | |||
|
324 | """result(N) -> return the result of job N.""" | |||
|
325 | try: | |||
|
326 | return self.jobs_all[num].result | |||
|
327 | except KeyError: | |||
|
328 | error('Job #%s not found' % num) | |||
|
329 | ||||
|
330 | def traceback(self,num): | |||
|
331 | try: | |||
|
332 | self.jobs_all[num].traceback() | |||
|
333 | except KeyError: | |||
|
334 | error('Job #%s not found' % num) | |||
|
335 | ||||
|
336 | ||||
|
337 | class BackgroundJobBase(threading.Thread): | |||
|
338 | """Base class to build BackgroundJob classes. | |||
|
339 | ||||
|
340 | The derived classes must implement: | |||
|
341 | ||||
|
342 | - Their own __init__, since the one here raises NotImplementedError. The | |||
|
343 | derived constructor must call self._init() at the end, to provide common | |||
|
344 | initialization. | |||
|
345 | ||||
|
346 | - A strform attribute used in calls to __str__. | |||
|
347 | ||||
|
348 | - A call() method, which will make the actual execution call and must | |||
|
349 | return a value to be held in the 'result' field of the job object.""" | |||
|
350 | ||||
|
351 | # Class constants for status, in string and as numerical codes (when | |||
|
352 | # updating jobs lists, we don't want to do string comparisons). This will | |||
|
353 | # be done at every user prompt, so it has to be as fast as possible | |||
|
354 | stat_created = 'Created'; stat_created_c = 0 | |||
|
355 | stat_running = 'Running'; stat_running_c = 1 | |||
|
356 | stat_completed = 'Completed'; stat_completed_c = 2 | |||
|
357 | stat_dead = 'Dead (Exception), call job.traceback() for details' | |||
|
358 | stat_dead_c = -1 | |||
|
359 | ||||
|
360 | def __init__(self): | |||
|
361 | raise NotImplementedError, \ | |||
|
362 | "This class can not be instantiated directly." | |||
|
363 | ||||
|
364 | def _init(self): | |||
|
365 | """Common initialization for all BackgroundJob objects""" | |||
|
366 | ||||
|
367 | for attr in ['call','strform']: | |||
|
368 | assert hasattr(self,attr), "Missing attribute <%s>" % attr | |||
|
369 | ||||
|
370 | # The num tag can be set by an external job manager | |||
|
371 | self.num = None | |||
|
372 | ||||
|
373 | self.status = BackgroundJobBase.stat_created | |||
|
374 | self.stat_code = BackgroundJobBase.stat_created_c | |||
|
375 | self.finished = False | |||
|
376 | self.result = '<BackgroundJob has not completed>' | |||
|
377 | # reuse the ipython traceback handler if we can get to it, otherwise | |||
|
378 | # make a new one | |||
|
379 | try: | |||
|
380 | self._make_tb = __IPYTHON__.InteractiveTB.text | |||
|
381 | except: | |||
|
382 | self._make_tb = AutoFormattedTB(mode = 'Context', | |||
|
383 | color_scheme='NoColor', | |||
|
384 | tb_offset = 1).text | |||
|
385 | # Hold a formatted traceback if one is generated. | |||
|
386 | self._tb = None | |||
|
387 | ||||
|
388 | threading.Thread.__init__(self) | |||
|
389 | ||||
|
390 | def __str__(self): | |||
|
391 | return self.strform | |||
|
392 | ||||
|
393 | def __repr__(self): | |||
|
394 | return '<BackgroundJob: %s>' % self.strform | |||
|
395 | ||||
|
396 | def traceback(self): | |||
|
397 | print self._tb | |||
|
398 | ||||
|
399 | def run(self): | |||
|
400 | try: | |||
|
401 | self.status = BackgroundJobBase.stat_running | |||
|
402 | self.stat_code = BackgroundJobBase.stat_running_c | |||
|
403 | self.result = self.call() | |||
|
404 | except: | |||
|
405 | self.status = BackgroundJobBase.stat_dead | |||
|
406 | self.stat_code = BackgroundJobBase.stat_dead_c | |||
|
407 | self.finished = None | |||
|
408 | self.result = ('<BackgroundJob died, call job.traceback() for details>') | |||
|
409 | self._tb = self._make_tb() | |||
|
410 | else: | |||
|
411 | self.status = BackgroundJobBase.stat_completed | |||
|
412 | self.stat_code = BackgroundJobBase.stat_completed_c | |||
|
413 | self.finished = True | |||
|
414 | ||||
|
415 | class BackgroundJobExpr(BackgroundJobBase): | |||
|
416 | """Evaluate an expression as a background job (uses a separate thread).""" | |||
|
417 | ||||
|
418 | def __init__(self,expression,glob=None,loc=None): | |||
|
419 | """Create a new job from a string which can be fed to eval(). | |||
|
420 | ||||
|
421 | global/locals dicts can be provided, which will be passed to the eval | |||
|
422 | call.""" | |||
|
423 | ||||
|
424 | # fail immediately if the given expression can't be compiled | |||
|
425 | self.code = compile(expression,'<BackgroundJob compilation>','eval') | |||
|
426 | ||||
|
427 | if glob is None: | |||
|
428 | glob = {} | |||
|
429 | if loc is None: | |||
|
430 | loc = {} | |||
|
431 | ||||
|
432 | self.expression = self.strform = expression | |||
|
433 | self.glob = glob | |||
|
434 | self.loc = loc | |||
|
435 | self._init() | |||
|
436 | ||||
|
437 | def call(self): | |||
|
438 | return eval(self.code,self.glob,self.loc) | |||
|
439 | ||||
|
440 | class BackgroundJobFunc(BackgroundJobBase): | |||
|
441 | """Run a function call as a background job (uses a separate thread).""" | |||
|
442 | ||||
|
443 | def __init__(self,func,*args,**kwargs): | |||
|
444 | """Create a new job from a callable object. | |||
|
445 | ||||
|
446 | Any positional arguments and keyword args given to this constructor | |||
|
447 | after the initial callable are passed directly to it.""" | |||
|
448 | ||||
|
449 | assert callable(func),'first argument must be callable' | |||
|
450 | ||||
|
451 | if args is None: | |||
|
452 | args = [] | |||
|
453 | if kwargs is None: | |||
|
454 | kwargs = {} | |||
|
455 | ||||
|
456 | self.func = func | |||
|
457 | self.args = args | |||
|
458 | self.kwargs = kwargs | |||
|
459 | # The string form will only include the function passed, because | |||
|
460 | # generating string representations of the arguments is a potentially | |||
|
461 | # _very_ expensive operation (e.g. with large arrays). | |||
|
462 | self.strform = str(func) | |||
|
463 | self._init() | |||
|
464 | ||||
|
465 | def call(self): | |||
|
466 | return self.func(*self.args,**self.kwargs) | |||
|
467 | ||||
|
468 | ||||
|
469 | if __name__=='__main__': | |||
|
470 | ||||
|
471 | import time | |||
|
472 | ||||
|
473 | def sleepfunc(interval=2,*a,**kw): | |||
|
474 | args = dict(interval=interval, | |||
|
475 | args=a, | |||
|
476 | kwargs=kw) | |||
|
477 | time.sleep(interval) | |||
|
478 | return args | |||
|
479 | ||||
|
480 | def diefunc(interval=2,*a,**kw): | |||
|
481 | time.sleep(interval) | |||
|
482 | die | |||
|
483 | ||||
|
484 | def printfunc(interval=1,reps=5): | |||
|
485 | for n in range(reps): | |||
|
486 | time.sleep(interval) | |||
|
487 | print 'In the background...' | |||
|
488 | ||||
|
489 | jobs = BackgroundJobManager() | |||
|
490 | # first job will have # 0 | |||
|
491 | jobs.new(sleepfunc,4) | |||
|
492 | jobs.new(sleepfunc,kw={'reps':2}) | |||
|
493 | # This makes a job which will die | |||
|
494 | jobs.new(diefunc,1) | |||
|
495 | jobs.new('printfunc(1,3)') | |||
|
496 | ||||
|
497 | # after a while, you can get the traceback of a dead job. Run the line | |||
|
498 | # below again interactively until it prints a traceback (check the status | |||
|
499 | # of the job): | |||
|
500 | print jobs[1].status | |||
|
501 | jobs[1].traceback() | |||
|
502 | ||||
|
503 | # Run this line again until the printed result changes | |||
|
504 | print "The result of job #0 is:",jobs[0].result |
@@ -0,0 +1,184 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | A module to change reload() so that it acts recursively. | |||
|
4 | To enable it type: | |||
|
5 | >>> import __builtin__, deep_reload | |||
|
6 | >>> __builtin__.reload = deep_reload.reload | |||
|
7 | You can then disable it with: | |||
|
8 | >>> __builtin__.reload = deep_reload.original_reload | |||
|
9 | ||||
|
10 | Alternatively, you can add a dreload builtin alongside normal reload with: | |||
|
11 | >>> __builtin__.dreload = deep_reload.reload | |||
|
12 | ||||
|
13 | This code is almost entirely based on knee.py from the standard library. | |||
|
14 | ||||
|
15 | $Id: deep_reload.py 410 2004-11-04 07:58:17Z fperez $""" | |||
|
16 | ||||
|
17 | #***************************************************************************** | |||
|
18 | # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu> | |||
|
19 | # | |||
|
20 | # Distributed under the terms of the BSD License. The full license is in | |||
|
21 | # the file COPYING, distributed as part of this software. | |||
|
22 | #***************************************************************************** | |||
|
23 | ||||
|
24 | from IPython import Release # do it explicitly so pydoc can see it - pydoc bug | |||
|
25 | __author__ = '%s <%s>' % Release.authors['Nathan'] | |||
|
26 | __license__ = Release.license | |||
|
27 | __version__ = "0.5" | |||
|
28 | __date__ = "21 August 2001" | |||
|
29 | ||||
|
30 | import sys, imp, __builtin__ | |||
|
31 | ||||
|
32 | # Replacement for __import__() | |||
|
33 | def deep_import_hook(name, globals=None, locals=None, fromlist=None): | |||
|
34 | parent = determine_parent(globals) | |||
|
35 | q, tail = find_head_package(parent, name) | |||
|
36 | m = load_tail(q, tail) | |||
|
37 | if not fromlist: | |||
|
38 | return q | |||
|
39 | if hasattr(m, "__path__"): | |||
|
40 | ensure_fromlist(m, fromlist) | |||
|
41 | return m | |||
|
42 | ||||
|
43 | def determine_parent(globals): | |||
|
44 | if not globals or not globals.has_key("__name__"): | |||
|
45 | return None | |||
|
46 | pname = globals['__name__'] | |||
|
47 | if globals.has_key("__path__"): | |||
|
48 | parent = sys.modules[pname] | |||
|
49 | assert globals is parent.__dict__ | |||
|
50 | return parent | |||
|
51 | if '.' in pname: | |||
|
52 | i = pname.rfind('.') | |||
|
53 | pname = pname[:i] | |||
|
54 | parent = sys.modules[pname] | |||
|
55 | assert parent.__name__ == pname | |||
|
56 | return parent | |||
|
57 | return None | |||
|
58 | ||||
|
59 | def find_head_package(parent, name): | |||
|
60 | # Import the first | |||
|
61 | if '.' in name: | |||
|
62 | # 'some.nested.package' -> head = 'some', tail = 'nested.package' | |||
|
63 | i = name.find('.') | |||
|
64 | head = name[:i] | |||
|
65 | tail = name[i+1:] | |||
|
66 | else: | |||
|
67 | # 'packagename' -> head = 'packagename', tail = '' | |||
|
68 | head = name | |||
|
69 | tail = "" | |||
|
70 | if parent: | |||
|
71 | # If this is a subpackage then qname = parent's name + head | |||
|
72 | qname = "%s.%s" % (parent.__name__, head) | |||
|
73 | else: | |||
|
74 | qname = head | |||
|
75 | q = import_module(head, qname, parent) | |||
|
76 | if q: return q, tail | |||
|
77 | if parent: | |||
|
78 | qname = head | |||
|
79 | parent = None | |||
|
80 | q = import_module(head, qname, parent) | |||
|
81 | if q: return q, tail | |||
|
82 | raise ImportError, "No module named " + qname | |||
|
83 | ||||
|
84 | def load_tail(q, tail): | |||
|
85 | m = q | |||
|
86 | while tail: | |||
|
87 | i = tail.find('.') | |||
|
88 | if i < 0: i = len(tail) | |||
|
89 | head, tail = tail[:i], tail[i+1:] | |||
|
90 | ||||
|
91 | # fperez: fix dotted.name reloading failures by changing: | |||
|
92 | #mname = "%s.%s" % (m.__name__, head) | |||
|
93 | # to: | |||
|
94 | mname = m.__name__ | |||
|
95 | # This needs more testing!!! (I don't understand this module too well) | |||
|
96 | ||||
|
97 | #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg | |||
|
98 | m = import_module(head, mname, m) | |||
|
99 | if not m: | |||
|
100 | raise ImportError, "No module named " + mname | |||
|
101 | return m | |||
|
102 | ||||
|
103 | def ensure_fromlist(m, fromlist, recursive=0): | |||
|
104 | for sub in fromlist: | |||
|
105 | if sub == "*": | |||
|
106 | if not recursive: | |||
|
107 | try: | |||
|
108 | all = m.__all__ | |||
|
109 | except AttributeError: | |||
|
110 | pass | |||
|
111 | else: | |||
|
112 | ensure_fromlist(m, all, 1) | |||
|
113 | continue | |||
|
114 | if sub != "*" and not hasattr(m, sub): | |||
|
115 | subname = "%s.%s" % (m.__name__, sub) | |||
|
116 | submod = import_module(sub, subname, m) | |||
|
117 | if not submod: | |||
|
118 | raise ImportError, "No module named " + subname | |||
|
119 | ||||
|
120 | # Need to keep track of what we've already reloaded to prevent cyclic evil | |||
|
121 | found_now = {} | |||
|
122 | ||||
|
123 | def import_module(partname, fqname, parent): | |||
|
124 | global found_now | |||
|
125 | if found_now.has_key(fqname): | |||
|
126 | try: | |||
|
127 | return sys.modules[fqname] | |||
|
128 | except KeyError: | |||
|
129 | pass | |||
|
130 | ||||
|
131 | print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \ | |||
|
132 | #sys.displayhook is sys.__displayhook__ | |||
|
133 | ||||
|
134 | found_now[fqname] = 1 | |||
|
135 | try: | |||
|
136 | fp, pathname, stuff = imp.find_module(partname, | |||
|
137 | parent and parent.__path__) | |||
|
138 | except ImportError: | |||
|
139 | return None | |||
|
140 | ||||
|
141 | try: | |||
|
142 | m = imp.load_module(fqname, fp, pathname, stuff) | |||
|
143 | finally: | |||
|
144 | if fp: fp.close() | |||
|
145 | ||||
|
146 | if parent: | |||
|
147 | setattr(parent, partname, m) | |||
|
148 | ||||
|
149 | return m | |||
|
150 | ||||
|
151 | def deep_reload_hook(module): | |||
|
152 | name = module.__name__ | |||
|
153 | if '.' not in name: | |||
|
154 | return import_module(name, name, None) | |||
|
155 | i = name.rfind('.') | |||
|
156 | pname = name[:i] | |||
|
157 | parent = sys.modules[pname] | |||
|
158 | return import_module(name[i+1:], name, parent) | |||
|
159 | ||||
|
160 | # Save the original hooks | |||
|
161 | original_reload = __builtin__.reload | |||
|
162 | ||||
|
163 | # Replacement for reload() | |||
|
164 | def reload(module, exclude=['sys', '__builtin__', '__main__']): | |||
|
165 | """Recursively reload all modules used in the given module. Optionally | |||
|
166 | takes a list of modules to exclude from reloading. The default exclude | |||
|
167 | list contains sys, __main__, and __builtin__, to prevent, e.g., resetting | |||
|
168 | display, exception, and io hooks. | |||
|
169 | """ | |||
|
170 | global found_now | |||
|
171 | for i in exclude: | |||
|
172 | found_now[i] = 1 | |||
|
173 | original_import = __builtin__.__import__ | |||
|
174 | __builtin__.__import__ = deep_import_hook | |||
|
175 | try: | |||
|
176 | ret = deep_reload_hook(module) | |||
|
177 | finally: | |||
|
178 | __builtin__.__import__ = original_import | |||
|
179 | found_now = {} | |||
|
180 | return ret | |||
|
181 | ||||
|
182 | # Uncomment the following to automatically activate deep reloading whenever | |||
|
183 | # this module is imported | |||
|
184 | #__builtin__.reload = reload |
This diff has been collapsed as it changes many lines, (1519 lines changed) Show them Hide them | |||||
@@ -0,0 +1,1519 | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | General purpose utilities. | |||
|
4 | ||||
|
5 | This is a grab-bag of stuff I find useful in most programs I write. Some of | |||
|
6 | these things are also convenient when working at the command line. | |||
|
7 | ||||
|
8 | $Id: genutils.py 543 2005-03-18 09:23:48Z fperez $""" | |||
|
9 | ||||
|
10 | #***************************************************************************** | |||
|
11 | # Copyright (C) 2001-2004 Fernando Perez. <fperez@colorado.edu> | |||
|
12 | # | |||
|
13 | # Distributed under the terms of the BSD License. The full license is in | |||
|
14 | # the file COPYING, distributed as part of this software. | |||
|
15 | #***************************************************************************** | |||
|
16 | ||||
|
17 | from IPython import Release | |||
|
18 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
19 | __license__ = Release.license | |||
|
20 | ||||
|
21 | #**************************************************************************** | |||
|
22 | # required modules | |||
|
23 | import __main__ | |||
|
24 | import types,commands,time,sys,os,re,shutil | |||
|
25 | import tempfile | |||
|
26 | from IPython.Itpl import Itpl,itpl,printpl | |||
|
27 | from IPython import DPyGetOpt | |||
|
28 | ||||
|
29 | #**************************************************************************** | |||
|
30 | # Exceptions | |||
|
31 | class Error(Exception): | |||
|
32 | """Base class for exceptions in this module.""" | |||
|
33 | pass | |||
|
34 | ||||
|
35 | #---------------------------------------------------------------------------- | |||
|
36 | class Stream: | |||
|
37 | """Simple class to hold the various I/O streams in Term""" | |||
|
38 | ||||
|
39 | def __init__(self,stream,name): | |||
|
40 | self.stream = stream | |||
|
41 | self.name = name | |||
|
42 | try: | |||
|
43 | self.fileno = stream.fileno() | |||
|
44 | except AttributeError: | |||
|
45 | msg = ("Stream <%s> looks suspicious: it lacks a 'fileno' attribute." | |||
|
46 | % name) | |||
|
47 | print >> sys.stderr, 'WARNING:',msg | |||
|
48 | try: | |||
|
49 | self.mode = stream.mode | |||
|
50 | except AttributeError: | |||
|
51 | msg = ("Stream <%s> looks suspicious: it lacks a 'mode' attribute." | |||
|
52 | % name) | |||
|
53 | print >> sys.stderr, 'WARNING:',msg | |||
|
54 | ||||
|
55 | class Term: | |||
|
56 | """ Term holds the file or file-like objects for handling I/O operations. | |||
|
57 | ||||
|
58 | These are normally just sys.stdin, sys.stdout and sys.stderr but for | |||
|
59 | Windows they can can replaced to allow editing the strings before they are | |||
|
60 | displayed.""" | |||
|
61 | ||||
|
62 | # In the future, having IPython channel all its I/O operations through | |||
|
63 | # this class will make it easier to embed it into other environments which | |||
|
64 | # are not a normal terminal (such as a GUI-based shell) | |||
|
65 | in_s = Stream(sys.stdin,'cin') | |||
|
66 | out_s = Stream(sys.stdout,'cout') | |||
|
67 | err_s = Stream(sys.stderr,'cerr') | |||
|
68 | ||||
|
69 | # Store the three streams in (err,out,in) order so that if we need to reopen | |||
|
70 | # them, the error channel is reopened first to provide info. | |||
|
71 | streams = [err_s,out_s,in_s] | |||
|
72 | ||||
|
73 | # The class globals should be the actual 'bare' streams for normal I/O to work | |||
|
74 | cin = streams[2].stream | |||
|
75 | cout = streams[1].stream | |||
|
76 | cerr = streams[0].stream | |||
|
77 | ||||
|
78 | def reopen_all(cls): | |||
|
79 | """Reopen all streams if necessary. | |||
|
80 | ||||
|
81 | This should only be called if it is suspected that someting closed | |||
|
82 | accidentally one of the I/O streams.""" | |||
|
83 | ||||
|
84 | any_closed = 0 | |||
|
85 | ||||
|
86 | for sn in range(len(cls.streams)): | |||
|
87 | st = cls.streams[sn] | |||
|
88 | if st.stream.closed: | |||
|
89 | any_closed = 1 | |||
|
90 | new_stream = os.fdopen(os.dup(st.fileno), st.mode,0) | |||
|
91 | cls.streams[sn] = Stream(new_stream,st.name) | |||
|
92 | print >> cls.streams[0].stream, \ | |||
|
93 | '\nWARNING:\nStream Term.%s had to be reopened!' % st.name | |||
|
94 | ||||
|
95 | # Rebuild the class globals | |||
|
96 | cls.cin = cls.streams[2].stream | |||
|
97 | cls.cout = cls.streams[1].stream | |||
|
98 | cls.cerr = cls.streams[0].stream | |||
|
99 | ||||
|
100 | reopen_all = classmethod(reopen_all) | |||
|
101 | ||||
|
102 | def set_stdout(cls,stream): | |||
|
103 | """Set the stream """ | |||
|
104 | cls.cout = stream | |||
|
105 | set_stdout = classmethod(set_stdout) | |||
|
106 | ||||
|
107 | def set_stderr(cls,stream): | |||
|
108 | cls.cerr = stream | |||
|
109 | set_stderr = classmethod(set_stderr) | |||
|
110 | ||||
|
111 | # Windows-specific code to load Gary Bishop's readline and configure it | |||
|
112 | # automatically for the users | |||
|
113 | # Note: os.name on cygwin returns posix, so this should only pick up 'native' | |||
|
114 | # windows. Cygwin returns 'cygwin' for sys.platform. | |||
|
115 | if os.name == 'nt': | |||
|
116 | try: | |||
|
117 | import readline | |||
|
118 | except ImportError: | |||
|
119 | pass | |||
|
120 | else: | |||
|
121 | try: | |||
|
122 | _out = readline.GetOutputFile() | |||
|
123 | except AttributeError: | |||
|
124 | pass | |||
|
125 | else: | |||
|
126 | Term.set_stdout(_out) | |||
|
127 | Term.set_stderr(_out) | |||
|
128 | del _out | |||
|
129 | ||||
|
130 | #**************************************************************************** | |||
|
131 | # Generic warning/error printer, used by everything else | |||
|
132 | def warn(msg,level=2,exit_val=1): | |||
|
133 | """Standard warning printer. Gives formatting consistency. | |||
|
134 | ||||
|
135 | Output is sent to Term.cerr (sys.stderr by default). | |||
|
136 | ||||
|
137 | Options: | |||
|
138 | ||||
|
139 | -level(2): allows finer control: | |||
|
140 | 0 -> Do nothing, dummy function. | |||
|
141 | 1 -> Print message. | |||
|
142 | 2 -> Print 'WARNING:' + message. (Default level). | |||
|
143 | 3 -> Print 'ERROR:' + message. | |||
|
144 | 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val). | |||
|
145 | ||||
|
146 | -exit_val (1): exit value returned by sys.exit() for a level 4 | |||
|
147 | warning. Ignored for all other levels.""" | |||
|
148 | ||||
|
149 | if level>0: | |||
|
150 | header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] | |||
|
151 | print >> Term.cerr, '%s%s' % (header[level],msg) | |||
|
152 | if level == 4: | |||
|
153 | print >> Term.cerr,'Exiting.\n' | |||
|
154 | sys.exit(exit_val) | |||
|
155 | ||||
|
156 | def info(msg): | |||
|
157 | """Equivalent to warn(msg,level=1).""" | |||
|
158 | ||||
|
159 | warn(msg,level=1) | |||
|
160 | ||||
|
161 | def error(msg): | |||
|
162 | """Equivalent to warn(msg,level=3).""" | |||
|
163 | ||||
|
164 | warn(msg,level=3) | |||
|
165 | ||||
|
166 | def fatal(msg,exit_val=1): | |||
|
167 | """Equivalent to warn(msg,exit_val=exit_val,level=4).""" | |||
|
168 | ||||
|
169 | warn(msg,exit_val=exit_val,level=4) | |||
|
170 | ||||
|
171 | #---------------------------------------------------------------------------- | |||
|
172 | StringTypes = types.StringTypes | |||
|
173 | ||||
|
174 | # Basic timing functionality | |||
|
175 | ||||
|
176 | # If possible (Unix), use the resource module instead of time.clock() | |||
|
177 | try: | |||
|
178 | import resource | |||
|
179 | def clock(): | |||
|
180 | """clock() -> floating point number | |||
|
181 | ||||
|
182 | Return the CPU time in seconds (user time only, system time is | |||
|
183 | ignored) since the start of the process. This is done via a call to | |||
|
184 | resource.getrusage, so it avoids the wraparound problems in | |||
|
185 | time.clock().""" | |||
|
186 | ||||
|
187 | return resource.getrusage(resource.RUSAGE_SELF)[0] | |||
|
188 | ||||
|
189 | def clock2(): | |||
|
190 | """clock2() -> (t_user,t_system) | |||
|
191 | ||||
|
192 | Similar to clock(), but return a tuple of user/system times.""" | |||
|
193 | return resource.getrusage(resource.RUSAGE_SELF)[:2] | |||
|
194 | ||||
|
195 | except ImportError: | |||
|
196 | clock = time.clock | |||
|
197 | def clock2(): | |||
|
198 | """Under windows, system CPU time can't be measured. | |||
|
199 | ||||
|
200 | This just returns clock() and zero.""" | |||
|
201 | return time.clock(),0.0 | |||
|
202 | ||||
|
203 | def timings_out(reps,func,*args,**kw): | |||
|
204 | """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output) | |||
|
205 | ||||
|
206 | Execute a function reps times, return a tuple with the elapsed total | |||
|
207 | CPU time in seconds, the time per call and the function's output. | |||
|
208 | ||||
|
209 | Under Unix, the return value is the sum of user+system time consumed by | |||
|
210 | the process, computed via the resource module. This prevents problems | |||
|
211 | related to the wraparound effect which the time.clock() function has. | |||
|
212 | ||||
|
213 | Under Windows the return value is in wall clock seconds. See the | |||
|
214 | documentation for the time module for more details.""" | |||
|
215 | ||||
|
216 | reps = int(reps) | |||
|
217 | assert reps >=1, 'reps must be >= 1' | |||
|
218 | if reps==1: | |||
|
219 | start = clock() | |||
|
220 | out = func(*args,**kw) | |||
|
221 | tot_time = clock()-start | |||
|
222 | else: | |||
|
223 | rng = xrange(reps-1) # the last time is executed separately to store output | |||
|
224 | start = clock() | |||
|
225 | for dummy in rng: func(*args,**kw) | |||
|
226 | out = func(*args,**kw) # one last time | |||
|
227 | tot_time = clock()-start | |||
|
228 | av_time = tot_time / reps | |||
|
229 | return tot_time,av_time,out | |||
|
230 | ||||
|
231 | def timings(reps,func,*args,**kw): | |||
|
232 | """timings(reps,func,*args,**kw) -> (t_total,t_per_call) | |||
|
233 | ||||
|
234 | Execute a function reps times, return a tuple with the elapsed total CPU | |||
|
235 | time in seconds and the time per call. These are just the first two values | |||
|
236 | in timings_out().""" | |||
|
237 | ||||
|
238 | return timings_out(reps,func,*args,**kw)[0:2] | |||
|
239 | ||||
|
240 | def timing(func,*args,**kw): | |||
|
241 | """timing(func,*args,**kw) -> t_total | |||
|
242 | ||||
|
243 | Execute a function once, return the elapsed total CPU time in | |||
|
244 | seconds. This is just the first value in timings_out().""" | |||
|
245 | ||||
|
246 | return timings_out(1,func,*args,**kw)[0] | |||
|
247 | ||||
|
248 | #**************************************************************************** | |||
|
249 | # file and system | |||
|
250 | ||||
|
251 | def system(cmd,verbose=0,debug=0,header=''): | |||
|
252 | """Execute a system command, return its exit status. | |||
|
253 | ||||
|
254 | Options: | |||
|
255 | ||||
|
256 | - verbose (0): print the command to be executed. | |||
|
257 | ||||
|
258 | - debug (0): only print, do not actually execute. | |||
|
259 | ||||
|
260 | - header (''): Header to print on screen prior to the executed command (it | |||
|
261 | is only prepended to the command, no newlines are added). | |||
|
262 | ||||
|
263 | Note: a stateful version of this function is available through the | |||
|
264 | SystemExec class.""" | |||
|
265 | ||||
|
266 | stat = 0 | |||
|
267 | if verbose or debug: print header+cmd | |||
|
268 | sys.stdout.flush() | |||
|
269 | if not debug: stat = os.system(cmd) | |||
|
270 | return stat | |||
|
271 | ||||
|
272 | def shell(cmd,verbose=0,debug=0,header=''): | |||
|
273 | """Execute a command in the system shell, always return None. | |||
|
274 | ||||
|
275 | Options: | |||
|
276 | ||||
|
277 | - verbose (0): print the command to be executed. | |||
|
278 | ||||
|
279 | - debug (0): only print, do not actually execute. | |||
|
280 | ||||
|
281 | - header (''): Header to print on screen prior to the executed command (it | |||
|
282 | is only prepended to the command, no newlines are added). | |||
|
283 | ||||
|
284 | Note: this is similar to genutils.system(), but it returns None so it can | |||
|
285 | be conveniently used in interactive loops without getting the return value | |||
|
286 | (typically 0) printed many times.""" | |||
|
287 | ||||
|
288 | stat = 0 | |||
|
289 | if verbose or debug: print header+cmd | |||
|
290 | # flush stdout so we don't mangle python's buffering | |||
|
291 | sys.stdout.flush() | |||
|
292 | if not debug: | |||
|
293 | os.system(cmd) | |||
|
294 | ||||
|
295 | def getoutput(cmd,verbose=0,debug=0,header='',split=0): | |||
|
296 | """Dummy substitute for perl's backquotes. | |||
|
297 | ||||
|
298 | Executes a command and returns the output. | |||
|
299 | ||||
|
300 | Accepts the same arguments as system(), plus: | |||
|
301 | ||||
|
302 | - split(0): if true, the output is returned as a list split on newlines. | |||
|
303 | ||||
|
304 | Note: a stateful version of this function is available through the | |||
|
305 | SystemExec class.""" | |||
|
306 | ||||
|
307 | if verbose or debug: print header+cmd | |||
|
308 | if not debug: | |||
|
309 | output = commands.getoutput(cmd) | |||
|
310 | if split: | |||
|
311 | return output.split('\n') | |||
|
312 | else: | |||
|
313 | return output | |||
|
314 | ||||
|
315 | def getoutputerror(cmd,verbose=0,debug=0,header='',split=0): | |||
|
316 | """Return (standard output,standard error) of executing cmd in a shell. | |||
|
317 | ||||
|
318 | Accepts the same arguments as system(), plus: | |||
|
319 | ||||
|
320 | - split(0): if true, each of stdout/err is returned as a list split on | |||
|
321 | newlines. | |||
|
322 | ||||
|
323 | Note: a stateful version of this function is available through the | |||
|
324 | SystemExec class.""" | |||
|
325 | ||||
|
326 | if verbose or debug: print header+cmd | |||
|
327 | if not cmd: | |||
|
328 | if split: | |||
|
329 | return [],[] | |||
|
330 | else: | |||
|
331 | return '','' | |||
|
332 | if not debug: | |||
|
333 | pin,pout,perr = os.popen3(cmd) | |||
|
334 | tout = pout.read().rstrip() | |||
|
335 | terr = perr.read().rstrip() | |||
|
336 | pin.close() | |||
|
337 | pout.close() | |||
|
338 | perr.close() | |||
|
339 | if split: | |||
|
340 | return tout.split('\n'),terr.split('\n') | |||
|
341 | else: | |||
|
342 | return tout,terr | |||
|
343 | ||||
|
344 | # for compatibility with older naming conventions | |||
|
345 | xsys = system | |||
|
346 | bq = getoutput | |||
|
347 | ||||
|
348 | class SystemExec: | |||
|
349 | """Access the system and getoutput functions through a stateful interface. | |||
|
350 | ||||
|
351 | Note: here we refer to the system and getoutput functions from this | |||
|
352 | library, not the ones from the standard python library. | |||
|
353 | ||||
|
354 | This class offers the system and getoutput functions as methods, but the | |||
|
355 | verbose, debug and header parameters can be set for the instance (at | |||
|
356 | creation time or later) so that they don't need to be specified on each | |||
|
357 | call. | |||
|
358 | ||||
|
359 | For efficiency reasons, there's no way to override the parameters on a | |||
|
360 | per-call basis other than by setting instance attributes. If you need | |||
|
361 | local overrides, it's best to directly call system() or getoutput(). | |||
|
362 | ||||
|
363 | The following names are provided as alternate options: | |||
|
364 | - xsys: alias to system | |||
|
365 | - bq: alias to getoutput | |||
|
366 | ||||
|
367 | An instance can then be created as: | |||
|
368 | >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ') | |||
|
369 | ||||
|
370 | And used as: | |||
|
371 | >>> sysexec.xsys('pwd') | |||
|
372 | >>> dirlist = sysexec.bq('ls -l') | |||
|
373 | """ | |||
|
374 | ||||
|
375 | def __init__(self,verbose=0,debug=0,header='',split=0): | |||
|
376 | """Specify the instance's values for verbose, debug and header.""" | |||
|
377 | setattr_list(self,'verbose debug header split') | |||
|
378 | ||||
|
379 | def system(self,cmd): | |||
|
380 | """Stateful interface to system(), with the same keyword parameters.""" | |||
|
381 | ||||
|
382 | system(cmd,self.verbose,self.debug,self.header) | |||
|
383 | ||||
|
384 | def shell(self,cmd): | |||
|
385 | """Stateful interface to shell(), with the same keyword parameters.""" | |||
|
386 | ||||
|
387 | shell(cmd,self.verbose,self.debug,self.header) | |||
|
388 | ||||
|
389 | xsys = system # alias | |||
|
390 | ||||
|
391 | def getoutput(self,cmd): | |||
|
392 | """Stateful interface to getoutput().""" | |||
|
393 | ||||
|
394 | return getoutput(cmd,self.verbose,self.debug,self.header,self.split) | |||
|
395 | ||||
|
396 | def getoutputerror(self,cmd): | |||
|
397 | """Stateful interface to getoutputerror().""" | |||
|
398 | ||||
|
399 | return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split) | |||
|
400 | ||||
|
401 | bq = getoutput # alias | |||
|
402 | ||||
|
403 | #----------------------------------------------------------------------------- | |||
|
404 | def mutex_opts(dict,ex_op): | |||
|
405 | """Check for presence of mutually exclusive keys in a dict. | |||
|
406 | ||||
|
407 | Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]""" | |||
|
408 | for op1,op2 in ex_op: | |||
|
409 | if op1 in dict and op2 in dict: | |||
|
410 | raise ValueError,'\n*** ERROR in Arguments *** '\ | |||
|
411 | 'Options '+op1+' and '+op2+' are mutually exclusive.' | |||
|
412 | ||||
|
413 | #----------------------------------------------------------------------------- | |||
|
414 | def filefind(fname,alt_dirs = None): | |||
|
415 | """Return the given filename either in the current directory, if it | |||
|
416 | exists, or in a specified list of directories. | |||
|
417 | ||||
|
418 | ~ expansion is done on all file and directory names. | |||
|
419 | ||||
|
420 | Upon an unsuccessful search, raise an IOError exception.""" | |||
|
421 | ||||
|
422 | if alt_dirs is None: | |||
|
423 | try: | |||
|
424 | alt_dirs = get_home_dir() | |||
|
425 | except HomeDirError: | |||
|
426 | alt_dirs = os.getcwd() | |||
|
427 | search = [fname] + list_strings(alt_dirs) | |||
|
428 | search = map(os.path.expanduser,search) | |||
|
429 | #print 'search list for',fname,'list:',search # dbg | |||
|
430 | fname = search[0] | |||
|
431 | if os.path.isfile(fname): | |||
|
432 | return fname | |||
|
433 | for direc in search[1:]: | |||
|
434 | testname = os.path.join(direc,fname) | |||
|
435 | #print 'testname',testname # dbg | |||
|
436 | if os.path.isfile(testname): | |||
|
437 | return testname | |||
|
438 | raise IOError,'File' + `fname` + \ | |||
|
439 | ' not found in current or supplied directories:' + `alt_dirs` | |||
|
440 | ||||
|
441 | #---------------------------------------------------------------------------- | |||
|
442 | def target_outdated(target,deps): | |||
|
443 | """Determine whether a target is out of date. | |||
|
444 | ||||
|
445 | target_outdated(target,deps) -> 1/0 | |||
|
446 | ||||
|
447 | deps: list of filenames which MUST exist. | |||
|
448 | target: single filename which may or may not exist. | |||
|
449 | ||||
|
450 | If target doesn't exist or is older than any file listed in deps, return | |||
|
451 | true, otherwise return false. | |||
|
452 | """ | |||
|
453 | try: | |||
|
454 | target_time = os.path.getmtime(target) | |||
|
455 | except os.error: | |||
|
456 | return 1 | |||
|
457 | for dep in deps: | |||
|
458 | dep_time = os.path.getmtime(dep) | |||
|
459 | if dep_time > target_time: | |||
|
460 | #print "For target",target,"Dep failed:",dep # dbg | |||
|
461 | #print "times (dep,tar):",dep_time,target_time # dbg | |||
|
462 | return 1 | |||
|
463 | return 0 | |||
|
464 | ||||
|
465 | #----------------------------------------------------------------------------- | |||
|
466 | def target_update(target,deps,cmd): | |||
|
467 | """Update a target with a given command given a list of dependencies. | |||
|
468 | ||||
|
469 | target_update(target,deps,cmd) -> runs cmd if target is outdated. | |||
|
470 | ||||
|
471 | This is just a wrapper around target_outdated() which calls the given | |||
|
472 | command if target is outdated.""" | |||
|
473 | ||||
|
474 | if target_outdated(target,deps): | |||
|
475 | xsys(cmd) | |||
|
476 | ||||
|
477 | #---------------------------------------------------------------------------- | |||
|
478 | def unquote_ends(istr): | |||
|
479 | """Remove a single pair of quotes from the endpoints of a string.""" | |||
|
480 | ||||
|
481 | if not istr: | |||
|
482 | return istr | |||
|
483 | if (istr[0]=="'" and istr[-1]=="'") or \ | |||
|
484 | (istr[0]=='"' and istr[-1]=='"'): | |||
|
485 | return istr[1:-1] | |||
|
486 | else: | |||
|
487 | return istr | |||
|
488 | ||||
|
489 | #---------------------------------------------------------------------------- | |||
|
490 | def process_cmdline(argv,names=[],defaults={},usage=''): | |||
|
491 | """ Process command-line options and arguments. | |||
|
492 | ||||
|
493 | Arguments: | |||
|
494 | ||||
|
495 | - argv: list of arguments, typically sys.argv. | |||
|
496 | ||||
|
497 | - names: list of option names. See DPyGetOpt docs for details on options | |||
|
498 | syntax. | |||
|
499 | ||||
|
500 | - defaults: dict of default values. | |||
|
501 | ||||
|
502 | - usage: optional usage notice to print if a wrong argument is passed. | |||
|
503 | ||||
|
504 | Return a dict of options and a list of free arguments.""" | |||
|
505 | ||||
|
506 | getopt = DPyGetOpt.DPyGetOpt() | |||
|
507 | getopt.setIgnoreCase(0) | |||
|
508 | getopt.parseConfiguration(names) | |||
|
509 | ||||
|
510 | try: | |||
|
511 | getopt.processArguments(argv) | |||
|
512 | except: | |||
|
513 | print usage | |||
|
514 | warn(`sys.exc_value`,level=4) | |||
|
515 | ||||
|
516 | defaults.update(getopt.optionValues) | |||
|
517 | args = getopt.freeValues | |||
|
518 | ||||
|
519 | return defaults,args | |||
|
520 | ||||
|
521 | #---------------------------------------------------------------------------- | |||
|
522 | def optstr2types(ostr): | |||
|
523 | """Convert a string of option names to a dict of type mappings. | |||
|
524 | ||||
|
525 | optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'} | |||
|
526 | ||||
|
527 | This is used to get the types of all the options in a string formatted | |||
|
528 | with the conventions of DPyGetOpt. The 'type' None is used for options | |||
|
529 | which are strings (they need no further conversion). This function's main | |||
|
530 | use is to get a typemap for use with read_dict(). | |||
|
531 | """ | |||
|
532 | ||||
|
533 | typeconv = {None:'',int:'',float:''} | |||
|
534 | typemap = {'s':None,'i':int,'f':float} | |||
|
535 | opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)') | |||
|
536 | ||||
|
537 | for w in ostr.split(): | |||
|
538 | oname,alias,otype = opt_re.match(w).groups() | |||
|
539 | if otype == '' or alias == '!': # simple switches are integers too | |||
|
540 | otype = 'i' | |||
|
541 | typeconv[typemap[otype]] += oname + ' ' | |||
|
542 | return typeconv | |||
|
543 | ||||
|
544 | #---------------------------------------------------------------------------- | |||
|
545 | def read_dict(filename,type_conv=None,**opt): | |||
|
546 | ||||
|
547 | """Read a dictionary of key=value pairs from an input file, optionally | |||
|
548 | performing conversions on the resulting values. | |||
|
549 | ||||
|
550 | read_dict(filename,type_conv,**opt) -> dict | |||
|
551 | ||||
|
552 | Only one value per line is accepted, the format should be | |||
|
553 | # optional comments are ignored | |||
|
554 | key value\n | |||
|
555 | ||||
|
556 | Args: | |||
|
557 | ||||
|
558 | - type_conv: A dictionary specifying which keys need to be converted to | |||
|
559 | which types. By default all keys are read as strings. This dictionary | |||
|
560 | should have as its keys valid conversion functions for strings | |||
|
561 | (int,long,float,complex, or your own). The value for each key | |||
|
562 | (converter) should be a whitespace separated string containing the names | |||
|
563 | of all the entries in the file to be converted using that function. For | |||
|
564 | keys to be left alone, use None as the conversion function (only needed | |||
|
565 | with purge=1, see below). | |||
|
566 | ||||
|
567 | - opt: dictionary with extra options as below (default in parens) | |||
|
568 | ||||
|
569 | purge(0): if set to 1, all keys *not* listed in type_conv are purged out | |||
|
570 | of the dictionary to be returned. If purge is going to be used, the | |||
|
571 | set of keys to be left as strings also has to be explicitly specified | |||
|
572 | using the (non-existent) conversion function None. | |||
|
573 | ||||
|
574 | fs(None): field separator. This is the key/value separator to be used | |||
|
575 | when parsing the file. The None default means any whitespace [behavior | |||
|
576 | of string.split()]. | |||
|
577 | ||||
|
578 | strip(0): if 1, strip string values of leading/trailinig whitespace. | |||
|
579 | ||||
|
580 | warn(1): warning level if requested keys are not found in file. | |||
|
581 | - 0: silently ignore. | |||
|
582 | - 1: inform but proceed. | |||
|
583 | - 2: raise KeyError exception. | |||
|
584 | ||||
|
585 | no_empty(0): if 1, remove keys with whitespace strings as a value. | |||
|
586 | ||||
|
587 | unique([]): list of keys (or space separated string) which can't be | |||
|
588 | repeated. If one such key is found in the file, each new instance | |||
|
589 | overwrites the previous one. For keys not listed here, the behavior is | |||
|
590 | to make a list of all appearances. | |||
|
591 | ||||
|
592 | Example: | |||
|
593 | If the input file test.ini has: | |||
|
594 | i 3 | |||
|
595 | x 4.5 | |||
|
596 | y 5.5 | |||
|
597 | s hi ho | |||
|
598 | Then: | |||
|
599 | ||||
|
600 | >>> type_conv={int:'i',float:'x',None:'s'} | |||
|
601 | >>> read_dict('test.ini') | |||
|
602 | {'i': '3', 's': 'hi ho', 'x': '4.5', 'y': '5.5'} | |||
|
603 | >>> read_dict('test.ini',type_conv) | |||
|
604 | {'i': 3, 's': 'hi ho', 'x': 4.5, 'y': '5.5'} | |||
|
605 | >>> read_dict('test.ini',type_conv,purge=1) | |||
|
606 | {'i': 3, 's': 'hi ho', 'x': 4.5} | |||
|
607 | """ | |||
|
608 | ||||
|
609 | # starting config | |||
|
610 | opt.setdefault('purge',0) | |||
|
611 | opt.setdefault('fs',None) # field sep defaults to any whitespace | |||
|
612 | opt.setdefault('strip',0) | |||
|
613 | opt.setdefault('warn',1) | |||
|
614 | opt.setdefault('no_empty',0) | |||
|
615 | opt.setdefault('unique','') | |||
|
616 | if type(opt['unique']) in StringTypes: | |||
|
617 | unique_keys = qw(opt['unique']) | |||
|
618 | elif type(opt['unique']) in (types.TupleType,types.ListType): | |||
|
619 | unique_keys = opt['unique'] | |||
|
620 | else: | |||
|
621 | raise ValueError, 'Unique keys must be given as a string, List or Tuple' | |||
|
622 | ||||
|
623 | dict = {} | |||
|
624 | # first read in table of values as strings | |||
|
625 | file = open(filename,'r') | |||
|
626 | for line in file.readlines(): | |||
|
627 | line = line.strip() | |||
|
628 | if len(line) and line[0]=='#': continue | |||
|
629 | if len(line)>0: | |||
|
630 | lsplit = line.split(opt['fs'],1) | |||
|
631 | try: | |||
|
632 | key,val = lsplit | |||
|
633 | except ValueError: | |||
|
634 | key,val = lsplit[0],'' | |||
|
635 | key = key.strip() | |||
|
636 | if opt['strip']: val = val.strip() | |||
|
637 | if val == "''" or val == '""': val = '' | |||
|
638 | if opt['no_empty'] and (val=='' or val.isspace()): | |||
|
639 | continue | |||
|
640 | # if a key is found more than once in the file, build a list | |||
|
641 | # unless it's in the 'unique' list. In that case, last found in file | |||
|
642 | # takes precedence. User beware. | |||
|
643 | try: | |||
|
644 | if dict[key] and key in unique_keys: | |||
|
645 | dict[key] = val | |||
|
646 | elif type(dict[key]) is types.ListType: | |||
|
647 | dict[key].append(val) | |||
|
648 | else: | |||
|
649 | dict[key] = [dict[key],val] | |||
|
650 | except KeyError: | |||
|
651 | dict[key] = val | |||
|
652 | # purge if requested | |||
|
653 | if opt['purge']: | |||
|
654 | accepted_keys = qwflat(type_conv.values()) | |||
|
655 | for key in dict.keys(): | |||
|
656 | if key in accepted_keys: continue | |||
|
657 | del(dict[key]) | |||
|
658 | # now convert if requested | |||
|
659 | if type_conv==None: return dict | |||
|
660 | conversions = type_conv.keys() | |||
|
661 | try: conversions.remove(None) | |||
|
662 | except: pass | |||
|
663 | for convert in conversions: | |||
|
664 | for val in qw(type_conv[convert]): | |||
|
665 | try: | |||
|
666 | dict[val] = convert(dict[val]) | |||
|
667 | except KeyError,e: | |||
|
668 | if opt['warn'] == 0: | |||
|
669 | pass | |||
|
670 | elif opt['warn'] == 1: | |||
|
671 | print >>sys.stderr, 'Warning: key',val,\ | |||
|
672 | 'not found in file',filename | |||
|
673 | elif opt['warn'] == 2: | |||
|
674 | raise KeyError,e | |||
|
675 | else: | |||
|
676 | raise ValueError,'Warning level must be 0,1 or 2' | |||
|
677 | ||||
|
678 | return dict | |||
|
679 | ||||
|
680 | #---------------------------------------------------------------------------- | |||
|
681 | def flag_calls(func): | |||
|
682 | """Wrap a function to detect and flag when it gets called. | |||
|
683 | ||||
|
684 | This is a decorator which takes a function and wraps it in a function with | |||
|
685 | a 'called' attribute. wrapper.called is initialized to False. | |||
|
686 | ||||
|
687 | The wrapper.called attribute is set to False right before each call to the | |||
|
688 | wrapped function, so if the call fails it remains False. After the call | |||
|
689 | completes, wrapper.called is set to True and the output is returned. | |||
|
690 | ||||
|
691 | Testing for truth in wrapper.called allows you to determine if a call to | |||
|
692 | func() was attempted and succeeded.""" | |||
|
693 | ||||
|
694 | def wrapper(*args,**kw): | |||
|
695 | wrapper.called = False | |||
|
696 | out = func(*args,**kw) | |||
|
697 | wrapper.called = True | |||
|
698 | return out | |||
|
699 | ||||
|
700 | wrapper.called = False | |||
|
701 | wrapper.__doc__ = func.__doc__ | |||
|
702 | return wrapper | |||
|
703 | ||||
|
704 | #---------------------------------------------------------------------------- | |||
|
705 | class HomeDirError(Error): | |||
|
706 | pass | |||
|
707 | ||||
|
708 | def get_home_dir(): | |||
|
709 | """Return the closest possible equivalent to a 'home' directory. | |||
|
710 | ||||
|
711 | We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH. | |||
|
712 | ||||
|
713 | Currently only Posix and NT are implemented, a HomeDirError exception is | |||
|
714 | raised for all other OSes. """ #' | |||
|
715 | ||||
|
716 | try: | |||
|
717 | return os.environ['HOME'] | |||
|
718 | except KeyError: | |||
|
719 | if os.name == 'posix': | |||
|
720 | raise HomeDirError,'undefined $HOME, IPython can not proceed.' | |||
|
721 | elif os.name == 'nt': | |||
|
722 | # For some strange reason, win9x returns 'nt' for os.name. | |||
|
723 | try: | |||
|
724 | return os.path.join(os.environ['HOMEDRIVE'],os.environ['HOMEPATH']) | |||
|
725 | except: | |||
|
726 | try: | |||
|
727 | # Use the registry to get the 'My Documents' folder. | |||
|
728 | import _winreg as wreg | |||
|
729 | key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, | |||
|
730 | "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders") | |||
|
731 | homedir = wreg.QueryValueEx(key,'Personal')[0] | |||
|
732 | key.Close() | |||
|
733 | return homedir | |||
|
734 | except: | |||
|
735 | return 'C:\\' | |||
|
736 | elif os.name == 'dos': | |||
|
737 | # Desperate, may do absurd things in classic MacOS. May work under DOS. | |||
|
738 | return 'C:\\' | |||
|
739 | else: | |||
|
740 | raise HomeDirError,'support for your operating system not implemented.' | |||
|
741 | ||||
|
742 | #**************************************************************************** | |||
|
743 | # strings and text | |||
|
744 | ||||
|
745 | class LSString(str): | |||
|
746 | """String derivative with a special access attributes. | |||
|
747 | ||||
|
748 | These are normal strings, but with the special attributes: | |||
|
749 | ||||
|
750 | .l (or .list) : value as list (split on newlines). | |||
|
751 | .n (or .nlstr): original value (the string itself). | |||
|
752 | .s (or .spstr): value as whitespace-separated string. | |||
|
753 | ||||
|
754 | Any values which require transformations are computed only once and | |||
|
755 | cached. | |||
|
756 | ||||
|
757 | Such strings are very useful to efficiently interact with the shell, which | |||
|
758 | typically only understands whitespace-separated options for commands.""" | |||
|
759 | ||||
|
760 | def get_list(self): | |||
|
761 | try: | |||
|
762 | return self.__list | |||
|
763 | except AttributeError: | |||
|
764 | self.__list = self.split('\n') | |||
|
765 | return self.__list | |||
|
766 | ||||
|
767 | l = list = property(get_list) | |||
|
768 | ||||
|
769 | def get_spstr(self): | |||
|
770 | try: | |||
|
771 | return self.__spstr | |||
|
772 | except AttributeError: | |||
|
773 | self.__spstr = self.replace('\n',' ') | |||
|
774 | return self.__spstr | |||
|
775 | ||||
|
776 | s = spstr = property(get_spstr) | |||
|
777 | ||||
|
778 | def get_nlstr(self): | |||
|
779 | return self | |||
|
780 | ||||
|
781 | n = nlstr = property(get_nlstr) | |||
|
782 | ||||
|
783 | class SList(list): | |||
|
784 | """List derivative with a special access attributes. | |||
|
785 | ||||
|
786 | These are normal lists, but with the special attributes: | |||
|
787 | ||||
|
788 | .l (or .list) : value as list (the list itself). | |||
|
789 | .n (or .nlstr): value as a string, joined on newlines. | |||
|
790 | .s (or .spstr): value as a string, joined on spaces. | |||
|
791 | ||||
|
792 | Any values which require transformations are computed only once and | |||
|
793 | cached.""" | |||
|
794 | ||||
|
795 | def get_list(self): | |||
|
796 | return self | |||
|
797 | ||||
|
798 | l = list = property(get_list) | |||
|
799 | ||||
|
800 | def get_spstr(self): | |||
|
801 | try: | |||
|
802 | return self.__spstr | |||
|
803 | except AttributeError: | |||
|
804 | self.__spstr = ' '.join(self) | |||
|
805 | return self.__spstr | |||
|
806 | ||||
|
807 | s = spstr = property(get_spstr) | |||
|
808 | ||||
|
809 | def get_nlstr(self): | |||
|
810 | try: | |||
|
811 | return self.__nlstr | |||
|
812 | except AttributeError: | |||
|
813 | self.__nlstr = '\n'.join(self) | |||
|
814 | return self.__nlstr | |||
|
815 | ||||
|
816 | n = nlstr = property(get_nlstr) | |||
|
817 | ||||
|
818 | def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'): | |||
|
819 | """Take multiple lines of input. | |||
|
820 | ||||
|
821 | A list with each line of input as a separate element is returned when a | |||
|
822 | termination string is entered (defaults to a single '.'). Input can also | |||
|
823 | terminate via EOF (^D in Unix, ^Z-RET in Windows). | |||
|
824 | ||||
|
825 | Lines of input which end in \\ are joined into single entries (and a | |||
|
826 | secondary continuation prompt is issued as long as the user terminates | |||
|
827 | lines with \\). This allows entering very long strings which are still | |||
|
828 | meant to be treated as single entities. | |||
|
829 | """ | |||
|
830 | ||||
|
831 | try: | |||
|
832 | if header: | |||
|
833 | header += '\n' | |||
|
834 | lines = [raw_input(header + ps1)] | |||
|
835 | except EOFError: | |||
|
836 | return [] | |||
|
837 | terminate = [terminate_str] | |||
|
838 | try: | |||
|
839 | while lines[-1:] != terminate: | |||
|
840 | new_line = raw_input(ps1) | |||
|
841 | while new_line.endswith('\\'): | |||
|
842 | new_line = new_line[:-1] + raw_input(ps2) | |||
|
843 | lines.append(new_line) | |||
|
844 | ||||
|
845 | return lines[:-1] # don't return the termination command | |||
|
846 | except EOFError: | |||
|
847 | ||||
|
848 | return lines | |||
|
849 | ||||
|
850 | #---------------------------------------------------------------------------- | |||
|
851 | def raw_input_ext(prompt='', ps2='... '): | |||
|
852 | """Similar to raw_input(), but accepts extended lines if input ends with \\.""" | |||
|
853 | ||||
|
854 | line = raw_input(prompt) | |||
|
855 | while line.endswith('\\'): | |||
|
856 | line = line[:-1] + raw_input(ps2) | |||
|
857 | return line | |||
|
858 | ||||
|
859 | #---------------------------------------------------------------------------- | |||
|
860 | def ask_yes_no(prompt,default=None): | |||
|
861 | """Asks a question and returns an integer 1/0 (y/n) answer. | |||
|
862 | ||||
|
863 | If default is given (one of 'y','n'), it is used if the user input is | |||
|
864 | empty. Otherwise the question is repeated until an answer is given. | |||
|
865 | If EOF occurs 20 times consecutively, the default answer is assumed, | |||
|
866 | or if there is no default, an exception is raised to prevent infinite | |||
|
867 | loops. | |||
|
868 | ||||
|
869 | Valid answers are: y/yes/n/no (match is not case sensitive).""" | |||
|
870 | ||||
|
871 | answers = {'y':1,'n':0,'yes':1,'no':0} | |||
|
872 | ans = None | |||
|
873 | eofs, max_eofs = 0, 20 | |||
|
874 | while ans not in answers.keys(): | |||
|
875 | try: | |||
|
876 | ans = raw_input(prompt+' ').lower() | |||
|
877 | if not ans: # response was an empty string | |||
|
878 | ans = default | |||
|
879 | eofs = 0 | |||
|
880 | except (EOFError,KeyboardInterrupt): | |||
|
881 | eofs = eofs + 1 | |||
|
882 | if eofs >= max_eofs: | |||
|
883 | if default in answers.keys(): | |||
|
884 | ans = default | |||
|
885 | else: | |||
|
886 | raise | |||
|
887 | ||||
|
888 | return answers[ans] | |||
|
889 | ||||
|
890 | #---------------------------------------------------------------------------- | |||
|
891 | class EvalDict: | |||
|
892 | """ | |||
|
893 | Emulate a dict which evaluates its contents in the caller's frame. | |||
|
894 | ||||
|
895 | Usage: | |||
|
896 | >>>number = 19 | |||
|
897 | >>>text = "python" | |||
|
898 | >>>print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict() | |||
|
899 | """ | |||
|
900 | ||||
|
901 | # This version is due to sismex01@hebmex.com on c.l.py, and is basically a | |||
|
902 | # modified (shorter) version of: | |||
|
903 | # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by | |||
|
904 | # Skip Montanaro (skip@pobox.com). | |||
|
905 | ||||
|
906 | def __getitem__(self, name): | |||
|
907 | frame = sys._getframe(1) | |||
|
908 | return eval(name, frame.f_globals, frame.f_locals) | |||
|
909 | ||||
|
910 | EvalString = EvalDict # for backwards compatibility | |||
|
911 | #---------------------------------------------------------------------------- | |||
|
912 | def qw(words,flat=0,sep=None,maxsplit=-1): | |||
|
913 | """Similar to Perl's qw() operator, but with some more options. | |||
|
914 | ||||
|
915 | qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit) | |||
|
916 | ||||
|
917 | words can also be a list itself, and with flat=1, the output will be | |||
|
918 | recursively flattened. Examples: | |||
|
919 | ||||
|
920 | >>> qw('1 2') | |||
|
921 | ['1', '2'] | |||
|
922 | >>> qw(['a b','1 2',['m n','p q']]) | |||
|
923 | [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]] | |||
|
924 | >>> qw(['a b','1 2',['m n','p q']],flat=1) | |||
|
925 | ['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] """ | |||
|
926 | ||||
|
927 | if type(words) in StringTypes: | |||
|
928 | return [word.strip() for word in words.split(sep,maxsplit) | |||
|
929 | if word and not word.isspace() ] | |||
|
930 | if flat: | |||
|
931 | return flatten(map(qw,words,[1]*len(words))) | |||
|
932 | return map(qw,words) | |||
|
933 | ||||
|
934 | #---------------------------------------------------------------------------- | |||
|
935 | def qwflat(words,sep=None,maxsplit=-1): | |||
|
936 | """Calls qw(words) in flat mode. It's just a convenient shorthand.""" | |||
|
937 | return qw(words,1,sep,maxsplit) | |||
|
938 | ||||
|
939 | #----------------------------------------------------------------------------- | |||
|
940 | def list_strings(arg): | |||
|
941 | """Always return a list of strings, given a string or list of strings | |||
|
942 | as input.""" | |||
|
943 | ||||
|
944 | if type(arg) in StringTypes: return [arg] | |||
|
945 | else: return arg | |||
|
946 | ||||
|
947 | #---------------------------------------------------------------------------- | |||
|
948 | def grep(pat,list,case=1): | |||
|
949 | """Simple minded grep-like function. | |||
|
950 | grep(pat,list) returns occurrences of pat in list, None on failure. | |||
|
951 | ||||
|
952 | It only does simple string matching, with no support for regexps. Use the | |||
|
953 | option case=0 for case-insensitive matching.""" | |||
|
954 | ||||
|
955 | # This is pretty crude. At least it should implement copying only references | |||
|
956 | # to the original data in case it's big. Now it copies the data for output. | |||
|
957 | out=[] | |||
|
958 | if case: | |||
|
959 | for term in list: | |||
|
960 | if term.find(pat)>-1: out.append(term) | |||
|
961 | else: | |||
|
962 | lpat=pat.lower() | |||
|
963 | for term in list: | |||
|
964 | if term.lower().find(lpat)>-1: out.append(term) | |||
|
965 | ||||
|
966 | if len(out): return out | |||
|
967 | else: return None | |||
|
968 | ||||
|
969 | #---------------------------------------------------------------------------- | |||
|
970 | def dgrep(pat,*opts): | |||
|
971 | """Return grep() on dir()+dir(__builtins__). | |||
|
972 | ||||
|
973 | A very common use of grep() when working interactively.""" | |||
|
974 | ||||
|
975 | return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts) | |||
|
976 | ||||
|
977 | #---------------------------------------------------------------------------- | |||
|
978 | def idgrep(pat): | |||
|
979 | """Case-insensitive dgrep()""" | |||
|
980 | ||||
|
981 | return dgrep(pat,0) | |||
|
982 | ||||
|
983 | #---------------------------------------------------------------------------- | |||
|
984 | def igrep(pat,list): | |||
|
985 | """Synonym for case-insensitive grep.""" | |||
|
986 | ||||
|
987 | return grep(pat,list,case=0) | |||
|
988 | ||||
|
989 | #---------------------------------------------------------------------------- | |||
|
990 | def indent(str,nspaces=4,ntabs=0): | |||
|
991 | """Indent a string a given number of spaces or tabstops. | |||
|
992 | ||||
|
993 | indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces. | |||
|
994 | """ | |||
|
995 | if str is None: | |||
|
996 | return | |||
|
997 | ind = '\t'*ntabs+' '*nspaces | |||
|
998 | outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind)) | |||
|
999 | if outstr.endswith(os.linesep+ind): | |||
|
1000 | return outstr[:-len(ind)] | |||
|
1001 | else: | |||
|
1002 | return outstr | |||
|
1003 | ||||
|
1004 | #----------------------------------------------------------------------------- | |||
|
1005 | def native_line_ends(filename,backup=1): | |||
|
1006 | """Convert (in-place) a file to line-ends native to the current OS. | |||
|
1007 | ||||
|
1008 | If the optional backup argument is given as false, no backup of the | |||
|
1009 | original file is left. """ | |||
|
1010 | ||||
|
1011 | backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'} | |||
|
1012 | ||||
|
1013 | bak_filename = filename + backup_suffixes[os.name] | |||
|
1014 | ||||
|
1015 | original = open(filename).read() | |||
|
1016 | shutil.copy2(filename,bak_filename) | |||
|
1017 | try: | |||
|
1018 | new = open(filename,'wb') | |||
|
1019 | new.write(os.linesep.join(original.splitlines())) | |||
|
1020 | new.write(os.linesep) # ALWAYS put an eol at the end of the file | |||
|
1021 | new.close() | |||
|
1022 | except: | |||
|
1023 | os.rename(bak_filename,filename) | |||
|
1024 | if not backup: | |||
|
1025 | try: | |||
|
1026 | os.remove(bak_filename) | |||
|
1027 | except: | |||
|
1028 | pass | |||
|
1029 | ||||
|
1030 | #---------------------------------------------------------------------------- | |||
|
1031 | def get_pager_cmd(pager_cmd = None): | |||
|
1032 | """Return a pager command. | |||
|
1033 | ||||
|
1034 | Makes some attempts at finding an OS-correct one.""" | |||
|
1035 | ||||
|
1036 | if os.name == 'posix': | |||
|
1037 | default_pager_cmd = 'less -r' # -r for color control sequences | |||
|
1038 | elif os.name in ['nt','dos']: | |||
|
1039 | default_pager_cmd = 'type' | |||
|
1040 | ||||
|
1041 | if pager_cmd is None: | |||
|
1042 | try: | |||
|
1043 | pager_cmd = os.environ['PAGER'] | |||
|
1044 | except: | |||
|
1045 | pager_cmd = default_pager_cmd | |||
|
1046 | return pager_cmd | |||
|
1047 | ||||
|
1048 | #----------------------------------------------------------------------------- | |||
|
1049 | def get_pager_start(pager,start): | |||
|
1050 | """Return the string for paging files with an offset. | |||
|
1051 | ||||
|
1052 | This is the '+N' argument which less and more (under Unix) accept. | |||
|
1053 | """ | |||
|
1054 | ||||
|
1055 | if pager in ['less','more']: | |||
|
1056 | if start: | |||
|
1057 | start_string = '+' + str(start) | |||
|
1058 | else: | |||
|
1059 | start_string = '' | |||
|
1060 | else: | |||
|
1061 | start_string = '' | |||
|
1062 | return start_string | |||
|
1063 | ||||
|
1064 | #---------------------------------------------------------------------------- | |||
|
1065 | def page_dumb(strng,start=0,screen_lines=25): | |||
|
1066 | """Very dumb 'pager' in Python, for when nothing else works. | |||
|
1067 | ||||
|
1068 | Only moves forward, same interface as page(), except for pager_cmd and | |||
|
1069 | mode.""" | |||
|
1070 | ||||
|
1071 | out_ln = strng.splitlines()[start:] | |||
|
1072 | screens = chop(out_ln,screen_lines-1) | |||
|
1073 | if len(screens) == 1: | |||
|
1074 | print >>Term.cout, os.linesep.join(screens[0]) | |||
|
1075 | else: | |||
|
1076 | for scr in screens[0:-1]: | |||
|
1077 | print >>Term.cout, os.linesep.join(scr) | |||
|
1078 | ans = raw_input('---Return to continue, q to quit--- ') | |||
|
1079 | if ans.lower().startswith('q'): | |||
|
1080 | return | |||
|
1081 | print >>Term.cout, os.linesep.join(screens[-1]) | |||
|
1082 | ||||
|
1083 | #---------------------------------------------------------------------------- | |||
|
1084 | def page(strng,start=0,screen_lines=0,pager_cmd = None): | |||
|
1085 | """Print a string, piping through a pager after a certain length. | |||
|
1086 | ||||
|
1087 | The screen_lines parameter specifies the number of *usable* lines of your | |||
|
1088 | terminal screen (total lines minus lines you need to reserve to show other | |||
|
1089 | information). | |||
|
1090 | ||||
|
1091 | If you set screen_lines to a number <=0, page() will try to auto-determine | |||
|
1092 | your screen size and will only use up to (screen_size+screen_lines) for | |||
|
1093 | printing, paging after that. That is, if you want auto-detection but need | |||
|
1094 | to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for | |||
|
1095 | auto-detection without any lines reserved simply use screen_lines = 0. | |||
|
1096 | ||||
|
1097 | If a string won't fit in the allowed lines, it is sent through the | |||
|
1098 | specified pager command. If none given, look for PAGER in the environment, | |||
|
1099 | and ultimately default to less. | |||
|
1100 | ||||
|
1101 | If no system pager works, the string is sent through a 'dumb pager' | |||
|
1102 | written in python, very simplistic. | |||
|
1103 | """ | |||
|
1104 | ||||
|
1105 | # Ugly kludge, but calling curses.initscr() flat out crashes in emacs | |||
|
1106 | TERM = os.environ.get('TERM','dumb') | |||
|
1107 | if TERM in ['dumb','emacs'] and os.name != 'nt': | |||
|
1108 | print strng | |||
|
1109 | return | |||
|
1110 | # chop off the topmost part of the string we don't want to see | |||
|
1111 | str_lines = strng.split(os.linesep)[start:] | |||
|
1112 | str_toprint = os.linesep.join(str_lines) | |||
|
1113 | num_newlines = len(str_lines) | |||
|
1114 | len_str = len(str_toprint) | |||
|
1115 | ||||
|
1116 | # Dumb heuristics to guesstimate number of on-screen lines the string | |||
|
1117 | # takes. Very basic, but good enough for docstrings in reasonable | |||
|
1118 | # terminals. If someone later feels like refining it, it's not hard. | |||
|
1119 | numlines = max(num_newlines,int(len_str/80)+1) | |||
|
1120 | ||||
|
1121 | screen_lines_def = 25 # default value if we can't auto-determine | |||
|
1122 | ||||
|
1123 | # auto-determine screen size | |||
|
1124 | if screen_lines <= 0: | |||
|
1125 | if TERM=='xterm': | |||
|
1126 | try: | |||
|
1127 | import curses | |||
|
1128 | if hasattr(curses,'initscr'): | |||
|
1129 | use_curses = 1 | |||
|
1130 | else: | |||
|
1131 | use_curses = 0 | |||
|
1132 | except ImportError: | |||
|
1133 | use_curses = 0 | |||
|
1134 | else: | |||
|
1135 | # curses causes problems on many terminals other than xterm. | |||
|
1136 | use_curses = 0 | |||
|
1137 | if use_curses: | |||
|
1138 | scr = curses.initscr() | |||
|
1139 | screen_lines_real,screen_cols = scr.getmaxyx() | |||
|
1140 | curses.endwin() | |||
|
1141 | screen_lines += screen_lines_real | |||
|
1142 | #print '***Screen size:',screen_lines_real,'lines x',\ | |||
|
1143 | #screen_cols,'columns.' # dbg | |||
|
1144 | else: | |||
|
1145 | screen_lines += screen_lines_def | |||
|
1146 | ||||
|
1147 | #print 'numlines',numlines,'screenlines',screen_lines # dbg | |||
|
1148 | if numlines <= screen_lines : | |||
|
1149 | #print '*** normal print' # dbg | |||
|
1150 | print >>Term.cout, str_toprint | |||
|
1151 | else: | |||
|
1152 | # Try to open pager and default to internal one if that fails. | |||
|
1153 | # All failure modes are tagged as 'retval=1', to match the return | |||
|
1154 | # value of a failed system command. If any intermediate attempt | |||
|
1155 | # sets retval to 1, at the end we resort to our own page_dumb() pager. | |||
|
1156 | pager_cmd = get_pager_cmd(pager_cmd) | |||
|
1157 | pager_cmd += ' ' + get_pager_start(pager_cmd,start) | |||
|
1158 | if os.name == 'nt': | |||
|
1159 | if pager_cmd.startswith('type'): | |||
|
1160 | # The default WinXP 'type' command is failing on complex strings. | |||
|
1161 | retval = 1 | |||
|
1162 | else: | |||
|
1163 | tmpname = tempfile.mktemp('.txt') | |||
|
1164 | tmpfile = file(tmpname,'wt') | |||
|
1165 | tmpfile.write(strng) | |||
|
1166 | tmpfile.close() | |||
|
1167 | cmd = "%s < %s" % (pager_cmd,tmpname) | |||
|
1168 | if os.system(cmd): | |||
|
1169 | retval = 1 | |||
|
1170 | else: | |||
|
1171 | retval = None | |||
|
1172 | os.remove(tmpname) | |||
|
1173 | else: | |||
|
1174 | try: | |||
|
1175 | retval = None | |||
|
1176 | # if I use popen4, things hang. No idea why. | |||
|
1177 | #pager,shell_out = os.popen4(pager_cmd) | |||
|
1178 | pager = os.popen(pager_cmd,'w') | |||
|
1179 | pager.write(strng) | |||
|
1180 | pager.close() | |||
|
1181 | retval = pager.close() # success returns None | |||
|
1182 | except IOError,msg: # broken pipe when user quits | |||
|
1183 | if msg.args == (32,'Broken pipe'): | |||
|
1184 | retval = None | |||
|
1185 | else: | |||
|
1186 | retval = 1 | |||
|
1187 | except OSError: | |||
|
1188 | # Other strange problems, sometimes seen in Win2k/cygwin | |||
|
1189 | retval = 1 | |||
|
1190 | if retval is not None: | |||
|
1191 | page_dumb(strng,screen_lines=screen_lines) | |||
|
1192 | ||||
|
1193 | #---------------------------------------------------------------------------- | |||
|
1194 | def page_file(fname,start = 0, pager_cmd = None): | |||
|
1195 | """Page a file, using an optional pager command and starting line. | |||
|
1196 | """ | |||
|
1197 | ||||
|
1198 | pager_cmd = get_pager_cmd(pager_cmd) | |||
|
1199 | pager_cmd += ' ' + get_pager_start(pager_cmd,start) | |||
|
1200 | ||||
|
1201 | try: | |||
|
1202 | if os.environ['TERM'] in ['emacs','dumb']: | |||
|
1203 | raise EnvironmentError | |||
|
1204 | xsys(pager_cmd + ' ' + fname) | |||
|
1205 | except: | |||
|
1206 | try: | |||
|
1207 | if start > 0: | |||
|
1208 | start -= 1 | |||
|
1209 | page(open(fname).read(),start) | |||
|
1210 | except: | |||
|
1211 | print 'Unable to show file',`fname` | |||
|
1212 | ||||
|
1213 | #---------------------------------------------------------------------------- | |||
|
1214 | def snip_print(str,width = 75,print_full = 0,header = ''): | |||
|
1215 | """Print a string snipping the midsection to fit in width. | |||
|
1216 | ||||
|
1217 | print_full: mode control: | |||
|
1218 | - 0: only snip long strings | |||
|
1219 | - 1: send to page() directly. | |||
|
1220 | - 2: snip long strings and ask for full length viewing with page() | |||
|
1221 | Return 1 if snipping was necessary, 0 otherwise.""" | |||
|
1222 | ||||
|
1223 | if print_full == 1: | |||
|
1224 | page(header+str) | |||
|
1225 | return 0 | |||
|
1226 | ||||
|
1227 | print header, | |||
|
1228 | if len(str) < width: | |||
|
1229 | print str | |||
|
1230 | snip = 0 | |||
|
1231 | else: | |||
|
1232 | whalf = int((width -5)/2) | |||
|
1233 | print str[:whalf] + ' <...> ' + str[-whalf:] | |||
|
1234 | snip = 1 | |||
|
1235 | if snip and print_full == 2: | |||
|
1236 | if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y': | |||
|
1237 | page(str) | |||
|
1238 | return snip | |||
|
1239 | ||||
|
1240 | #**************************************************************************** | |||
|
1241 | # lists, dicts and structures | |||
|
1242 | ||||
|
1243 | def belong(candidates,checklist): | |||
|
1244 | """Check whether a list of items appear in a given list of options. | |||
|
1245 | ||||
|
1246 | Returns a list of 1 and 0, one for each candidate given.""" | |||
|
1247 | ||||
|
1248 | return [x in checklist for x in candidates] | |||
|
1249 | ||||
|
1250 | #---------------------------------------------------------------------------- | |||
|
1251 | def uniq_stable(elems): | |||
|
1252 | """uniq_stable(elems) -> list | |||
|
1253 | ||||
|
1254 | Return from an iterable, a list of all the unique elements in the input, | |||
|
1255 | but maintaining the order in which they first appear. | |||
|
1256 | ||||
|
1257 | A naive solution to this problem which just makes a dictionary with the | |||
|
1258 | elements as keys fails to respect the stability condition, since | |||
|
1259 | dictionaries are unsorted by nature. | |||
|
1260 | ||||
|
1261 | Note: All elements in the input must be valid dictionary keys for this | |||
|
1262 | routine to work, as it internally uses a dictionary for efficiency | |||
|
1263 | reasons.""" | |||
|
1264 | ||||
|
1265 | unique = [] | |||
|
1266 | unique_dict = {} | |||
|
1267 | for nn in elems: | |||
|
1268 | if nn not in unique_dict: | |||
|
1269 | unique.append(nn) | |||
|
1270 | unique_dict[nn] = None | |||
|
1271 | return unique | |||
|
1272 | ||||
|
1273 | #---------------------------------------------------------------------------- | |||
|
1274 | class NLprinter: | |||
|
1275 | """Print an arbitrarily nested list, indicating index numbers. | |||
|
1276 | ||||
|
1277 | An instance of this class called nlprint is available and callable as a | |||
|
1278 | function. | |||
|
1279 | ||||
|
1280 | nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent' | |||
|
1281 | and using 'sep' to separate the index from the value. """ | |||
|
1282 | ||||
|
1283 | def __init__(self): | |||
|
1284 | self.depth = 0 | |||
|
1285 | ||||
|
1286 | def __call__(self,lst,pos='',**kw): | |||
|
1287 | """Prints the nested list numbering levels.""" | |||
|
1288 | kw.setdefault('indent',' ') | |||
|
1289 | kw.setdefault('sep',': ') | |||
|
1290 | kw.setdefault('start',0) | |||
|
1291 | kw.setdefault('stop',len(lst)) | |||
|
1292 | # we need to remove start and stop from kw so they don't propagate | |||
|
1293 | # into a recursive call for a nested list. | |||
|
1294 | start = kw['start']; del kw['start'] | |||
|
1295 | stop = kw['stop']; del kw['stop'] | |||
|
1296 | if self.depth == 0 and 'header' in kw.keys(): | |||
|
1297 | print kw['header'] | |||
|
1298 | ||||
|
1299 | for idx in range(start,stop): | |||
|
1300 | elem = lst[idx] | |||
|
1301 | if type(elem)==type([]): | |||
|
1302 | self.depth += 1 | |||
|
1303 | self.__call__(elem,itpl('$pos$idx,'),**kw) | |||
|
1304 | self.depth -= 1 | |||
|
1305 | else: | |||
|
1306 | printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem') | |||
|
1307 | ||||
|
1308 | nlprint = NLprinter() | |||
|
1309 | #---------------------------------------------------------------------------- | |||
|
1310 | def all_belong(candidates,checklist): | |||
|
1311 | """Check whether a list of items ALL appear in a given list of options. | |||
|
1312 | ||||
|
1313 | Returns a single 1 or 0 value.""" | |||
|
1314 | ||||
|
1315 | return 1-(0 in [x in checklist for x in candidates]) | |||
|
1316 | ||||
|
1317 | #---------------------------------------------------------------------------- | |||
|
1318 | def sort_compare(lst1,lst2,inplace = 1): | |||
|
1319 | """Sort and compare two lists. | |||
|
1320 | ||||
|
1321 | By default it does it in place, thus modifying the lists. Use inplace = 0 | |||
|
1322 | to avoid that (at the cost of temporary copy creation).""" | |||
|
1323 | if not inplace: | |||
|
1324 | lst1 = lst1[:] | |||
|
1325 | lst2 = lst2[:] | |||
|
1326 | lst1.sort(); lst2.sort() | |||
|
1327 | return lst1 == lst2 | |||
|
1328 | ||||
|
1329 | #---------------------------------------------------------------------------- | |||
|
1330 | def mkdict(**kwargs): | |||
|
1331 | """Return a dict from a keyword list. | |||
|
1332 | ||||
|
1333 | It's just syntactic sugar for making ditcionary creation more convenient: | |||
|
1334 | # the standard way | |||
|
1335 | >>>data = { 'red' : 1, 'green' : 2, 'blue' : 3 } | |||
|
1336 | # a cleaner way | |||
|
1337 | >>>data = dict(red=1, green=2, blue=3) | |||
|
1338 | ||||
|
1339 | If you need more than this, look at the Struct() class.""" | |||
|
1340 | ||||
|
1341 | return kwargs | |||
|
1342 | ||||
|
1343 | #---------------------------------------------------------------------------- | |||
|
1344 | def list2dict(lst): | |||
|
1345 | """Takes a list of (key,value) pairs and turns it into a dict.""" | |||
|
1346 | ||||
|
1347 | dic = {} | |||
|
1348 | for k,v in lst: dic[k] = v | |||
|
1349 | return dic | |||
|
1350 | ||||
|
1351 | #---------------------------------------------------------------------------- | |||
|
1352 | def list2dict2(lst,default=''): | |||
|
1353 | """Takes a list and turns it into a dict. | |||
|
1354 | Much slower than list2dict, but more versatile. This version can take | |||
|
1355 | lists with sublists of arbitrary length (including sclars).""" | |||
|
1356 | ||||
|
1357 | dic = {} | |||
|
1358 | for elem in lst: | |||
|
1359 | if type(elem) in (types.ListType,types.TupleType): | |||
|
1360 | size = len(elem) | |||
|
1361 | if size == 0: | |||
|
1362 | pass | |||
|
1363 | elif size == 1: | |||
|
1364 | dic[elem] = default | |||
|
1365 | else: | |||
|
1366 | k,v = elem[0], elem[1:] | |||
|
1367 | if len(v) == 1: v = v[0] | |||
|
1368 | dic[k] = v | |||
|
1369 | else: | |||
|
1370 | dic[elem] = default | |||
|
1371 | return dic | |||
|
1372 | ||||
|
1373 | #---------------------------------------------------------------------------- | |||
|
1374 | def flatten(seq): | |||
|
1375 | """Flatten a list of lists (NOT recursive, only works for 2d lists).""" | |||
|
1376 | ||||
|
1377 | # bug in python??? (YES. Fixed in 2.2, let's leave the kludgy fix in). | |||
|
1378 | ||||
|
1379 | # if the x=0 isn't made, a *global* variable x is left over after calling | |||
|
1380 | # this function, with the value of the last element in the return | |||
|
1381 | # list. This does seem like a bug big time to me. | |||
|
1382 | ||||
|
1383 | # the problem is fixed with the x=0, which seems to force the creation of | |||
|
1384 | # a local name | |||
|
1385 | ||||
|
1386 | x = 0 | |||
|
1387 | return [x for subseq in seq for x in subseq] | |||
|
1388 | ||||
|
1389 | #---------------------------------------------------------------------------- | |||
|
1390 | def get_slice(seq,start=0,stop=None,step=1): | |||
|
1391 | """Get a slice of a sequence with variable step. Specify start,stop,step.""" | |||
|
1392 | if stop == None: | |||
|
1393 | stop = len(seq) | |||
|
1394 | item = lambda i: seq[i] | |||
|
1395 | return map(item,xrange(start,stop,step)) | |||
|
1396 | ||||
|
1397 | #---------------------------------------------------------------------------- | |||
|
1398 | def chop(seq,size): | |||
|
1399 | """Chop a sequence into chunks of the given size.""" | |||
|
1400 | chunk = lambda i: seq[i:i+size] | |||
|
1401 | return map(chunk,xrange(0,len(seq),size)) | |||
|
1402 | ||||
|
1403 | #---------------------------------------------------------------------------- | |||
|
1404 | def with(object, **args): | |||
|
1405 | """Set multiple attributes for an object, similar to Pascal's with. | |||
|
1406 | ||||
|
1407 | Example: | |||
|
1408 | with(jim, | |||
|
1409 | born = 1960, | |||
|
1410 | haircolour = 'Brown', | |||
|
1411 | eyecolour = 'Green') | |||
|
1412 | ||||
|
1413 | Credit: Greg Ewing, in | |||
|
1414 | http://mail.python.org/pipermail/python-list/2001-May/040703.html""" | |||
|
1415 | ||||
|
1416 | object.__dict__.update(args) | |||
|
1417 | ||||
|
1418 | #---------------------------------------------------------------------------- | |||
|
1419 | def setattr_list(obj,alist,nspace = None): | |||
|
1420 | """Set a list of attributes for an object taken from a namespace. | |||
|
1421 | ||||
|
1422 | setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in | |||
|
1423 | alist with their values taken from nspace, which must be a dict (something | |||
|
1424 | like locals() will often do) If nspace isn't given, locals() of the | |||
|
1425 | *caller* is used, so in most cases you can omit it. | |||
|
1426 | ||||
|
1427 | Note that alist can be given as a string, which will be automatically | |||
|
1428 | split into a list on whitespace. If given as a list, it must be a list of | |||
|
1429 | *strings* (the variable names themselves), not of variables.""" | |||
|
1430 | ||||
|
1431 | # this grabs the local variables from the *previous* call frame -- that is | |||
|
1432 | # the locals from the function that called setattr_list(). | |||
|
1433 | # - snipped from weave.inline() | |||
|
1434 | if nspace is None: | |||
|
1435 | call_frame = sys._getframe().f_back | |||
|
1436 | nspace = call_frame.f_locals | |||
|
1437 | ||||
|
1438 | if type(alist) in StringTypes: | |||
|
1439 | alist = alist.split() | |||
|
1440 | for attr in alist: | |||
|
1441 | val = eval(attr,nspace) | |||
|
1442 | setattr(obj,attr,val) | |||
|
1443 | ||||
|
1444 | #---------------------------------------------------------------------------- | |||
|
1445 | def getattr_list(obj,alist,*args): | |||
|
1446 | """getattr_list(obj,alist[, default]) -> attribute list. | |||
|
1447 | ||||
|
1448 | Get a list of named attributes for an object. When a default argument is | |||
|
1449 | given, it is returned when the attribute doesn't exist; without it, an | |||
|
1450 | exception is raised in that case. | |||
|
1451 | ||||
|
1452 | Note that alist can be given as a string, which will be automatically | |||
|
1453 | split into a list on whitespace. If given as a list, it must be a list of | |||
|
1454 | *strings* (the variable names themselves), not of variables.""" | |||
|
1455 | ||||
|
1456 | if type(alist) in StringTypes: | |||
|
1457 | alist = alist.split() | |||
|
1458 | if args: | |||
|
1459 | if len(args)==1: | |||
|
1460 | default = args[0] | |||
|
1461 | return map(lambda attr: getattr(obj,attr,default),alist) | |||
|
1462 | else: | |||
|
1463 | raise ValueError,'getattr_list() takes only one optional argument' | |||
|
1464 | else: | |||
|
1465 | return map(lambda attr: getattr(obj,attr),alist) | |||
|
1466 | ||||
|
1467 | #---------------------------------------------------------------------------- | |||
|
1468 | def map_method(method,object_list,*argseq,**kw): | |||
|
1469 | """map_method(method,object_list,*args,**kw) -> list | |||
|
1470 | ||||
|
1471 | Return a list of the results of applying the methods to the items of the | |||
|
1472 | argument sequence(s). If more than one sequence is given, the method is | |||
|
1473 | called with an argument list consisting of the corresponding item of each | |||
|
1474 | sequence. All sequences must be of the same length. | |||
|
1475 | ||||
|
1476 | Keyword arguments are passed verbatim to all objects called. | |||
|
1477 | ||||
|
1478 | This is Python code, so it's not nearly as fast as the builtin map().""" | |||
|
1479 | ||||
|
1480 | out_list = [] | |||
|
1481 | idx = 0 | |||
|
1482 | for object in object_list: | |||
|
1483 | try: | |||
|
1484 | handler = getattr(object, method) | |||
|
1485 | except AttributeError: | |||
|
1486 | out_list.append(None) | |||
|
1487 | else: | |||
|
1488 | if argseq: | |||
|
1489 | args = map(lambda lst:lst[idx],argseq) | |||
|
1490 | #print 'ob',object,'hand',handler,'ar',args # dbg | |||
|
1491 | out_list.append(handler(args,**kw)) | |||
|
1492 | else: | |||
|
1493 | out_list.append(handler(**kw)) | |||
|
1494 | idx += 1 | |||
|
1495 | return out_list | |||
|
1496 | ||||
|
1497 | #---------------------------------------------------------------------------- | |||
|
1498 | # Proposed popitem() extension, written as a method | |||
|
1499 | ||||
|
1500 | class NotGiven: pass | |||
|
1501 | ||||
|
1502 | def popkey(dct,key,default=NotGiven): | |||
|
1503 | """Return dct[key] and delete dct[key]. | |||
|
1504 | ||||
|
1505 | If default is given, return it if dct[key] doesn't exist, otherwise raise | |||
|
1506 | KeyError. """ | |||
|
1507 | ||||
|
1508 | try: | |||
|
1509 | val = dct[key] | |||
|
1510 | except KeyError: | |||
|
1511 | if default is NotGiven: | |||
|
1512 | raise | |||
|
1513 | else: | |||
|
1514 | return default | |||
|
1515 | else: | |||
|
1516 | del dct[key] | |||
|
1517 | return val | |||
|
1518 | #*************************** end of file <genutils.py> ********************** | |||
|
1519 |
@@ -0,0 +1,72 | |||||
|
1 | """hooks for IPython. | |||
|
2 | ||||
|
3 | In Python, it is possible to overwrite any method of any object if you really | |||
|
4 | want to. But IPython exposes a few 'hooks', methods which are _designed_ to | |||
|
5 | be overwritten by users for customization purposes. This module defines the | |||
|
6 | default versions of all such hooks, which get used by IPython if not | |||
|
7 | overridden by the user. | |||
|
8 | ||||
|
9 | hooks are simple functions, but they should be declared with 'self' as their | |||
|
10 | first argument, because when activated they are registered into IPython as | |||
|
11 | instance methods. The self argument will be the IPython running instance | |||
|
12 | itself, so hooks have full access to the entire IPython object. | |||
|
13 | ||||
|
14 | If you wish to define a new hook and activate it, you need to put the | |||
|
15 | necessary code into a python file which can be either imported or execfile()'d | |||
|
16 | from within your ipythonrc configuration. | |||
|
17 | ||||
|
18 | For example, suppose that you have a module called 'myiphooks' in your | |||
|
19 | PYTHONPATH, which contains the following definition: | |||
|
20 | ||||
|
21 | import os | |||
|
22 | def calljed(self,filename, linenum): | |||
|
23 | "My editor hook calls the jed editor directly." | |||
|
24 | print "Calling my own editor, jed ..." | |||
|
25 | os.system('jed +%d %s' % (linenum,filename)) | |||
|
26 | ||||
|
27 | You can then execute the following line of code to make it the new IPython | |||
|
28 | editor hook, after having imported 'myiphooks': | |||
|
29 | ||||
|
30 | ip_set_hook('editor',myiphooks.calljed) | |||
|
31 | ||||
|
32 | The ip_set_hook function is put by IPython into the builtin namespace, so it | |||
|
33 | is always available from all running code. | |||
|
34 | ||||
|
35 | $Id: hooks.py 535 2005-03-02 08:42:25Z fperez $""" | |||
|
36 | ||||
|
37 | #***************************************************************************** | |||
|
38 | # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu> | |||
|
39 | # | |||
|
40 | # Distributed under the terms of the BSD License. The full license is in | |||
|
41 | # the file COPYING, distributed as part of this software. | |||
|
42 | #***************************************************************************** | |||
|
43 | ||||
|
44 | from IPython import Release | |||
|
45 | __author__ = '%s <%s>' % Release.authors['Fernando'] | |||
|
46 | __license__ = Release.license | |||
|
47 | __version__ = Release.version | |||
|
48 | ||||
|
49 | import os | |||
|
50 | ||||
|
51 | # List here all the default hooks. For now it's just the editor, but over | |||
|
52 | # time we'll move here all the public API for user-accessible things. | |||
|
53 | __all__ = ['editor'] | |||
|
54 | ||||
|
55 | def editor(self,filename, linenum): | |||
|
56 | """Open the default editor at the given filename and linenumber. | |||
|
57 | ||||
|
58 | This is IPython's default editor hook, you can use it as an example to | |||
|
59 | write your own modified one. To set your own editor function as the | |||
|
60 | new editor hook, call ip_set_hook('editor',yourfunc).""" | |||
|
61 | ||||
|
62 | # IPython configures a default editor at startup by reading $EDITOR from | |||
|
63 | # the environment, and falling back on vi (unix) or notepad (win32). | |||
|
64 | editor = self.rc.editor | |||
|
65 | ||||
|
66 | # marker for at which line to open the file (for existing objects) | |||
|
67 | if linenum is None or editor=='notepad': | |||
|
68 | linemark = '' | |||
|
69 | else: | |||
|
70 | linemark = '+%d' % linenum | |||
|
71 | # Call the actual editor | |||
|
72 | os.system('%s %s %s' % (editor,linemark,filename)) |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644, binary diff hidden |
|
NO CONTENT: new file 100644, binary diff hidden |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100755 |
|
NO CONTENT: new file 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
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