##// END OF EJS Templates
Add generics.py, result_display generic, first impl is LSString result printer
vivainio -
Show More
@@ -0,0 +1,28 b''
1 from IPython.ipapi import TryNext
2 from IPython.external.simplegeneric import generic
3
4 """ 'Generic' functions for extending IPython
5
6 See http://cheeseshop.python.org/pypi/simplegeneric
7
8 Here's an example from genutils.py:
9
10 def print_lsstring(arg):
11 """ Prettier (non-repr-like) and more informative printer for LSString """
12 print "LSString (.p, .n, .l, .s available). Value:"
13 print arg
14
15 print_lsstring = result_display.when_type(LSString)(print_lsstring)
16
17 (Yes, the nasty syntax is for python 2.3 compatibility. Your own extensions
18 can use the niftier decorator syntax)
19
20 """
21
22 @generic
23 def result_display(result):
24 """ print the result of computation """
25 raise TryNext
26
27 result_display = generic(result_display)
28
@@ -1,588 +1,591 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Classes for handling input/output prompts.
3 Classes for handling input/output prompts.
4
4
5 $Id: Prompts.py 2349 2007-05-15 16:20:35Z vivainio $"""
5 $Id: Prompts.py 2397 2007-05-26 10:06:26Z vivainio $"""
6
6
7 #*****************************************************************************
7 #*****************************************************************************
8 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #*****************************************************************************
12 #*****************************************************************************
13
13
14 from IPython import Release
14 from IPython import Release
15 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __author__ = '%s <%s>' % Release.authors['Fernando']
16 __license__ = Release.license
16 __license__ = Release.license
17 __version__ = Release.version
17 __version__ = Release.version
18
18
19 #****************************************************************************
19 #****************************************************************************
20 # Required modules
20 # Required modules
21 import __builtin__
21 import __builtin__
22 import os
22 import os
23 import socket
23 import socket
24 import sys
24 import sys
25 import time
25 import time
26
26
27 # IPython's own
27 # IPython's own
28 from IPython import ColorANSI
28 from IPython import ColorANSI
29 from IPython.Itpl import ItplNS
29 from IPython.Itpl import ItplNS
30 from IPython.ipstruct import Struct
30 from IPython.ipstruct import Struct
31 from IPython.macro import Macro
31 from IPython.macro import Macro
32 from IPython.genutils import *
32 from IPython.genutils import *
33 from IPython.ipapi import TryNext
33
34
34 #****************************************************************************
35 #****************************************************************************
35 #Color schemes for Prompts.
36 #Color schemes for Prompts.
36
37
37 PromptColors = ColorANSI.ColorSchemeTable()
38 PromptColors = ColorANSI.ColorSchemeTable()
38 InputColors = ColorANSI.InputTermColors # just a shorthand
39 InputColors = ColorANSI.InputTermColors # just a shorthand
39 Colors = ColorANSI.TermColors # just a shorthand
40 Colors = ColorANSI.TermColors # just a shorthand
40
41
41 PromptColors.add_scheme(ColorANSI.ColorScheme(
42 PromptColors.add_scheme(ColorANSI.ColorScheme(
42 'NoColor',
43 'NoColor',
43 in_prompt = InputColors.NoColor, # Input prompt
44 in_prompt = InputColors.NoColor, # Input prompt
44 in_number = InputColors.NoColor, # Input prompt number
45 in_number = InputColors.NoColor, # Input prompt number
45 in_prompt2 = InputColors.NoColor, # Continuation prompt
46 in_prompt2 = InputColors.NoColor, # Continuation prompt
46 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
47 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
47
48
48 out_prompt = Colors.NoColor, # Output prompt
49 out_prompt = Colors.NoColor, # Output prompt
49 out_number = Colors.NoColor, # Output prompt number
50 out_number = Colors.NoColor, # Output prompt number
50
51
51 normal = Colors.NoColor # color off (usu. Colors.Normal)
52 normal = Colors.NoColor # color off (usu. Colors.Normal)
52 ))
53 ))
53
54
54 # make some schemes as instances so we can copy them for modification easily:
55 # make some schemes as instances so we can copy them for modification easily:
55 __PColLinux = ColorANSI.ColorScheme(
56 __PColLinux = ColorANSI.ColorScheme(
56 'Linux',
57 'Linux',
57 in_prompt = InputColors.Green,
58 in_prompt = InputColors.Green,
58 in_number = InputColors.LightGreen,
59 in_number = InputColors.LightGreen,
59 in_prompt2 = InputColors.Green,
60 in_prompt2 = InputColors.Green,
60 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
61 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
61
62
62 out_prompt = Colors.Red,
63 out_prompt = Colors.Red,
63 out_number = Colors.LightRed,
64 out_number = Colors.LightRed,
64
65
65 normal = Colors.Normal
66 normal = Colors.Normal
66 )
67 )
67 # Don't forget to enter it into the table!
68 # Don't forget to enter it into the table!
68 PromptColors.add_scheme(__PColLinux)
69 PromptColors.add_scheme(__PColLinux)
69
70
70 # Slightly modified Linux for light backgrounds
71 # Slightly modified Linux for light backgrounds
71 __PColLightBG = __PColLinux.copy('LightBG')
72 __PColLightBG = __PColLinux.copy('LightBG')
72
73
73 __PColLightBG.colors.update(
74 __PColLightBG.colors.update(
74 in_prompt = InputColors.Blue,
75 in_prompt = InputColors.Blue,
75 in_number = InputColors.LightBlue,
76 in_number = InputColors.LightBlue,
76 in_prompt2 = InputColors.Blue
77 in_prompt2 = InputColors.Blue
77 )
78 )
78 PromptColors.add_scheme(__PColLightBG)
79 PromptColors.add_scheme(__PColLightBG)
79
80
80 del Colors,InputColors
81 del Colors,InputColors
81
82
82 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
83 def multiple_replace(dict, text):
84 def multiple_replace(dict, text):
84 """ Replace in 'text' all occurences of any key in the given
85 """ Replace in 'text' all occurences of any key in the given
85 dictionary by its corresponding value. Returns the new string."""
86 dictionary by its corresponding value. Returns the new string."""
86
87
87 # Function by Xavier Defrang, originally found at:
88 # Function by Xavier Defrang, originally found at:
88 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
89 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
89
90
90 # Create a regular expression from the dictionary keys
91 # Create a regular expression from the dictionary keys
91 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
92 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
92 # For each match, look-up corresponding value in dictionary
93 # For each match, look-up corresponding value in dictionary
93 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
94 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
94
95
95 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
96 # Special characters that can be used in prompt templates, mainly bash-like
97 # Special characters that can be used in prompt templates, mainly bash-like
97
98
98 # If $HOME isn't defined (Windows), make it an absurd string so that it can
99 # If $HOME isn't defined (Windows), make it an absurd string so that it can
99 # never be expanded out into '~'. Basically anything which can never be a
100 # never be expanded out into '~'. Basically anything which can never be a
100 # reasonable directory name will do, we just want the $HOME -> '~' operation
101 # reasonable directory name will do, we just want the $HOME -> '~' operation
101 # to become a no-op. We pre-compute $HOME here so it's not done on every
102 # to become a no-op. We pre-compute $HOME here so it's not done on every
102 # prompt call.
103 # prompt call.
103
104
104 # FIXME:
105 # FIXME:
105
106
106 # - This should be turned into a class which does proper namespace management,
107 # - This should be turned into a class which does proper namespace management,
107 # since the prompt specials need to be evaluated in a certain namespace.
108 # since the prompt specials need to be evaluated in a certain namespace.
108 # Currently it's just globals, which need to be managed manually by code
109 # Currently it's just globals, which need to be managed manually by code
109 # below.
110 # below.
110
111
111 # - I also need to split up the color schemes from the prompt specials
112 # - I also need to split up the color schemes from the prompt specials
112 # somehow. I don't have a clean design for that quite yet.
113 # somehow. I don't have a clean design for that quite yet.
113
114
114 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
115 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
115
116
116 # We precompute a few more strings here for the prompt_specials, which are
117 # We precompute a few more strings here for the prompt_specials, which are
117 # fixed once ipython starts. This reduces the runtime overhead of computing
118 # fixed once ipython starts. This reduces the runtime overhead of computing
118 # prompt strings.
119 # prompt strings.
119 USER = os.environ.get("USER")
120 USER = os.environ.get("USER")
120 HOSTNAME = socket.gethostname()
121 HOSTNAME = socket.gethostname()
121 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
122 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
122 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
123 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
123
124
124 prompt_specials_color = {
125 prompt_specials_color = {
125 # Prompt/history count
126 # Prompt/history count
126 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
127 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
127 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
128 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
128 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
129 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
129 # can get numbers displayed in whatever color they want.
130 # can get numbers displayed in whatever color they want.
130 r'\N': '${self.cache.prompt_count}',
131 r'\N': '${self.cache.prompt_count}',
131 # Prompt/history count, with the actual digits replaced by dots. Used
132 # Prompt/history count, with the actual digits replaced by dots. Used
132 # mainly in continuation prompts (prompt_in2)
133 # mainly in continuation prompts (prompt_in2)
133 r'\D': '${"."*len(str(self.cache.prompt_count))}',
134 r'\D': '${"."*len(str(self.cache.prompt_count))}',
134 # Current working directory
135 # Current working directory
135 r'\w': '${os.getcwd()}',
136 r'\w': '${os.getcwd()}',
136 # Current time
137 # Current time
137 r'\t' : '${time.strftime("%H:%M:%S")}',
138 r'\t' : '${time.strftime("%H:%M:%S")}',
138 # Basename of current working directory.
139 # Basename of current working directory.
139 # (use os.sep to make this portable across OSes)
140 # (use os.sep to make this portable across OSes)
140 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
141 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
141 # These X<N> are an extension to the normal bash prompts. They return
142 # These X<N> are an extension to the normal bash prompts. They return
142 # N terms of the path, after replacing $HOME with '~'
143 # N terms of the path, after replacing $HOME with '~'
143 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
144 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
144 r'\X1': '${self.cwd_filt(1)}',
145 r'\X1': '${self.cwd_filt(1)}',
145 r'\X2': '${self.cwd_filt(2)}',
146 r'\X2': '${self.cwd_filt(2)}',
146 r'\X3': '${self.cwd_filt(3)}',
147 r'\X3': '${self.cwd_filt(3)}',
147 r'\X4': '${self.cwd_filt(4)}',
148 r'\X4': '${self.cwd_filt(4)}',
148 r'\X5': '${self.cwd_filt(5)}',
149 r'\X5': '${self.cwd_filt(5)}',
149 # Y<N> are similar to X<N>, but they show '~' if it's the directory
150 # Y<N> are similar to X<N>, but they show '~' if it's the directory
150 # N+1 in the list. Somewhat like %cN in tcsh.
151 # N+1 in the list. Somewhat like %cN in tcsh.
151 r'\Y0': '${self.cwd_filt2(0)}',
152 r'\Y0': '${self.cwd_filt2(0)}',
152 r'\Y1': '${self.cwd_filt2(1)}',
153 r'\Y1': '${self.cwd_filt2(1)}',
153 r'\Y2': '${self.cwd_filt2(2)}',
154 r'\Y2': '${self.cwd_filt2(2)}',
154 r'\Y3': '${self.cwd_filt2(3)}',
155 r'\Y3': '${self.cwd_filt2(3)}',
155 r'\Y4': '${self.cwd_filt2(4)}',
156 r'\Y4': '${self.cwd_filt2(4)}',
156 r'\Y5': '${self.cwd_filt2(5)}',
157 r'\Y5': '${self.cwd_filt2(5)}',
157 # Hostname up to first .
158 # Hostname up to first .
158 r'\h': HOSTNAME_SHORT,
159 r'\h': HOSTNAME_SHORT,
159 # Full hostname
160 # Full hostname
160 r'\H': HOSTNAME,
161 r'\H': HOSTNAME,
161 # Username of current user
162 # Username of current user
162 r'\u': USER,
163 r'\u': USER,
163 # Escaped '\'
164 # Escaped '\'
164 '\\\\': '\\',
165 '\\\\': '\\',
165 # Newline
166 # Newline
166 r'\n': '\n',
167 r'\n': '\n',
167 # Carriage return
168 # Carriage return
168 r'\r': '\r',
169 r'\r': '\r',
169 # Release version
170 # Release version
170 r'\v': __version__,
171 r'\v': __version__,
171 # Root symbol ($ or #)
172 # Root symbol ($ or #)
172 r'\$': ROOT_SYMBOL,
173 r'\$': ROOT_SYMBOL,
173 }
174 }
174
175
175 # A copy of the prompt_specials dictionary but with all color escapes removed,
176 # A copy of the prompt_specials dictionary but with all color escapes removed,
176 # so we can correctly compute the prompt length for the auto_rewrite method.
177 # so we can correctly compute the prompt length for the auto_rewrite method.
177 prompt_specials_nocolor = prompt_specials_color.copy()
178 prompt_specials_nocolor = prompt_specials_color.copy()
178 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
179 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
179 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
180 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
180
181
181 # Add in all the InputTermColors color escapes as valid prompt characters.
182 # Add in all the InputTermColors color escapes as valid prompt characters.
182 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
183 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
183 # with a color name which may begin with a letter used by any other of the
184 # with a color name which may begin with a letter used by any other of the
184 # allowed specials. This of course means that \\C will never be allowed for
185 # allowed specials. This of course means that \\C will never be allowed for
185 # anything else.
186 # anything else.
186 input_colors = ColorANSI.InputTermColors
187 input_colors = ColorANSI.InputTermColors
187 for _color in dir(input_colors):
188 for _color in dir(input_colors):
188 if _color[0] != '_':
189 if _color[0] != '_':
189 c_name = r'\C_'+_color
190 c_name = r'\C_'+_color
190 prompt_specials_color[c_name] = getattr(input_colors,_color)
191 prompt_specials_color[c_name] = getattr(input_colors,_color)
191 prompt_specials_nocolor[c_name] = ''
192 prompt_specials_nocolor[c_name] = ''
192
193
193 # we default to no color for safety. Note that prompt_specials is a global
194 # we default to no color for safety. Note that prompt_specials is a global
194 # variable used by all prompt objects.
195 # variable used by all prompt objects.
195 prompt_specials = prompt_specials_nocolor
196 prompt_specials = prompt_specials_nocolor
196
197
197 #-----------------------------------------------------------------------------
198 #-----------------------------------------------------------------------------
198 def str_safe(arg):
199 def str_safe(arg):
199 """Convert to a string, without ever raising an exception.
200 """Convert to a string, without ever raising an exception.
200
201
201 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
202 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
202 error message."""
203 error message."""
203
204
204 try:
205 try:
205 out = str(arg)
206 out = str(arg)
206 except UnicodeError:
207 except UnicodeError:
207 try:
208 try:
208 out = arg.encode('utf_8','replace')
209 out = arg.encode('utf_8','replace')
209 except Exception,msg:
210 except Exception,msg:
210 # let's keep this little duplication here, so that the most common
211 # let's keep this little duplication here, so that the most common
211 # case doesn't suffer from a double try wrapping.
212 # case doesn't suffer from a double try wrapping.
212 out = '<ERROR: %s>' % msg
213 out = '<ERROR: %s>' % msg
213 except Exception,msg:
214 except Exception,msg:
214 out = '<ERROR: %s>' % msg
215 out = '<ERROR: %s>' % msg
215 return out
216 return out
216
217
217 class BasePrompt:
218 class BasePrompt:
218 """Interactive prompt similar to Mathematica's."""
219 """Interactive prompt similar to Mathematica's."""
219 def __init__(self,cache,sep,prompt,pad_left=False):
220 def __init__(self,cache,sep,prompt,pad_left=False):
220
221
221 # Hack: we access information about the primary prompt through the
222 # Hack: we access information about the primary prompt through the
222 # cache argument. We need this, because we want the secondary prompt
223 # cache argument. We need this, because we want the secondary prompt
223 # to be aligned with the primary one. Color table info is also shared
224 # to be aligned with the primary one. Color table info is also shared
224 # by all prompt classes through the cache. Nice OO spaghetti code!
225 # by all prompt classes through the cache. Nice OO spaghetti code!
225 self.cache = cache
226 self.cache = cache
226 self.sep = sep
227 self.sep = sep
227
228
228 # regexp to count the number of spaces at the end of a prompt
229 # regexp to count the number of spaces at the end of a prompt
229 # expression, useful for prompt auto-rewriting
230 # expression, useful for prompt auto-rewriting
230 self.rspace = re.compile(r'(\s*)$')
231 self.rspace = re.compile(r'(\s*)$')
231 # Flag to left-pad prompt strings to match the length of the primary
232 # Flag to left-pad prompt strings to match the length of the primary
232 # prompt
233 # prompt
233 self.pad_left = pad_left
234 self.pad_left = pad_left
234 # Set template to create each actual prompt (where numbers change)
235 # Set template to create each actual prompt (where numbers change)
235 self.p_template = prompt
236 self.p_template = prompt
236 self.set_p_str()
237 self.set_p_str()
237
238
238 def set_p_str(self):
239 def set_p_str(self):
239 """ Set the interpolating prompt strings.
240 """ Set the interpolating prompt strings.
240
241
241 This must be called every time the color settings change, because the
242 This must be called every time the color settings change, because the
242 prompt_specials global may have changed."""
243 prompt_specials global may have changed."""
243
244
244 import os,time # needed in locals for prompt string handling
245 import os,time # needed in locals for prompt string handling
245 loc = locals()
246 loc = locals()
246 self.p_str = ItplNS('%s%s%s' %
247 self.p_str = ItplNS('%s%s%s' %
247 ('${self.sep}${self.col_p}',
248 ('${self.sep}${self.col_p}',
248 multiple_replace(prompt_specials, self.p_template),
249 multiple_replace(prompt_specials, self.p_template),
249 '${self.col_norm}'),self.cache.user_ns,loc)
250 '${self.col_norm}'),self.cache.user_ns,loc)
250
251
251 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
252 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
252 self.p_template),
253 self.p_template),
253 self.cache.user_ns,loc)
254 self.cache.user_ns,loc)
254
255
255 def write(self,msg): # dbg
256 def write(self,msg): # dbg
256 sys.stdout.write(msg)
257 sys.stdout.write(msg)
257 return ''
258 return ''
258
259
259 def __str__(self):
260 def __str__(self):
260 """Return a string form of the prompt.
261 """Return a string form of the prompt.
261
262
262 This for is useful for continuation and output prompts, since it is
263 This for is useful for continuation and output prompts, since it is
263 left-padded to match lengths with the primary one (if the
264 left-padded to match lengths with the primary one (if the
264 self.pad_left attribute is set)."""
265 self.pad_left attribute is set)."""
265
266
266 out_str = str_safe(self.p_str)
267 out_str = str_safe(self.p_str)
267 if self.pad_left:
268 if self.pad_left:
268 # We must find the amount of padding required to match lengths,
269 # We must find the amount of padding required to match lengths,
269 # taking the color escapes (which are invisible on-screen) into
270 # taking the color escapes (which are invisible on-screen) into
270 # account.
271 # account.
271 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
272 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
272 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
273 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
273 return format % out_str
274 return format % out_str
274 else:
275 else:
275 return out_str
276 return out_str
276
277
277 # these path filters are put in as methods so that we can control the
278 # these path filters are put in as methods so that we can control the
278 # namespace where the prompt strings get evaluated
279 # namespace where the prompt strings get evaluated
279 def cwd_filt(self,depth):
280 def cwd_filt(self,depth):
280 """Return the last depth elements of the current working directory.
281 """Return the last depth elements of the current working directory.
281
282
282 $HOME is always replaced with '~'.
283 $HOME is always replaced with '~'.
283 If depth==0, the full path is returned."""
284 If depth==0, the full path is returned."""
284
285
285 cwd = os.getcwd().replace(HOME,"~")
286 cwd = os.getcwd().replace(HOME,"~")
286 out = os.sep.join(cwd.split(os.sep)[-depth:])
287 out = os.sep.join(cwd.split(os.sep)[-depth:])
287 if out:
288 if out:
288 return out
289 return out
289 else:
290 else:
290 return os.sep
291 return os.sep
291
292
292 def cwd_filt2(self,depth):
293 def cwd_filt2(self,depth):
293 """Return the last depth elements of the current working directory.
294 """Return the last depth elements of the current working directory.
294
295
295 $HOME is always replaced with '~'.
296 $HOME is always replaced with '~'.
296 If depth==0, the full path is returned."""
297 If depth==0, the full path is returned."""
297
298
298 cwd = os.getcwd().replace(HOME,"~").split(os.sep)
299 cwd = os.getcwd().replace(HOME,"~").split(os.sep)
299 if '~' in cwd and len(cwd) == depth+1:
300 if '~' in cwd and len(cwd) == depth+1:
300 depth += 1
301 depth += 1
301 out = os.sep.join(cwd[-depth:])
302 out = os.sep.join(cwd[-depth:])
302 if out:
303 if out:
303 return out
304 return out
304 else:
305 else:
305 return os.sep
306 return os.sep
306
307
307 class Prompt1(BasePrompt):
308 class Prompt1(BasePrompt):
308 """Input interactive prompt similar to Mathematica's."""
309 """Input interactive prompt similar to Mathematica's."""
309
310
310 def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
311 def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
311 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
312 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
312
313
313 def set_colors(self):
314 def set_colors(self):
314 self.set_p_str()
315 self.set_p_str()
315 Colors = self.cache.color_table.active_colors # shorthand
316 Colors = self.cache.color_table.active_colors # shorthand
316 self.col_p = Colors.in_prompt
317 self.col_p = Colors.in_prompt
317 self.col_num = Colors.in_number
318 self.col_num = Colors.in_number
318 self.col_norm = Colors.in_normal
319 self.col_norm = Colors.in_normal
319 # We need a non-input version of these escapes for the '--->'
320 # We need a non-input version of these escapes for the '--->'
320 # auto-call prompts used in the auto_rewrite() method.
321 # auto-call prompts used in the auto_rewrite() method.
321 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
322 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
322 self.col_norm_ni = Colors.normal
323 self.col_norm_ni = Colors.normal
323
324
324 def __str__(self):
325 def __str__(self):
325 self.cache.prompt_count += 1
326 self.cache.prompt_count += 1
326 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
327 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
327 return str_safe(self.p_str)
328 return str_safe(self.p_str)
328
329
329 def auto_rewrite(self):
330 def auto_rewrite(self):
330 """Print a string of the form '--->' which lines up with the previous
331 """Print a string of the form '--->' which lines up with the previous
331 input string. Useful for systems which re-write the user input when
332 input string. Useful for systems which re-write the user input when
332 handling automatically special syntaxes."""
333 handling automatically special syntaxes."""
333
334
334 curr = str(self.cache.last_prompt)
335 curr = str(self.cache.last_prompt)
335 nrspaces = len(self.rspace.search(curr).group())
336 nrspaces = len(self.rspace.search(curr).group())
336 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
337 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
337 ' '*nrspaces,self.col_norm_ni)
338 ' '*nrspaces,self.col_norm_ni)
338
339
339 class PromptOut(BasePrompt):
340 class PromptOut(BasePrompt):
340 """Output interactive prompt similar to Mathematica's."""
341 """Output interactive prompt similar to Mathematica's."""
341
342
342 def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
343 def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
343 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
344 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
344 if not self.p_template:
345 if not self.p_template:
345 self.__str__ = lambda: ''
346 self.__str__ = lambda: ''
346
347
347 def set_colors(self):
348 def set_colors(self):
348 self.set_p_str()
349 self.set_p_str()
349 Colors = self.cache.color_table.active_colors # shorthand
350 Colors = self.cache.color_table.active_colors # shorthand
350 self.col_p = Colors.out_prompt
351 self.col_p = Colors.out_prompt
351 self.col_num = Colors.out_number
352 self.col_num = Colors.out_number
352 self.col_norm = Colors.normal
353 self.col_norm = Colors.normal
353
354
354 class Prompt2(BasePrompt):
355 class Prompt2(BasePrompt):
355 """Interactive continuation prompt."""
356 """Interactive continuation prompt."""
356
357
357 def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
358 def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
358 self.cache = cache
359 self.cache = cache
359 self.p_template = prompt
360 self.p_template = prompt
360 self.pad_left = pad_left
361 self.pad_left = pad_left
361 self.set_p_str()
362 self.set_p_str()
362
363
363 def set_p_str(self):
364 def set_p_str(self):
364 import os,time # needed in locals for prompt string handling
365 import os,time # needed in locals for prompt string handling
365 loc = locals()
366 loc = locals()
366 self.p_str = ItplNS('%s%s%s' %
367 self.p_str = ItplNS('%s%s%s' %
367 ('${self.col_p2}',
368 ('${self.col_p2}',
368 multiple_replace(prompt_specials, self.p_template),
369 multiple_replace(prompt_specials, self.p_template),
369 '$self.col_norm'),
370 '$self.col_norm'),
370 self.cache.user_ns,loc)
371 self.cache.user_ns,loc)
371 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
372 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
372 self.p_template),
373 self.p_template),
373 self.cache.user_ns,loc)
374 self.cache.user_ns,loc)
374
375
375 def set_colors(self):
376 def set_colors(self):
376 self.set_p_str()
377 self.set_p_str()
377 Colors = self.cache.color_table.active_colors
378 Colors = self.cache.color_table.active_colors
378 self.col_p2 = Colors.in_prompt2
379 self.col_p2 = Colors.in_prompt2
379 self.col_norm = Colors.in_normal
380 self.col_norm = Colors.in_normal
380 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
381 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
381 # updated their prompt_in2 definitions. Remove eventually.
382 # updated their prompt_in2 definitions. Remove eventually.
382 self.col_p = Colors.out_prompt
383 self.col_p = Colors.out_prompt
383 self.col_num = Colors.out_number
384 self.col_num = Colors.out_number
384
385
385
386
386 #-----------------------------------------------------------------------------
387 #-----------------------------------------------------------------------------
387 class CachedOutput:
388 class CachedOutput:
388 """Class for printing output from calculations while keeping a cache of
389 """Class for printing output from calculations while keeping a cache of
389 reults. It dynamically creates global variables prefixed with _ which
390 reults. It dynamically creates global variables prefixed with _ which
390 contain these results.
391 contain these results.
391
392
392 Meant to be used as a sys.displayhook replacement, providing numbered
393 Meant to be used as a sys.displayhook replacement, providing numbered
393 prompts and cache services.
394 prompts and cache services.
394
395
395 Initialize with initial and final values for cache counter (this defines
396 Initialize with initial and final values for cache counter (this defines
396 the maximum size of the cache."""
397 the maximum size of the cache."""
397
398
398 def __init__(self,shell,cache_size,Pprint,
399 def __init__(self,shell,cache_size,Pprint,
399 colors='NoColor',input_sep='\n',
400 colors='NoColor',input_sep='\n',
400 output_sep='\n',output_sep2='',
401 output_sep='\n',output_sep2='',
401 ps1 = None, ps2 = None,ps_out = None,pad_left=True):
402 ps1 = None, ps2 = None,ps_out = None,pad_left=True):
402
403
403 cache_size_min = 3
404 cache_size_min = 3
404 if cache_size <= 0:
405 if cache_size <= 0:
405 self.do_full_cache = 0
406 self.do_full_cache = 0
406 cache_size = 0
407 cache_size = 0
407 elif cache_size < cache_size_min:
408 elif cache_size < cache_size_min:
408 self.do_full_cache = 0
409 self.do_full_cache = 0
409 cache_size = 0
410 cache_size = 0
410 warn('caching was disabled (min value for cache size is %s).' %
411 warn('caching was disabled (min value for cache size is %s).' %
411 cache_size_min,level=3)
412 cache_size_min,level=3)
412 else:
413 else:
413 self.do_full_cache = 1
414 self.do_full_cache = 1
414
415
415 self.cache_size = cache_size
416 self.cache_size = cache_size
416 self.input_sep = input_sep
417 self.input_sep = input_sep
417
418
418 # we need a reference to the user-level namespace
419 # we need a reference to the user-level namespace
419 self.shell = shell
420 self.shell = shell
420 self.user_ns = shell.user_ns
421 self.user_ns = shell.user_ns
421 # and to the user's input
422 # and to the user's input
422 self.input_hist = shell.input_hist
423 self.input_hist = shell.input_hist
423 # and to the user's logger, for logging output
424 # and to the user's logger, for logging output
424 self.logger = shell.logger
425 self.logger = shell.logger
425
426
426 # Set input prompt strings and colors
427 # Set input prompt strings and colors
427 if cache_size == 0:
428 if cache_size == 0:
428 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
429 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
429 or ps1.find(r'\N') > -1:
430 or ps1.find(r'\N') > -1:
430 ps1 = '>>> '
431 ps1 = '>>> '
431 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
432 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
432 or ps2.find(r'\N') > -1:
433 or ps2.find(r'\N') > -1:
433 ps2 = '... '
434 ps2 = '... '
434 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
435 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
435 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
436 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
436 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
437 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
437
438
438 self.color_table = PromptColors
439 self.color_table = PromptColors
439 self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
440 self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
440 pad_left=pad_left)
441 pad_left=pad_left)
441 self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
442 self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
442 self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
443 self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
443 pad_left=pad_left)
444 pad_left=pad_left)
444 self.set_colors(colors)
445 self.set_colors(colors)
445
446
446 # other more normal stuff
447 # other more normal stuff
447 # b/c each call to the In[] prompt raises it by 1, even the first.
448 # b/c each call to the In[] prompt raises it by 1, even the first.
448 self.prompt_count = 0
449 self.prompt_count = 0
449 # Store the last prompt string each time, we need it for aligning
450 # Store the last prompt string each time, we need it for aligning
450 # continuation and auto-rewrite prompts
451 # continuation and auto-rewrite prompts
451 self.last_prompt = ''
452 self.last_prompt = ''
452 self.Pprint = Pprint
453 self.Pprint = Pprint
453 self.output_sep = output_sep
454 self.output_sep = output_sep
454 self.output_sep2 = output_sep2
455 self.output_sep2 = output_sep2
455 self._,self.__,self.___ = '','',''
456 self._,self.__,self.___ = '','',''
456 self.pprint_types = map(type,[(),[],{}])
457 self.pprint_types = map(type,[(),[],{}])
457
458
458 # these are deliberately global:
459 # these are deliberately global:
459 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
460 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
460 self.user_ns.update(to_user_ns)
461 self.user_ns.update(to_user_ns)
461
462
462 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
463 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
463 if p_str is None:
464 if p_str is None:
464 if self.do_full_cache:
465 if self.do_full_cache:
465 return cache_def
466 return cache_def
466 else:
467 else:
467 return no_cache_def
468 return no_cache_def
468 else:
469 else:
469 return p_str
470 return p_str
470
471
471 def set_colors(self,colors):
472 def set_colors(self,colors):
472 """Set the active color scheme and configure colors for the three
473 """Set the active color scheme and configure colors for the three
473 prompt subsystems."""
474 prompt subsystems."""
474
475
475 # FIXME: the prompt_specials global should be gobbled inside this
476 # FIXME: the prompt_specials global should be gobbled inside this
476 # class instead. Do it when cleaning up the whole 3-prompt system.
477 # class instead. Do it when cleaning up the whole 3-prompt system.
477 global prompt_specials
478 global prompt_specials
478 if colors.lower()=='nocolor':
479 if colors.lower()=='nocolor':
479 prompt_specials = prompt_specials_nocolor
480 prompt_specials = prompt_specials_nocolor
480 else:
481 else:
481 prompt_specials = prompt_specials_color
482 prompt_specials = prompt_specials_color
482
483
483 self.color_table.set_active_scheme(colors)
484 self.color_table.set_active_scheme(colors)
484 self.prompt1.set_colors()
485 self.prompt1.set_colors()
485 self.prompt2.set_colors()
486 self.prompt2.set_colors()
486 self.prompt_out.set_colors()
487 self.prompt_out.set_colors()
487
488
488 def __call__(self,arg=None):
489 def __call__(self,arg=None):
489 """Printing with history cache management.
490 """Printing with history cache management.
490
491
491 This is invoked everytime the interpreter needs to print, and is
492 This is invoked everytime the interpreter needs to print, and is
492 activated by setting the variable sys.displayhook to it."""
493 activated by setting the variable sys.displayhook to it."""
493
494
494 # If something injected a '_' variable in __builtin__, delete
495 # If something injected a '_' variable in __builtin__, delete
495 # ipython's automatic one so we don't clobber that. gettext() in
496 # ipython's automatic one so we don't clobber that. gettext() in
496 # particular uses _, so we need to stay away from it.
497 # particular uses _, so we need to stay away from it.
497 if '_' in __builtin__.__dict__:
498 if '_' in __builtin__.__dict__:
498 try:
499 try:
499 del self.user_ns['_']
500 del self.user_ns['_']
500 except KeyError:
501 except KeyError:
501 pass
502 pass
502 if arg is not None:
503 if arg is not None:
503 cout_write = Term.cout.write # fast lookup
504 cout_write = Term.cout.write # fast lookup
504 # first handle the cache and counters
505 # first handle the cache and counters
505
506
506 # do not print output if input ends in ';'
507 # do not print output if input ends in ';'
507 if self.input_hist[self.prompt_count].endswith(';\n'):
508 if self.input_hist[self.prompt_count].endswith(';\n'):
508 return
509 return
509 # don't use print, puts an extra space
510 # don't use print, puts an extra space
510 cout_write(self.output_sep)
511 cout_write(self.output_sep)
511 outprompt = self.shell.hooks.generate_output_prompt()
512 outprompt = self.shell.hooks.generate_output_prompt()
512 if self.do_full_cache:
513 if self.do_full_cache:
513 cout_write(outprompt)
514 cout_write(outprompt)
514
515
515 # and now call a possibly user-defined print mechanism
516 # and now call a possibly user-defined print mechanism
516 manipulated_val = self.display(arg)
517 manipulated_val = self.display(arg)
517
518
518 # user display hooks can change the variable to be stored in
519 # user display hooks can change the variable to be stored in
519 # output history
520 # output history
520
521
521 if manipulated_val is not None:
522 if manipulated_val is not None:
522 arg = manipulated_val
523 arg = manipulated_val
523
524
524 # avoid recursive reference when displaying _oh/Out
525 # avoid recursive reference when displaying _oh/Out
525 if arg is not self.user_ns['_oh']:
526 if arg is not self.user_ns['_oh']:
526 self.update(arg)
527 self.update(arg)
527
528
528 if self.logger.log_output:
529 if self.logger.log_output:
529 self.logger.log_write(repr(arg),'output')
530 self.logger.log_write(repr(arg),'output')
530 cout_write(self.output_sep2)
531 cout_write(self.output_sep2)
531 Term.cout.flush()
532 Term.cout.flush()
532
533
533 def _display(self,arg):
534 def _display(self,arg):
534 """Default printer method, uses pprint.
535 """Default printer method, uses pprint.
535
536
536 Do ip.set_hook("result_display", my_displayhook) for custom result
537 Do ip.set_hook("result_display", my_displayhook) for custom result
537 display, e.g. when your own objects need special formatting.
538 display, e.g. when your own objects need special formatting.
538 """
539 """
539
540 try:
540 return self.shell.hooks.result_display(arg)
541 return IPython.generics.result_display(arg)
542 except TryNext:
543 return self.shell.hooks.result_display(arg)
541
544
542 # Assign the default display method:
545 # Assign the default display method:
543 display = _display
546 display = _display
544
547
545 def update(self,arg):
548 def update(self,arg):
546 #print '***cache_count', self.cache_count # dbg
549 #print '***cache_count', self.cache_count # dbg
547 if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
550 if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
548 warn('Output cache limit (currently '+
551 warn('Output cache limit (currently '+
549 `self.cache_size`+' entries) hit.\n'
552 `self.cache_size`+' entries) hit.\n'
550 'Flushing cache and resetting history counter...\n'
553 'Flushing cache and resetting history counter...\n'
551 'The only history variables available will be _,__,___ and _1\n'
554 'The only history variables available will be _,__,___ and _1\n'
552 'with the current result.')
555 'with the current result.')
553
556
554 self.flush()
557 self.flush()
555 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
558 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
556 # we cause buggy behavior for things like gettext).
559 # we cause buggy behavior for things like gettext).
557 if '_' not in __builtin__.__dict__:
560 if '_' not in __builtin__.__dict__:
558 self.___ = self.__
561 self.___ = self.__
559 self.__ = self._
562 self.__ = self._
560 self._ = arg
563 self._ = arg
561 self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
564 self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
562
565
563 # hackish access to top-level namespace to create _1,_2... dynamically
566 # hackish access to top-level namespace to create _1,_2... dynamically
564 to_main = {}
567 to_main = {}
565 if self.do_full_cache:
568 if self.do_full_cache:
566 new_result = '_'+`self.prompt_count`
569 new_result = '_'+`self.prompt_count`
567 to_main[new_result] = arg
570 to_main[new_result] = arg
568 self.user_ns.update(to_main)
571 self.user_ns.update(to_main)
569 self.user_ns['_oh'][self.prompt_count] = arg
572 self.user_ns['_oh'][self.prompt_count] = arg
570
573
571 def flush(self):
574 def flush(self):
572 if not self.do_full_cache:
575 if not self.do_full_cache:
573 raise ValueError,"You shouldn't have reached the cache flush "\
576 raise ValueError,"You shouldn't have reached the cache flush "\
574 "if full caching is not enabled!"
577 "if full caching is not enabled!"
575 # delete auto-generated vars from global namespace
578 # delete auto-generated vars from global namespace
576
579
577 for n in range(1,self.prompt_count + 1):
580 for n in range(1,self.prompt_count + 1):
578 key = '_'+`n`
581 key = '_'+`n`
579 try:
582 try:
580 del self.user_ns[key]
583 del self.user_ns[key]
581 except: pass
584 except: pass
582 self.user_ns['_oh'].clear()
585 self.user_ns['_oh'].clear()
583
586
584 if '_' not in __builtin__.__dict__:
587 if '_' not in __builtin__.__dict__:
585 self.user_ns.update({'_':None,'__':None, '___':None})
588 self.user_ns.update({'_':None,'__':None, '___':None})
586 import gc
589 import gc
587 gc.collect() # xxx needed?
590 gc.collect() # xxx needed?
588
591
@@ -1,1772 +1,1783 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 General purpose utilities.
3 General purpose utilities.
4
4
5 This is a grab-bag of stuff I find useful in most programs I write. Some of
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.
6 these things are also convenient when working at the command line.
7
7
8 $Id: genutils.py 2371 2007-05-23 18:40:26Z vivainio $"""
8 $Id: genutils.py 2397 2007-05-26 10:06:26Z vivainio $"""
9
9
10 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #*****************************************************************************
15 #*****************************************************************************
16
16
17 from IPython import Release
17 from IPython import Release
18 __author__ = '%s <%s>' % Release.authors['Fernando']
18 __author__ = '%s <%s>' % Release.authors['Fernando']
19 __license__ = Release.license
19 __license__ = Release.license
20
20
21 #****************************************************************************
21 #****************************************************************************
22 # required modules from the Python standard library
22 # required modules from the Python standard library
23 import __main__
23 import __main__
24 import commands
24 import commands
25 import os
25 import os
26 import re
26 import re
27 import shlex
27 import shlex
28 import shutil
28 import shutil
29 import sys
29 import sys
30 import tempfile
30 import tempfile
31 import time
31 import time
32 import types
32 import types
33 import warnings
33 import warnings
34
34
35 # Other IPython utilities
35 # Other IPython utilities
36 import IPython
36 import IPython
37 from IPython.Itpl import Itpl,itpl,printpl
37 from IPython.Itpl import Itpl,itpl,printpl
38 from IPython import DPyGetOpt
38 from IPython import DPyGetOpt
39 from IPython.generics import result_display
39 from path import path
40 from path import path
40 if os.name == "nt":
41 if os.name == "nt":
41 from IPython.winconsole import get_console_size
42 from IPython.winconsole import get_console_size
42
43
43 #****************************************************************************
44 #****************************************************************************
44 # Exceptions
45 # Exceptions
45 class Error(Exception):
46 class Error(Exception):
46 """Base class for exceptions in this module."""
47 """Base class for exceptions in this module."""
47 pass
48 pass
48
49
49 #----------------------------------------------------------------------------
50 #----------------------------------------------------------------------------
50 class IOStream:
51 class IOStream:
51 def __init__(self,stream,fallback):
52 def __init__(self,stream,fallback):
52 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
53 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
53 stream = fallback
54 stream = fallback
54 self.stream = stream
55 self.stream = stream
55 self._swrite = stream.write
56 self._swrite = stream.write
56 self.flush = stream.flush
57 self.flush = stream.flush
57
58
58 def write(self,data):
59 def write(self,data):
59 try:
60 try:
60 self._swrite(data)
61 self._swrite(data)
61 except:
62 except:
62 try:
63 try:
63 # print handles some unicode issues which may trip a plain
64 # print handles some unicode issues which may trip a plain
64 # write() call. Attempt to emulate write() by using a
65 # write() call. Attempt to emulate write() by using a
65 # trailing comma
66 # trailing comma
66 print >> self.stream, data,
67 print >> self.stream, data,
67 except:
68 except:
68 # if we get here, something is seriously broken.
69 # if we get here, something is seriously broken.
69 print >> sys.stderr, \
70 print >> sys.stderr, \
70 'ERROR - failed to write data to stream:', self.stream
71 'ERROR - failed to write data to stream:', self.stream
71
72
72 def close(self):
73 def close(self):
73 pass
74 pass
74
75
75
76
76 class IOTerm:
77 class IOTerm:
77 """ Term holds the file or file-like objects for handling I/O operations.
78 """ Term holds the file or file-like objects for handling I/O operations.
78
79
79 These are normally just sys.stdin, sys.stdout and sys.stderr but for
80 These are normally just sys.stdin, sys.stdout and sys.stderr but for
80 Windows they can can replaced to allow editing the strings before they are
81 Windows they can can replaced to allow editing the strings before they are
81 displayed."""
82 displayed."""
82
83
83 # In the future, having IPython channel all its I/O operations through
84 # In the future, having IPython channel all its I/O operations through
84 # this class will make it easier to embed it into other environments which
85 # this class will make it easier to embed it into other environments which
85 # are not a normal terminal (such as a GUI-based shell)
86 # are not a normal terminal (such as a GUI-based shell)
86 def __init__(self,cin=None,cout=None,cerr=None):
87 def __init__(self,cin=None,cout=None,cerr=None):
87 self.cin = IOStream(cin,sys.stdin)
88 self.cin = IOStream(cin,sys.stdin)
88 self.cout = IOStream(cout,sys.stdout)
89 self.cout = IOStream(cout,sys.stdout)
89 self.cerr = IOStream(cerr,sys.stderr)
90 self.cerr = IOStream(cerr,sys.stderr)
90
91
91 # Global variable to be used for all I/O
92 # Global variable to be used for all I/O
92 Term = IOTerm()
93 Term = IOTerm()
93
94
94 import IPython.rlineimpl as readline
95 import IPython.rlineimpl as readline
95 # Remake Term to use the readline i/o facilities
96 # Remake Term to use the readline i/o facilities
96 if sys.platform == 'win32' and readline.have_readline:
97 if sys.platform == 'win32' and readline.have_readline:
97
98
98 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
99 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
99
100
100
101
101 #****************************************************************************
102 #****************************************************************************
102 # Generic warning/error printer, used by everything else
103 # Generic warning/error printer, used by everything else
103 def warn(msg,level=2,exit_val=1):
104 def warn(msg,level=2,exit_val=1):
104 """Standard warning printer. Gives formatting consistency.
105 """Standard warning printer. Gives formatting consistency.
105
106
106 Output is sent to Term.cerr (sys.stderr by default).
107 Output is sent to Term.cerr (sys.stderr by default).
107
108
108 Options:
109 Options:
109
110
110 -level(2): allows finer control:
111 -level(2): allows finer control:
111 0 -> Do nothing, dummy function.
112 0 -> Do nothing, dummy function.
112 1 -> Print message.
113 1 -> Print message.
113 2 -> Print 'WARNING:' + message. (Default level).
114 2 -> Print 'WARNING:' + message. (Default level).
114 3 -> Print 'ERROR:' + message.
115 3 -> Print 'ERROR:' + message.
115 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
116 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
116
117
117 -exit_val (1): exit value returned by sys.exit() for a level 4
118 -exit_val (1): exit value returned by sys.exit() for a level 4
118 warning. Ignored for all other levels."""
119 warning. Ignored for all other levels."""
119
120
120 if level>0:
121 if level>0:
121 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
122 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
122 print >> Term.cerr, '%s%s' % (header[level],msg)
123 print >> Term.cerr, '%s%s' % (header[level],msg)
123 if level == 4:
124 if level == 4:
124 print >> Term.cerr,'Exiting.\n'
125 print >> Term.cerr,'Exiting.\n'
125 sys.exit(exit_val)
126 sys.exit(exit_val)
126
127
127 def info(msg):
128 def info(msg):
128 """Equivalent to warn(msg,level=1)."""
129 """Equivalent to warn(msg,level=1)."""
129
130
130 warn(msg,level=1)
131 warn(msg,level=1)
131
132
132 def error(msg):
133 def error(msg):
133 """Equivalent to warn(msg,level=3)."""
134 """Equivalent to warn(msg,level=3)."""
134
135
135 warn(msg,level=3)
136 warn(msg,level=3)
136
137
137 def fatal(msg,exit_val=1):
138 def fatal(msg,exit_val=1):
138 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
139 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
139
140
140 warn(msg,exit_val=exit_val,level=4)
141 warn(msg,exit_val=exit_val,level=4)
141
142
142 #---------------------------------------------------------------------------
143 #---------------------------------------------------------------------------
143 # Debugging routines
144 # Debugging routines
144 #
145 #
145 def debugx(expr,pre_msg=''):
146 def debugx(expr,pre_msg=''):
146 """Print the value of an expression from the caller's frame.
147 """Print the value of an expression from the caller's frame.
147
148
148 Takes an expression, evaluates it in the caller's frame and prints both
149 Takes an expression, evaluates it in the caller's frame and prints both
149 the given expression and the resulting value (as well as a debug mark
150 the given expression and the resulting value (as well as a debug mark
150 indicating the name of the calling function. The input must be of a form
151 indicating the name of the calling function. The input must be of a form
151 suitable for eval().
152 suitable for eval().
152
153
153 An optional message can be passed, which will be prepended to the printed
154 An optional message can be passed, which will be prepended to the printed
154 expr->value pair."""
155 expr->value pair."""
155
156
156 cf = sys._getframe(1)
157 cf = sys._getframe(1)
157 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
158 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
158 eval(expr,cf.f_globals,cf.f_locals))
159 eval(expr,cf.f_globals,cf.f_locals))
159
160
160 # deactivate it by uncommenting the following line, which makes it a no-op
161 # deactivate it by uncommenting the following line, which makes it a no-op
161 #def debugx(expr,pre_msg=''): pass
162 #def debugx(expr,pre_msg=''): pass
162
163
163 #----------------------------------------------------------------------------
164 #----------------------------------------------------------------------------
164 StringTypes = types.StringTypes
165 StringTypes = types.StringTypes
165
166
166 # Basic timing functionality
167 # Basic timing functionality
167
168
168 # If possible (Unix), use the resource module instead of time.clock()
169 # If possible (Unix), use the resource module instead of time.clock()
169 try:
170 try:
170 import resource
171 import resource
171 def clocku():
172 def clocku():
172 """clocku() -> floating point number
173 """clocku() -> floating point number
173
174
174 Return the *USER* CPU time in seconds since the start of the process.
175 Return the *USER* CPU time in seconds since the start of the process.
175 This is done via a call to resource.getrusage, so it avoids the
176 This is done via a call to resource.getrusage, so it avoids the
176 wraparound problems in time.clock()."""
177 wraparound problems in time.clock()."""
177
178
178 return resource.getrusage(resource.RUSAGE_SELF)[0]
179 return resource.getrusage(resource.RUSAGE_SELF)[0]
179
180
180 def clocks():
181 def clocks():
181 """clocks() -> floating point number
182 """clocks() -> floating point number
182
183
183 Return the *SYSTEM* CPU time in seconds since the start of the process.
184 Return the *SYSTEM* CPU time in seconds since the start of the process.
184 This is done via a call to resource.getrusage, so it avoids the
185 This is done via a call to resource.getrusage, so it avoids the
185 wraparound problems in time.clock()."""
186 wraparound problems in time.clock()."""
186
187
187 return resource.getrusage(resource.RUSAGE_SELF)[1]
188 return resource.getrusage(resource.RUSAGE_SELF)[1]
188
189
189 def clock():
190 def clock():
190 """clock() -> floating point number
191 """clock() -> floating point number
191
192
192 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
193 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
193 the process. This is done via a call to resource.getrusage, so it
194 the process. This is done via a call to resource.getrusage, so it
194 avoids the wraparound problems in time.clock()."""
195 avoids the wraparound problems in time.clock()."""
195
196
196 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
197 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
197 return u+s
198 return u+s
198
199
199 def clock2():
200 def clock2():
200 """clock2() -> (t_user,t_system)
201 """clock2() -> (t_user,t_system)
201
202
202 Similar to clock(), but return a tuple of user/system times."""
203 Similar to clock(), but return a tuple of user/system times."""
203 return resource.getrusage(resource.RUSAGE_SELF)[:2]
204 return resource.getrusage(resource.RUSAGE_SELF)[:2]
204
205
205 except ImportError:
206 except ImportError:
206 # There is no distinction of user/system time under windows, so we just use
207 # There is no distinction of user/system time under windows, so we just use
207 # time.clock() for everything...
208 # time.clock() for everything...
208 clocku = clocks = clock = time.clock
209 clocku = clocks = clock = time.clock
209 def clock2():
210 def clock2():
210 """Under windows, system CPU time can't be measured.
211 """Under windows, system CPU time can't be measured.
211
212
212 This just returns clock() and zero."""
213 This just returns clock() and zero."""
213 return time.clock(),0.0
214 return time.clock(),0.0
214
215
215 def timings_out(reps,func,*args,**kw):
216 def timings_out(reps,func,*args,**kw):
216 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
217 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
217
218
218 Execute a function reps times, return a tuple with the elapsed total
219 Execute a function reps times, return a tuple with the elapsed total
219 CPU time in seconds, the time per call and the function's output.
220 CPU time in seconds, the time per call and the function's output.
220
221
221 Under Unix, the return value is the sum of user+system time consumed by
222 Under Unix, the return value is the sum of user+system time consumed by
222 the process, computed via the resource module. This prevents problems
223 the process, computed via the resource module. This prevents problems
223 related to the wraparound effect which the time.clock() function has.
224 related to the wraparound effect which the time.clock() function has.
224
225
225 Under Windows the return value is in wall clock seconds. See the
226 Under Windows the return value is in wall clock seconds. See the
226 documentation for the time module for more details."""
227 documentation for the time module for more details."""
227
228
228 reps = int(reps)
229 reps = int(reps)
229 assert reps >=1, 'reps must be >= 1'
230 assert reps >=1, 'reps must be >= 1'
230 if reps==1:
231 if reps==1:
231 start = clock()
232 start = clock()
232 out = func(*args,**kw)
233 out = func(*args,**kw)
233 tot_time = clock()-start
234 tot_time = clock()-start
234 else:
235 else:
235 rng = xrange(reps-1) # the last time is executed separately to store output
236 rng = xrange(reps-1) # the last time is executed separately to store output
236 start = clock()
237 start = clock()
237 for dummy in rng: func(*args,**kw)
238 for dummy in rng: func(*args,**kw)
238 out = func(*args,**kw) # one last time
239 out = func(*args,**kw) # one last time
239 tot_time = clock()-start
240 tot_time = clock()-start
240 av_time = tot_time / reps
241 av_time = tot_time / reps
241 return tot_time,av_time,out
242 return tot_time,av_time,out
242
243
243 def timings(reps,func,*args,**kw):
244 def timings(reps,func,*args,**kw):
244 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
245 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
245
246
246 Execute a function reps times, return a tuple with the elapsed total CPU
247 Execute a function reps times, return a tuple with the elapsed total CPU
247 time in seconds and the time per call. These are just the first two values
248 time in seconds and the time per call. These are just the first two values
248 in timings_out()."""
249 in timings_out()."""
249
250
250 return timings_out(reps,func,*args,**kw)[0:2]
251 return timings_out(reps,func,*args,**kw)[0:2]
251
252
252 def timing(func,*args,**kw):
253 def timing(func,*args,**kw):
253 """timing(func,*args,**kw) -> t_total
254 """timing(func,*args,**kw) -> t_total
254
255
255 Execute a function once, return the elapsed total CPU time in
256 Execute a function once, return the elapsed total CPU time in
256 seconds. This is just the first value in timings_out()."""
257 seconds. This is just the first value in timings_out()."""
257
258
258 return timings_out(1,func,*args,**kw)[0]
259 return timings_out(1,func,*args,**kw)[0]
259
260
260 #****************************************************************************
261 #****************************************************************************
261 # file and system
262 # file and system
262
263
263 def arg_split(s,posix=False):
264 def arg_split(s,posix=False):
264 """Split a command line's arguments in a shell-like manner.
265 """Split a command line's arguments in a shell-like manner.
265
266
266 This is a modified version of the standard library's shlex.split()
267 This is a modified version of the standard library's shlex.split()
267 function, but with a default of posix=False for splitting, so that quotes
268 function, but with a default of posix=False for splitting, so that quotes
268 in inputs are respected."""
269 in inputs are respected."""
269
270
270 # XXX - there may be unicode-related problems here!!! I'm not sure that
271 # XXX - there may be unicode-related problems here!!! I'm not sure that
271 # shlex is truly unicode-safe, so it might be necessary to do
272 # shlex is truly unicode-safe, so it might be necessary to do
272 #
273 #
273 # s = s.encode(sys.stdin.encoding)
274 # s = s.encode(sys.stdin.encoding)
274 #
275 #
275 # first, to ensure that shlex gets a normal string. Input from anyone who
276 # first, to ensure that shlex gets a normal string. Input from anyone who
276 # knows more about unicode and shlex than I would be good to have here...
277 # knows more about unicode and shlex than I would be good to have here...
277 lex = shlex.shlex(s, posix=posix)
278 lex = shlex.shlex(s, posix=posix)
278 lex.whitespace_split = True
279 lex.whitespace_split = True
279 return list(lex)
280 return list(lex)
280
281
281 def system(cmd,verbose=0,debug=0,header=''):
282 def system(cmd,verbose=0,debug=0,header=''):
282 """Execute a system command, return its exit status.
283 """Execute a system command, return its exit status.
283
284
284 Options:
285 Options:
285
286
286 - verbose (0): print the command to be executed.
287 - verbose (0): print the command to be executed.
287
288
288 - debug (0): only print, do not actually execute.
289 - debug (0): only print, do not actually execute.
289
290
290 - header (''): Header to print on screen prior to the executed command (it
291 - header (''): Header to print on screen prior to the executed command (it
291 is only prepended to the command, no newlines are added).
292 is only prepended to the command, no newlines are added).
292
293
293 Note: a stateful version of this function is available through the
294 Note: a stateful version of this function is available through the
294 SystemExec class."""
295 SystemExec class."""
295
296
296 stat = 0
297 stat = 0
297 if verbose or debug: print header+cmd
298 if verbose or debug: print header+cmd
298 sys.stdout.flush()
299 sys.stdout.flush()
299 if not debug: stat = os.system(cmd)
300 if not debug: stat = os.system(cmd)
300 return stat
301 return stat
301
302
302 # This function is used by ipython in a lot of places to make system calls.
303 # This function is used by ipython in a lot of places to make system calls.
303 # We need it to be slightly different under win32, due to the vagaries of
304 # We need it to be slightly different under win32, due to the vagaries of
304 # 'network shares'. A win32 override is below.
305 # 'network shares'. A win32 override is below.
305
306
306 def shell(cmd,verbose=0,debug=0,header=''):
307 def shell(cmd,verbose=0,debug=0,header=''):
307 """Execute a command in the system shell, always return None.
308 """Execute a command in the system shell, always return None.
308
309
309 Options:
310 Options:
310
311
311 - verbose (0): print the command to be executed.
312 - verbose (0): print the command to be executed.
312
313
313 - debug (0): only print, do not actually execute.
314 - debug (0): only print, do not actually execute.
314
315
315 - header (''): Header to print on screen prior to the executed command (it
316 - header (''): Header to print on screen prior to the executed command (it
316 is only prepended to the command, no newlines are added).
317 is only prepended to the command, no newlines are added).
317
318
318 Note: this is similar to genutils.system(), but it returns None so it can
319 Note: this is similar to genutils.system(), but it returns None so it can
319 be conveniently used in interactive loops without getting the return value
320 be conveniently used in interactive loops without getting the return value
320 (typically 0) printed many times."""
321 (typically 0) printed many times."""
321
322
322 stat = 0
323 stat = 0
323 if verbose or debug: print header+cmd
324 if verbose or debug: print header+cmd
324 # flush stdout so we don't mangle python's buffering
325 # flush stdout so we don't mangle python's buffering
325 sys.stdout.flush()
326 sys.stdout.flush()
326 if not debug:
327 if not debug:
327 os.system(cmd)
328 os.system(cmd)
328
329
329 # override shell() for win32 to deal with network shares
330 # override shell() for win32 to deal with network shares
330 if os.name in ('nt','dos'):
331 if os.name in ('nt','dos'):
331
332
332 shell_ori = shell
333 shell_ori = shell
333
334
334 def shell(cmd,verbose=0,debug=0,header=''):
335 def shell(cmd,verbose=0,debug=0,header=''):
335 if os.getcwd().startswith(r"\\"):
336 if os.getcwd().startswith(r"\\"):
336 path = os.getcwd()
337 path = os.getcwd()
337 # change to c drive (cannot be on UNC-share when issuing os.system,
338 # change to c drive (cannot be on UNC-share when issuing os.system,
338 # as cmd.exe cannot handle UNC addresses)
339 # as cmd.exe cannot handle UNC addresses)
339 os.chdir("c:")
340 os.chdir("c:")
340 # issue pushd to the UNC-share and then run the command
341 # issue pushd to the UNC-share and then run the command
341 try:
342 try:
342 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
343 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
343 finally:
344 finally:
344 os.chdir(path)
345 os.chdir(path)
345 else:
346 else:
346 shell_ori(cmd,verbose,debug,header)
347 shell_ori(cmd,verbose,debug,header)
347
348
348 shell.__doc__ = shell_ori.__doc__
349 shell.__doc__ = shell_ori.__doc__
349
350
350 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
351 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
351 """Dummy substitute for perl's backquotes.
352 """Dummy substitute for perl's backquotes.
352
353
353 Executes a command and returns the output.
354 Executes a command and returns the output.
354
355
355 Accepts the same arguments as system(), plus:
356 Accepts the same arguments as system(), plus:
356
357
357 - split(0): if true, the output is returned as a list split on newlines.
358 - split(0): if true, the output is returned as a list split on newlines.
358
359
359 Note: a stateful version of this function is available through the
360 Note: a stateful version of this function is available through the
360 SystemExec class.
361 SystemExec class.
361
362
362 This is pretty much deprecated and rarely used,
363 This is pretty much deprecated and rarely used,
363 genutils.getoutputerror may be what you need.
364 genutils.getoutputerror may be what you need.
364
365
365 """
366 """
366
367
367 if verbose or debug: print header+cmd
368 if verbose or debug: print header+cmd
368 if not debug:
369 if not debug:
369 output = os.popen(cmd).read()
370 output = os.popen(cmd).read()
370 # stipping last \n is here for backwards compat.
371 # stipping last \n is here for backwards compat.
371 if output.endswith('\n'):
372 if output.endswith('\n'):
372 output = output[:-1]
373 output = output[:-1]
373 if split:
374 if split:
374 return output.split('\n')
375 return output.split('\n')
375 else:
376 else:
376 return output
377 return output
377
378
378 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
379 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
379 """Return (standard output,standard error) of executing cmd in a shell.
380 """Return (standard output,standard error) of executing cmd in a shell.
380
381
381 Accepts the same arguments as system(), plus:
382 Accepts the same arguments as system(), plus:
382
383
383 - split(0): if true, each of stdout/err is returned as a list split on
384 - split(0): if true, each of stdout/err is returned as a list split on
384 newlines.
385 newlines.
385
386
386 Note: a stateful version of this function is available through the
387 Note: a stateful version of this function is available through the
387 SystemExec class."""
388 SystemExec class."""
388
389
389 if verbose or debug: print header+cmd
390 if verbose or debug: print header+cmd
390 if not cmd:
391 if not cmd:
391 if split:
392 if split:
392 return [],[]
393 return [],[]
393 else:
394 else:
394 return '',''
395 return '',''
395 if not debug:
396 if not debug:
396 pin,pout,perr = os.popen3(cmd)
397 pin,pout,perr = os.popen3(cmd)
397 tout = pout.read().rstrip()
398 tout = pout.read().rstrip()
398 terr = perr.read().rstrip()
399 terr = perr.read().rstrip()
399 pin.close()
400 pin.close()
400 pout.close()
401 pout.close()
401 perr.close()
402 perr.close()
402 if split:
403 if split:
403 return tout.split('\n'),terr.split('\n')
404 return tout.split('\n'),terr.split('\n')
404 else:
405 else:
405 return tout,terr
406 return tout,terr
406
407
407 # for compatibility with older naming conventions
408 # for compatibility with older naming conventions
408 xsys = system
409 xsys = system
409 bq = getoutput
410 bq = getoutput
410
411
411 class SystemExec:
412 class SystemExec:
412 """Access the system and getoutput functions through a stateful interface.
413 """Access the system and getoutput functions through a stateful interface.
413
414
414 Note: here we refer to the system and getoutput functions from this
415 Note: here we refer to the system and getoutput functions from this
415 library, not the ones from the standard python library.
416 library, not the ones from the standard python library.
416
417
417 This class offers the system and getoutput functions as methods, but the
418 This class offers the system and getoutput functions as methods, but the
418 verbose, debug and header parameters can be set for the instance (at
419 verbose, debug and header parameters can be set for the instance (at
419 creation time or later) so that they don't need to be specified on each
420 creation time or later) so that they don't need to be specified on each
420 call.
421 call.
421
422
422 For efficiency reasons, there's no way to override the parameters on a
423 For efficiency reasons, there's no way to override the parameters on a
423 per-call basis other than by setting instance attributes. If you need
424 per-call basis other than by setting instance attributes. If you need
424 local overrides, it's best to directly call system() or getoutput().
425 local overrides, it's best to directly call system() or getoutput().
425
426
426 The following names are provided as alternate options:
427 The following names are provided as alternate options:
427 - xsys: alias to system
428 - xsys: alias to system
428 - bq: alias to getoutput
429 - bq: alias to getoutput
429
430
430 An instance can then be created as:
431 An instance can then be created as:
431 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
432 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
432
433
433 And used as:
434 And used as:
434 >>> sysexec.xsys('pwd')
435 >>> sysexec.xsys('pwd')
435 >>> dirlist = sysexec.bq('ls -l')
436 >>> dirlist = sysexec.bq('ls -l')
436 """
437 """
437
438
438 def __init__(self,verbose=0,debug=0,header='',split=0):
439 def __init__(self,verbose=0,debug=0,header='',split=0):
439 """Specify the instance's values for verbose, debug and header."""
440 """Specify the instance's values for verbose, debug and header."""
440 setattr_list(self,'verbose debug header split')
441 setattr_list(self,'verbose debug header split')
441
442
442 def system(self,cmd):
443 def system(self,cmd):
443 """Stateful interface to system(), with the same keyword parameters."""
444 """Stateful interface to system(), with the same keyword parameters."""
444
445
445 system(cmd,self.verbose,self.debug,self.header)
446 system(cmd,self.verbose,self.debug,self.header)
446
447
447 def shell(self,cmd):
448 def shell(self,cmd):
448 """Stateful interface to shell(), with the same keyword parameters."""
449 """Stateful interface to shell(), with the same keyword parameters."""
449
450
450 shell(cmd,self.verbose,self.debug,self.header)
451 shell(cmd,self.verbose,self.debug,self.header)
451
452
452 xsys = system # alias
453 xsys = system # alias
453
454
454 def getoutput(self,cmd):
455 def getoutput(self,cmd):
455 """Stateful interface to getoutput()."""
456 """Stateful interface to getoutput()."""
456
457
457 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
458 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
458
459
459 def getoutputerror(self,cmd):
460 def getoutputerror(self,cmd):
460 """Stateful interface to getoutputerror()."""
461 """Stateful interface to getoutputerror()."""
461
462
462 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
463 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
463
464
464 bq = getoutput # alias
465 bq = getoutput # alias
465
466
466 #-----------------------------------------------------------------------------
467 #-----------------------------------------------------------------------------
467 def mutex_opts(dict,ex_op):
468 def mutex_opts(dict,ex_op):
468 """Check for presence of mutually exclusive keys in a dict.
469 """Check for presence of mutually exclusive keys in a dict.
469
470
470 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
471 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
471 for op1,op2 in ex_op:
472 for op1,op2 in ex_op:
472 if op1 in dict and op2 in dict:
473 if op1 in dict and op2 in dict:
473 raise ValueError,'\n*** ERROR in Arguments *** '\
474 raise ValueError,'\n*** ERROR in Arguments *** '\
474 'Options '+op1+' and '+op2+' are mutually exclusive.'
475 'Options '+op1+' and '+op2+' are mutually exclusive.'
475
476
476 #-----------------------------------------------------------------------------
477 #-----------------------------------------------------------------------------
477 def get_py_filename(name):
478 def get_py_filename(name):
478 """Return a valid python filename in the current directory.
479 """Return a valid python filename in the current directory.
479
480
480 If the given name is not a file, it adds '.py' and searches again.
481 If the given name is not a file, it adds '.py' and searches again.
481 Raises IOError with an informative message if the file isn't found."""
482 Raises IOError with an informative message if the file isn't found."""
482
483
483 name = os.path.expanduser(name)
484 name = os.path.expanduser(name)
484 if not os.path.isfile(name) and not name.endswith('.py'):
485 if not os.path.isfile(name) and not name.endswith('.py'):
485 name += '.py'
486 name += '.py'
486 if os.path.isfile(name):
487 if os.path.isfile(name):
487 return name
488 return name
488 else:
489 else:
489 raise IOError,'File `%s` not found.' % name
490 raise IOError,'File `%s` not found.' % name
490
491
491 #-----------------------------------------------------------------------------
492 #-----------------------------------------------------------------------------
492 def filefind(fname,alt_dirs = None):
493 def filefind(fname,alt_dirs = None):
493 """Return the given filename either in the current directory, if it
494 """Return the given filename either in the current directory, if it
494 exists, or in a specified list of directories.
495 exists, or in a specified list of directories.
495
496
496 ~ expansion is done on all file and directory names.
497 ~ expansion is done on all file and directory names.
497
498
498 Upon an unsuccessful search, raise an IOError exception."""
499 Upon an unsuccessful search, raise an IOError exception."""
499
500
500 if alt_dirs is None:
501 if alt_dirs is None:
501 try:
502 try:
502 alt_dirs = get_home_dir()
503 alt_dirs = get_home_dir()
503 except HomeDirError:
504 except HomeDirError:
504 alt_dirs = os.getcwd()
505 alt_dirs = os.getcwd()
505 search = [fname] + list_strings(alt_dirs)
506 search = [fname] + list_strings(alt_dirs)
506 search = map(os.path.expanduser,search)
507 search = map(os.path.expanduser,search)
507 #print 'search list for',fname,'list:',search # dbg
508 #print 'search list for',fname,'list:',search # dbg
508 fname = search[0]
509 fname = search[0]
509 if os.path.isfile(fname):
510 if os.path.isfile(fname):
510 return fname
511 return fname
511 for direc in search[1:]:
512 for direc in search[1:]:
512 testname = os.path.join(direc,fname)
513 testname = os.path.join(direc,fname)
513 #print 'testname',testname # dbg
514 #print 'testname',testname # dbg
514 if os.path.isfile(testname):
515 if os.path.isfile(testname):
515 return testname
516 return testname
516 raise IOError,'File' + `fname` + \
517 raise IOError,'File' + `fname` + \
517 ' not found in current or supplied directories:' + `alt_dirs`
518 ' not found in current or supplied directories:' + `alt_dirs`
518
519
519 #----------------------------------------------------------------------------
520 #----------------------------------------------------------------------------
520 def file_read(filename):
521 def file_read(filename):
521 """Read a file and close it. Returns the file source."""
522 """Read a file and close it. Returns the file source."""
522 fobj = open(filename,'r');
523 fobj = open(filename,'r');
523 source = fobj.read();
524 source = fobj.read();
524 fobj.close()
525 fobj.close()
525 return source
526 return source
526
527
527 def file_readlines(filename):
528 def file_readlines(filename):
528 """Read a file and close it. Returns the file source using readlines()."""
529 """Read a file and close it. Returns the file source using readlines()."""
529 fobj = open(filename,'r');
530 fobj = open(filename,'r');
530 lines = fobj.readlines();
531 lines = fobj.readlines();
531 fobj.close()
532 fobj.close()
532 return lines
533 return lines
533
534
534 #----------------------------------------------------------------------------
535 #----------------------------------------------------------------------------
535 def target_outdated(target,deps):
536 def target_outdated(target,deps):
536 """Determine whether a target is out of date.
537 """Determine whether a target is out of date.
537
538
538 target_outdated(target,deps) -> 1/0
539 target_outdated(target,deps) -> 1/0
539
540
540 deps: list of filenames which MUST exist.
541 deps: list of filenames which MUST exist.
541 target: single filename which may or may not exist.
542 target: single filename which may or may not exist.
542
543
543 If target doesn't exist or is older than any file listed in deps, return
544 If target doesn't exist or is older than any file listed in deps, return
544 true, otherwise return false.
545 true, otherwise return false.
545 """
546 """
546 try:
547 try:
547 target_time = os.path.getmtime(target)
548 target_time = os.path.getmtime(target)
548 except os.error:
549 except os.error:
549 return 1
550 return 1
550 for dep in deps:
551 for dep in deps:
551 dep_time = os.path.getmtime(dep)
552 dep_time = os.path.getmtime(dep)
552 if dep_time > target_time:
553 if dep_time > target_time:
553 #print "For target",target,"Dep failed:",dep # dbg
554 #print "For target",target,"Dep failed:",dep # dbg
554 #print "times (dep,tar):",dep_time,target_time # dbg
555 #print "times (dep,tar):",dep_time,target_time # dbg
555 return 1
556 return 1
556 return 0
557 return 0
557
558
558 #-----------------------------------------------------------------------------
559 #-----------------------------------------------------------------------------
559 def target_update(target,deps,cmd):
560 def target_update(target,deps,cmd):
560 """Update a target with a given command given a list of dependencies.
561 """Update a target with a given command given a list of dependencies.
561
562
562 target_update(target,deps,cmd) -> runs cmd if target is outdated.
563 target_update(target,deps,cmd) -> runs cmd if target is outdated.
563
564
564 This is just a wrapper around target_outdated() which calls the given
565 This is just a wrapper around target_outdated() which calls the given
565 command if target is outdated."""
566 command if target is outdated."""
566
567
567 if target_outdated(target,deps):
568 if target_outdated(target,deps):
568 xsys(cmd)
569 xsys(cmd)
569
570
570 #----------------------------------------------------------------------------
571 #----------------------------------------------------------------------------
571 def unquote_ends(istr):
572 def unquote_ends(istr):
572 """Remove a single pair of quotes from the endpoints of a string."""
573 """Remove a single pair of quotes from the endpoints of a string."""
573
574
574 if not istr:
575 if not istr:
575 return istr
576 return istr
576 if (istr[0]=="'" and istr[-1]=="'") or \
577 if (istr[0]=="'" and istr[-1]=="'") or \
577 (istr[0]=='"' and istr[-1]=='"'):
578 (istr[0]=='"' and istr[-1]=='"'):
578 return istr[1:-1]
579 return istr[1:-1]
579 else:
580 else:
580 return istr
581 return istr
581
582
582 #----------------------------------------------------------------------------
583 #----------------------------------------------------------------------------
583 def process_cmdline(argv,names=[],defaults={},usage=''):
584 def process_cmdline(argv,names=[],defaults={},usage=''):
584 """ Process command-line options and arguments.
585 """ Process command-line options and arguments.
585
586
586 Arguments:
587 Arguments:
587
588
588 - argv: list of arguments, typically sys.argv.
589 - argv: list of arguments, typically sys.argv.
589
590
590 - names: list of option names. See DPyGetOpt docs for details on options
591 - names: list of option names. See DPyGetOpt docs for details on options
591 syntax.
592 syntax.
592
593
593 - defaults: dict of default values.
594 - defaults: dict of default values.
594
595
595 - usage: optional usage notice to print if a wrong argument is passed.
596 - usage: optional usage notice to print if a wrong argument is passed.
596
597
597 Return a dict of options and a list of free arguments."""
598 Return a dict of options and a list of free arguments."""
598
599
599 getopt = DPyGetOpt.DPyGetOpt()
600 getopt = DPyGetOpt.DPyGetOpt()
600 getopt.setIgnoreCase(0)
601 getopt.setIgnoreCase(0)
601 getopt.parseConfiguration(names)
602 getopt.parseConfiguration(names)
602
603
603 try:
604 try:
604 getopt.processArguments(argv)
605 getopt.processArguments(argv)
605 except:
606 except:
606 print usage
607 print usage
607 warn(`sys.exc_value`,level=4)
608 warn(`sys.exc_value`,level=4)
608
609
609 defaults.update(getopt.optionValues)
610 defaults.update(getopt.optionValues)
610 args = getopt.freeValues
611 args = getopt.freeValues
611
612
612 return defaults,args
613 return defaults,args
613
614
614 #----------------------------------------------------------------------------
615 #----------------------------------------------------------------------------
615 def optstr2types(ostr):
616 def optstr2types(ostr):
616 """Convert a string of option names to a dict of type mappings.
617 """Convert a string of option names to a dict of type mappings.
617
618
618 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
619 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
619
620
620 This is used to get the types of all the options in a string formatted
621 This is used to get the types of all the options in a string formatted
621 with the conventions of DPyGetOpt. The 'type' None is used for options
622 with the conventions of DPyGetOpt. The 'type' None is used for options
622 which are strings (they need no further conversion). This function's main
623 which are strings (they need no further conversion). This function's main
623 use is to get a typemap for use with read_dict().
624 use is to get a typemap for use with read_dict().
624 """
625 """
625
626
626 typeconv = {None:'',int:'',float:''}
627 typeconv = {None:'',int:'',float:''}
627 typemap = {'s':None,'i':int,'f':float}
628 typemap = {'s':None,'i':int,'f':float}
628 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
629 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
629
630
630 for w in ostr.split():
631 for w in ostr.split():
631 oname,alias,otype = opt_re.match(w).groups()
632 oname,alias,otype = opt_re.match(w).groups()
632 if otype == '' or alias == '!': # simple switches are integers too
633 if otype == '' or alias == '!': # simple switches are integers too
633 otype = 'i'
634 otype = 'i'
634 typeconv[typemap[otype]] += oname + ' '
635 typeconv[typemap[otype]] += oname + ' '
635 return typeconv
636 return typeconv
636
637
637 #----------------------------------------------------------------------------
638 #----------------------------------------------------------------------------
638 def read_dict(filename,type_conv=None,**opt):
639 def read_dict(filename,type_conv=None,**opt):
639
640
640 """Read a dictionary of key=value pairs from an input file, optionally
641 """Read a dictionary of key=value pairs from an input file, optionally
641 performing conversions on the resulting values.
642 performing conversions on the resulting values.
642
643
643 read_dict(filename,type_conv,**opt) -> dict
644 read_dict(filename,type_conv,**opt) -> dict
644
645
645 Only one value per line is accepted, the format should be
646 Only one value per line is accepted, the format should be
646 # optional comments are ignored
647 # optional comments are ignored
647 key value\n
648 key value\n
648
649
649 Args:
650 Args:
650
651
651 - type_conv: A dictionary specifying which keys need to be converted to
652 - type_conv: A dictionary specifying which keys need to be converted to
652 which types. By default all keys are read as strings. This dictionary
653 which types. By default all keys are read as strings. This dictionary
653 should have as its keys valid conversion functions for strings
654 should have as its keys valid conversion functions for strings
654 (int,long,float,complex, or your own). The value for each key
655 (int,long,float,complex, or your own). The value for each key
655 (converter) should be a whitespace separated string containing the names
656 (converter) should be a whitespace separated string containing the names
656 of all the entries in the file to be converted using that function. For
657 of all the entries in the file to be converted using that function. For
657 keys to be left alone, use None as the conversion function (only needed
658 keys to be left alone, use None as the conversion function (only needed
658 with purge=1, see below).
659 with purge=1, see below).
659
660
660 - opt: dictionary with extra options as below (default in parens)
661 - opt: dictionary with extra options as below (default in parens)
661
662
662 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
663 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
663 of the dictionary to be returned. If purge is going to be used, the
664 of the dictionary to be returned. If purge is going to be used, the
664 set of keys to be left as strings also has to be explicitly specified
665 set of keys to be left as strings also has to be explicitly specified
665 using the (non-existent) conversion function None.
666 using the (non-existent) conversion function None.
666
667
667 fs(None): field separator. This is the key/value separator to be used
668 fs(None): field separator. This is the key/value separator to be used
668 when parsing the file. The None default means any whitespace [behavior
669 when parsing the file. The None default means any whitespace [behavior
669 of string.split()].
670 of string.split()].
670
671
671 strip(0): if 1, strip string values of leading/trailinig whitespace.
672 strip(0): if 1, strip string values of leading/trailinig whitespace.
672
673
673 warn(1): warning level if requested keys are not found in file.
674 warn(1): warning level if requested keys are not found in file.
674 - 0: silently ignore.
675 - 0: silently ignore.
675 - 1: inform but proceed.
676 - 1: inform but proceed.
676 - 2: raise KeyError exception.
677 - 2: raise KeyError exception.
677
678
678 no_empty(0): if 1, remove keys with whitespace strings as a value.
679 no_empty(0): if 1, remove keys with whitespace strings as a value.
679
680
680 unique([]): list of keys (or space separated string) which can't be
681 unique([]): list of keys (or space separated string) which can't be
681 repeated. If one such key is found in the file, each new instance
682 repeated. If one such key is found in the file, each new instance
682 overwrites the previous one. For keys not listed here, the behavior is
683 overwrites the previous one. For keys not listed here, the behavior is
683 to make a list of all appearances.
684 to make a list of all appearances.
684
685
685 Example:
686 Example:
686 If the input file test.ini has:
687 If the input file test.ini has:
687 i 3
688 i 3
688 x 4.5
689 x 4.5
689 y 5.5
690 y 5.5
690 s hi ho
691 s hi ho
691 Then:
692 Then:
692
693
693 >>> type_conv={int:'i',float:'x',None:'s'}
694 >>> type_conv={int:'i',float:'x',None:'s'}
694 >>> read_dict('test.ini')
695 >>> read_dict('test.ini')
695 {'i': '3', 's': 'hi ho', 'x': '4.5', 'y': '5.5'}
696 {'i': '3', 's': 'hi ho', 'x': '4.5', 'y': '5.5'}
696 >>> read_dict('test.ini',type_conv)
697 >>> read_dict('test.ini',type_conv)
697 {'i': 3, 's': 'hi ho', 'x': 4.5, 'y': '5.5'}
698 {'i': 3, 's': 'hi ho', 'x': 4.5, 'y': '5.5'}
698 >>> read_dict('test.ini',type_conv,purge=1)
699 >>> read_dict('test.ini',type_conv,purge=1)
699 {'i': 3, 's': 'hi ho', 'x': 4.5}
700 {'i': 3, 's': 'hi ho', 'x': 4.5}
700 """
701 """
701
702
702 # starting config
703 # starting config
703 opt.setdefault('purge',0)
704 opt.setdefault('purge',0)
704 opt.setdefault('fs',None) # field sep defaults to any whitespace
705 opt.setdefault('fs',None) # field sep defaults to any whitespace
705 opt.setdefault('strip',0)
706 opt.setdefault('strip',0)
706 opt.setdefault('warn',1)
707 opt.setdefault('warn',1)
707 opt.setdefault('no_empty',0)
708 opt.setdefault('no_empty',0)
708 opt.setdefault('unique','')
709 opt.setdefault('unique','')
709 if type(opt['unique']) in StringTypes:
710 if type(opt['unique']) in StringTypes:
710 unique_keys = qw(opt['unique'])
711 unique_keys = qw(opt['unique'])
711 elif type(opt['unique']) in (types.TupleType,types.ListType):
712 elif type(opt['unique']) in (types.TupleType,types.ListType):
712 unique_keys = opt['unique']
713 unique_keys = opt['unique']
713 else:
714 else:
714 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
715 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
715
716
716 dict = {}
717 dict = {}
717 # first read in table of values as strings
718 # first read in table of values as strings
718 file = open(filename,'r')
719 file = open(filename,'r')
719 for line in file.readlines():
720 for line in file.readlines():
720 line = line.strip()
721 line = line.strip()
721 if len(line) and line[0]=='#': continue
722 if len(line) and line[0]=='#': continue
722 if len(line)>0:
723 if len(line)>0:
723 lsplit = line.split(opt['fs'],1)
724 lsplit = line.split(opt['fs'],1)
724 try:
725 try:
725 key,val = lsplit
726 key,val = lsplit
726 except ValueError:
727 except ValueError:
727 key,val = lsplit[0],''
728 key,val = lsplit[0],''
728 key = key.strip()
729 key = key.strip()
729 if opt['strip']: val = val.strip()
730 if opt['strip']: val = val.strip()
730 if val == "''" or val == '""': val = ''
731 if val == "''" or val == '""': val = ''
731 if opt['no_empty'] and (val=='' or val.isspace()):
732 if opt['no_empty'] and (val=='' or val.isspace()):
732 continue
733 continue
733 # if a key is found more than once in the file, build a list
734 # if a key is found more than once in the file, build a list
734 # unless it's in the 'unique' list. In that case, last found in file
735 # unless it's in the 'unique' list. In that case, last found in file
735 # takes precedence. User beware.
736 # takes precedence. User beware.
736 try:
737 try:
737 if dict[key] and key in unique_keys:
738 if dict[key] and key in unique_keys:
738 dict[key] = val
739 dict[key] = val
739 elif type(dict[key]) is types.ListType:
740 elif type(dict[key]) is types.ListType:
740 dict[key].append(val)
741 dict[key].append(val)
741 else:
742 else:
742 dict[key] = [dict[key],val]
743 dict[key] = [dict[key],val]
743 except KeyError:
744 except KeyError:
744 dict[key] = val
745 dict[key] = val
745 # purge if requested
746 # purge if requested
746 if opt['purge']:
747 if opt['purge']:
747 accepted_keys = qwflat(type_conv.values())
748 accepted_keys = qwflat(type_conv.values())
748 for key in dict.keys():
749 for key in dict.keys():
749 if key in accepted_keys: continue
750 if key in accepted_keys: continue
750 del(dict[key])
751 del(dict[key])
751 # now convert if requested
752 # now convert if requested
752 if type_conv==None: return dict
753 if type_conv==None: return dict
753 conversions = type_conv.keys()
754 conversions = type_conv.keys()
754 try: conversions.remove(None)
755 try: conversions.remove(None)
755 except: pass
756 except: pass
756 for convert in conversions:
757 for convert in conversions:
757 for val in qw(type_conv[convert]):
758 for val in qw(type_conv[convert]):
758 try:
759 try:
759 dict[val] = convert(dict[val])
760 dict[val] = convert(dict[val])
760 except KeyError,e:
761 except KeyError,e:
761 if opt['warn'] == 0:
762 if opt['warn'] == 0:
762 pass
763 pass
763 elif opt['warn'] == 1:
764 elif opt['warn'] == 1:
764 print >>sys.stderr, 'Warning: key',val,\
765 print >>sys.stderr, 'Warning: key',val,\
765 'not found in file',filename
766 'not found in file',filename
766 elif opt['warn'] == 2:
767 elif opt['warn'] == 2:
767 raise KeyError,e
768 raise KeyError,e
768 else:
769 else:
769 raise ValueError,'Warning level must be 0,1 or 2'
770 raise ValueError,'Warning level must be 0,1 or 2'
770
771
771 return dict
772 return dict
772
773
773 #----------------------------------------------------------------------------
774 #----------------------------------------------------------------------------
774 def flag_calls(func):
775 def flag_calls(func):
775 """Wrap a function to detect and flag when it gets called.
776 """Wrap a function to detect and flag when it gets called.
776
777
777 This is a decorator which takes a function and wraps it in a function with
778 This is a decorator which takes a function and wraps it in a function with
778 a 'called' attribute. wrapper.called is initialized to False.
779 a 'called' attribute. wrapper.called is initialized to False.
779
780
780 The wrapper.called attribute is set to False right before each call to the
781 The wrapper.called attribute is set to False right before each call to the
781 wrapped function, so if the call fails it remains False. After the call
782 wrapped function, so if the call fails it remains False. After the call
782 completes, wrapper.called is set to True and the output is returned.
783 completes, wrapper.called is set to True and the output is returned.
783
784
784 Testing for truth in wrapper.called allows you to determine if a call to
785 Testing for truth in wrapper.called allows you to determine if a call to
785 func() was attempted and succeeded."""
786 func() was attempted and succeeded."""
786
787
787 def wrapper(*args,**kw):
788 def wrapper(*args,**kw):
788 wrapper.called = False
789 wrapper.called = False
789 out = func(*args,**kw)
790 out = func(*args,**kw)
790 wrapper.called = True
791 wrapper.called = True
791 return out
792 return out
792
793
793 wrapper.called = False
794 wrapper.called = False
794 wrapper.__doc__ = func.__doc__
795 wrapper.__doc__ = func.__doc__
795 return wrapper
796 return wrapper
796
797
797 #----------------------------------------------------------------------------
798 #----------------------------------------------------------------------------
798 class HomeDirError(Error):
799 class HomeDirError(Error):
799 pass
800 pass
800
801
801 def get_home_dir():
802 def get_home_dir():
802 """Return the closest possible equivalent to a 'home' directory.
803 """Return the closest possible equivalent to a 'home' directory.
803
804
804 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
805 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
805
806
806 Currently only Posix and NT are implemented, a HomeDirError exception is
807 Currently only Posix and NT are implemented, a HomeDirError exception is
807 raised for all other OSes. """
808 raised for all other OSes. """
808
809
809 isdir = os.path.isdir
810 isdir = os.path.isdir
810 env = os.environ
811 env = os.environ
811
812
812 # first, check py2exe distribution root directory for _ipython.
813 # first, check py2exe distribution root directory for _ipython.
813 # This overrides all. Normally does not exist.
814 # This overrides all. Normally does not exist.
814 if '\\library.zip\\' in IPython.__file__.lower():
815 if '\\library.zip\\' in IPython.__file__.lower():
815 root, rest = IPython.__file__.lower().split('library.zip')
816 root, rest = IPython.__file__.lower().split('library.zip')
816 if os.path.isdir(root + '_ipython'):
817 if os.path.isdir(root + '_ipython'):
817 return root
818 return root
818
819
819 try:
820 try:
820 homedir = env['HOME']
821 homedir = env['HOME']
821 if not isdir(homedir):
822 if not isdir(homedir):
822 # in case a user stuck some string which does NOT resolve to a
823 # in case a user stuck some string which does NOT resolve to a
823 # valid path, it's as good as if we hadn't foud it
824 # valid path, it's as good as if we hadn't foud it
824 raise KeyError
825 raise KeyError
825 return homedir
826 return homedir
826 except KeyError:
827 except KeyError:
827 if os.name == 'posix':
828 if os.name == 'posix':
828 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
829 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
829 elif os.name == 'nt':
830 elif os.name == 'nt':
830 # For some strange reason, win9x returns 'nt' for os.name.
831 # For some strange reason, win9x returns 'nt' for os.name.
831 try:
832 try:
832 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
833 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
833 if not isdir(homedir):
834 if not isdir(homedir):
834 homedir = os.path.join(env['USERPROFILE'])
835 homedir = os.path.join(env['USERPROFILE'])
835 if not isdir(homedir):
836 if not isdir(homedir):
836 raise HomeDirError
837 raise HomeDirError
837 return homedir
838 return homedir
838 except:
839 except:
839 try:
840 try:
840 # Use the registry to get the 'My Documents' folder.
841 # Use the registry to get the 'My Documents' folder.
841 import _winreg as wreg
842 import _winreg as wreg
842 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
843 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
843 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
844 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
844 homedir = wreg.QueryValueEx(key,'Personal')[0]
845 homedir = wreg.QueryValueEx(key,'Personal')[0]
845 key.Close()
846 key.Close()
846 if not isdir(homedir):
847 if not isdir(homedir):
847 e = ('Invalid "Personal" folder registry key '
848 e = ('Invalid "Personal" folder registry key '
848 'typically "My Documents".\n'
849 'typically "My Documents".\n'
849 'Value: %s\n'
850 'Value: %s\n'
850 'This is not a valid directory on your system.' %
851 'This is not a valid directory on your system.' %
851 homedir)
852 homedir)
852 raise HomeDirError(e)
853 raise HomeDirError(e)
853 return homedir
854 return homedir
854 except HomeDirError:
855 except HomeDirError:
855 raise
856 raise
856 except:
857 except:
857 return 'C:\\'
858 return 'C:\\'
858 elif os.name == 'dos':
859 elif os.name == 'dos':
859 # Desperate, may do absurd things in classic MacOS. May work under DOS.
860 # Desperate, may do absurd things in classic MacOS. May work under DOS.
860 return 'C:\\'
861 return 'C:\\'
861 else:
862 else:
862 raise HomeDirError,'support for your operating system not implemented.'
863 raise HomeDirError,'support for your operating system not implemented.'
863
864
864 #****************************************************************************
865 #****************************************************************************
865 # strings and text
866 # strings and text
866
867
867 class LSString(str):
868 class LSString(str):
868 """String derivative with a special access attributes.
869 """String derivative with a special access attributes.
869
870
870 These are normal strings, but with the special attributes:
871 These are normal strings, but with the special attributes:
871
872
872 .l (or .list) : value as list (split on newlines).
873 .l (or .list) : value as list (split on newlines).
873 .n (or .nlstr): original value (the string itself).
874 .n (or .nlstr): original value (the string itself).
874 .s (or .spstr): value as whitespace-separated string.
875 .s (or .spstr): value as whitespace-separated string.
876 .p (or .paths): list of path objects
875
877
876 Any values which require transformations are computed only once and
878 Any values which require transformations are computed only once and
877 cached.
879 cached.
878
880
879 Such strings are very useful to efficiently interact with the shell, which
881 Such strings are very useful to efficiently interact with the shell, which
880 typically only understands whitespace-separated options for commands."""
882 typically only understands whitespace-separated options for commands."""
881
883
882 def get_list(self):
884 def get_list(self):
883 try:
885 try:
884 return self.__list
886 return self.__list
885 except AttributeError:
887 except AttributeError:
886 self.__list = self.split('\n')
888 self.__list = self.split('\n')
887 return self.__list
889 return self.__list
888
890
889 l = list = property(get_list)
891 l = list = property(get_list)
890
892
891 def get_spstr(self):
893 def get_spstr(self):
892 try:
894 try:
893 return self.__spstr
895 return self.__spstr
894 except AttributeError:
896 except AttributeError:
895 self.__spstr = self.replace('\n',' ')
897 self.__spstr = self.replace('\n',' ')
896 return self.__spstr
898 return self.__spstr
897
899
898 s = spstr = property(get_spstr)
900 s = spstr = property(get_spstr)
899
901
900 def get_nlstr(self):
902 def get_nlstr(self):
901 return self
903 return self
902
904
903 n = nlstr = property(get_nlstr)
905 n = nlstr = property(get_nlstr)
904
906
905 def get_paths(self):
907 def get_paths(self):
906 try:
908 try:
907 return self.__paths
909 return self.__paths
908 except AttributeError:
910 except AttributeError:
909 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
911 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
910 return self.__paths
912 return self.__paths
911
913
912 p = paths = property(get_paths)
914 p = paths = property(get_paths)
913
915
914
916
917
918 def print_lsstring(arg):
919 """ Prettier (non-repr-like) and more informative printer for LSString """
920 print "LSString (.p, .n, .l, .s available). Value:"
921 print arg
922
923 print_lsstring = result_display.when_type(LSString)(print_lsstring)
924
915 #----------------------------------------------------------------------------
925 #----------------------------------------------------------------------------
916 class SList(list):
926 class SList(list):
917 """List derivative with a special access attributes.
927 """List derivative with a special access attributes.
918
928
919 These are normal lists, but with the special attributes:
929 These are normal lists, but with the special attributes:
920
930
921 .l (or .list) : value as list (the list itself).
931 .l (or .list) : value as list (the list itself).
922 .n (or .nlstr): value as a string, joined on newlines.
932 .n (or .nlstr): value as a string, joined on newlines.
923 .s (or .spstr): value as a string, joined on spaces.
933 .s (or .spstr): value as a string, joined on spaces.
924
934 .p (or .paths): list of path objects
935
925 Any values which require transformations are computed only once and
936 Any values which require transformations are computed only once and
926 cached."""
937 cached."""
927
938
928 def get_list(self):
939 def get_list(self):
929 return self
940 return self
930
941
931 l = list = property(get_list)
942 l = list = property(get_list)
932
943
933 def get_spstr(self):
944 def get_spstr(self):
934 try:
945 try:
935 return self.__spstr
946 return self.__spstr
936 except AttributeError:
947 except AttributeError:
937 self.__spstr = ' '.join(self)
948 self.__spstr = ' '.join(self)
938 return self.__spstr
949 return self.__spstr
939
950
940 s = spstr = property(get_spstr)
951 s = spstr = property(get_spstr)
941
952
942 def get_nlstr(self):
953 def get_nlstr(self):
943 try:
954 try:
944 return self.__nlstr
955 return self.__nlstr
945 except AttributeError:
956 except AttributeError:
946 self.__nlstr = '\n'.join(self)
957 self.__nlstr = '\n'.join(self)
947 return self.__nlstr
958 return self.__nlstr
948
959
949 n = nlstr = property(get_nlstr)
960 n = nlstr = property(get_nlstr)
950
961
951 def get_paths(self):
962 def get_paths(self):
952 try:
963 try:
953 return self.__paths
964 return self.__paths
954 except AttributeError:
965 except AttributeError:
955 self.__paths = [path(p) for p in self if os.path.exists(p)]
966 self.__paths = [path(p) for p in self if os.path.exists(p)]
956 return self.__paths
967 return self.__paths
957
968
958 p = paths = property(get_paths)
969 p = paths = property(get_paths)
959
970
960 #----------------------------------------------------------------------------
971 #----------------------------------------------------------------------------
961 def esc_quotes(strng):
972 def esc_quotes(strng):
962 """Return the input string with single and double quotes escaped out"""
973 """Return the input string with single and double quotes escaped out"""
963
974
964 return strng.replace('"','\\"').replace("'","\\'")
975 return strng.replace('"','\\"').replace("'","\\'")
965
976
966 #----------------------------------------------------------------------------
977 #----------------------------------------------------------------------------
967 def make_quoted_expr(s):
978 def make_quoted_expr(s):
968 """Return string s in appropriate quotes, using raw string if possible.
979 """Return string s in appropriate quotes, using raw string if possible.
969
980
970 Effectively this turns string: cd \ao\ao\
981 Effectively this turns string: cd \ao\ao\
971 to: r"cd \ao\ao\_"[:-1]
982 to: r"cd \ao\ao\_"[:-1]
972
983
973 Note the use of raw string and padding at the end to allow trailing backslash.
984 Note the use of raw string and padding at the end to allow trailing backslash.
974
985
975 """
986 """
976
987
977 tail = ''
988 tail = ''
978 tailpadding = ''
989 tailpadding = ''
979 raw = ''
990 raw = ''
980 if "\\" in s:
991 if "\\" in s:
981 raw = 'r'
992 raw = 'r'
982 if s.endswith('\\'):
993 if s.endswith('\\'):
983 tail = '[:-1]'
994 tail = '[:-1]'
984 tailpadding = '_'
995 tailpadding = '_'
985 if '"' not in s:
996 if '"' not in s:
986 quote = '"'
997 quote = '"'
987 elif "'" not in s:
998 elif "'" not in s:
988 quote = "'"
999 quote = "'"
989 elif '"""' not in s and not s.endswith('"'):
1000 elif '"""' not in s and not s.endswith('"'):
990 quote = '"""'
1001 quote = '"""'
991 elif "'''" not in s and not s.endswith("'"):
1002 elif "'''" not in s and not s.endswith("'"):
992 quote = "'''"
1003 quote = "'''"
993 else:
1004 else:
994 # give up, backslash-escaped string will do
1005 # give up, backslash-escaped string will do
995 return '"%s"' % esc_quotes(s)
1006 return '"%s"' % esc_quotes(s)
996 res = itpl("$raw$quote$s$tailpadding$quote$tail")
1007 res = itpl("$raw$quote$s$tailpadding$quote$tail")
997 return res
1008 return res
998
1009
999
1010
1000 #----------------------------------------------------------------------------
1011 #----------------------------------------------------------------------------
1001 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1012 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1002 """Take multiple lines of input.
1013 """Take multiple lines of input.
1003
1014
1004 A list with each line of input as a separate element is returned when a
1015 A list with each line of input as a separate element is returned when a
1005 termination string is entered (defaults to a single '.'). Input can also
1016 termination string is entered (defaults to a single '.'). Input can also
1006 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1017 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1007
1018
1008 Lines of input which end in \\ are joined into single entries (and a
1019 Lines of input which end in \\ are joined into single entries (and a
1009 secondary continuation prompt is issued as long as the user terminates
1020 secondary continuation prompt is issued as long as the user terminates
1010 lines with \\). This allows entering very long strings which are still
1021 lines with \\). This allows entering very long strings which are still
1011 meant to be treated as single entities.
1022 meant to be treated as single entities.
1012 """
1023 """
1013
1024
1014 try:
1025 try:
1015 if header:
1026 if header:
1016 header += '\n'
1027 header += '\n'
1017 lines = [raw_input(header + ps1)]
1028 lines = [raw_input(header + ps1)]
1018 except EOFError:
1029 except EOFError:
1019 return []
1030 return []
1020 terminate = [terminate_str]
1031 terminate = [terminate_str]
1021 try:
1032 try:
1022 while lines[-1:] != terminate:
1033 while lines[-1:] != terminate:
1023 new_line = raw_input(ps1)
1034 new_line = raw_input(ps1)
1024 while new_line.endswith('\\'):
1035 while new_line.endswith('\\'):
1025 new_line = new_line[:-1] + raw_input(ps2)
1036 new_line = new_line[:-1] + raw_input(ps2)
1026 lines.append(new_line)
1037 lines.append(new_line)
1027
1038
1028 return lines[:-1] # don't return the termination command
1039 return lines[:-1] # don't return the termination command
1029 except EOFError:
1040 except EOFError:
1030 print
1041 print
1031 return lines
1042 return lines
1032
1043
1033 #----------------------------------------------------------------------------
1044 #----------------------------------------------------------------------------
1034 def raw_input_ext(prompt='', ps2='... '):
1045 def raw_input_ext(prompt='', ps2='... '):
1035 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1046 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1036
1047
1037 line = raw_input(prompt)
1048 line = raw_input(prompt)
1038 while line.endswith('\\'):
1049 while line.endswith('\\'):
1039 line = line[:-1] + raw_input(ps2)
1050 line = line[:-1] + raw_input(ps2)
1040 return line
1051 return line
1041
1052
1042 #----------------------------------------------------------------------------
1053 #----------------------------------------------------------------------------
1043 def ask_yes_no(prompt,default=None):
1054 def ask_yes_no(prompt,default=None):
1044 """Asks a question and returns an integer 1/0 (y/n) answer.
1055 """Asks a question and returns an integer 1/0 (y/n) answer.
1045
1056
1046 If default is given (one of 'y','n'), it is used if the user input is
1057 If default is given (one of 'y','n'), it is used if the user input is
1047 empty. Otherwise the question is repeated until an answer is given.
1058 empty. Otherwise the question is repeated until an answer is given.
1048
1059
1049 An EOF is treated as the default answer. If there is no default, an
1060 An EOF is treated as the default answer. If there is no default, an
1050 exception is raised to prevent infinite loops.
1061 exception is raised to prevent infinite loops.
1051
1062
1052 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1063 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1053
1064
1054 answers = {'y':True,'n':False,'yes':True,'no':False}
1065 answers = {'y':True,'n':False,'yes':True,'no':False}
1055 ans = None
1066 ans = None
1056 while ans not in answers.keys():
1067 while ans not in answers.keys():
1057 try:
1068 try:
1058 ans = raw_input(prompt+' ').lower()
1069 ans = raw_input(prompt+' ').lower()
1059 if not ans: # response was an empty string
1070 if not ans: # response was an empty string
1060 ans = default
1071 ans = default
1061 except KeyboardInterrupt:
1072 except KeyboardInterrupt:
1062 pass
1073 pass
1063 except EOFError:
1074 except EOFError:
1064 if default in answers.keys():
1075 if default in answers.keys():
1065 ans = default
1076 ans = default
1066 print
1077 print
1067 else:
1078 else:
1068 raise
1079 raise
1069
1080
1070 return answers[ans]
1081 return answers[ans]
1071
1082
1072 #----------------------------------------------------------------------------
1083 #----------------------------------------------------------------------------
1073 def marquee(txt='',width=78,mark='*'):
1084 def marquee(txt='',width=78,mark='*'):
1074 """Return the input string centered in a 'marquee'."""
1085 """Return the input string centered in a 'marquee'."""
1075 if not txt:
1086 if not txt:
1076 return (mark*width)[:width]
1087 return (mark*width)[:width]
1077 nmark = (width-len(txt)-2)/len(mark)/2
1088 nmark = (width-len(txt)-2)/len(mark)/2
1078 if nmark < 0: nmark =0
1089 if nmark < 0: nmark =0
1079 marks = mark*nmark
1090 marks = mark*nmark
1080 return '%s %s %s' % (marks,txt,marks)
1091 return '%s %s %s' % (marks,txt,marks)
1081
1092
1082 #----------------------------------------------------------------------------
1093 #----------------------------------------------------------------------------
1083 class EvalDict:
1094 class EvalDict:
1084 """
1095 """
1085 Emulate a dict which evaluates its contents in the caller's frame.
1096 Emulate a dict which evaluates its contents in the caller's frame.
1086
1097
1087 Usage:
1098 Usage:
1088 >>>number = 19
1099 >>>number = 19
1089 >>>text = "python"
1100 >>>text = "python"
1090 >>>print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1101 >>>print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1091 """
1102 """
1092
1103
1093 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1104 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1094 # modified (shorter) version of:
1105 # modified (shorter) version of:
1095 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1106 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1096 # Skip Montanaro (skip@pobox.com).
1107 # Skip Montanaro (skip@pobox.com).
1097
1108
1098 def __getitem__(self, name):
1109 def __getitem__(self, name):
1099 frame = sys._getframe(1)
1110 frame = sys._getframe(1)
1100 return eval(name, frame.f_globals, frame.f_locals)
1111 return eval(name, frame.f_globals, frame.f_locals)
1101
1112
1102 EvalString = EvalDict # for backwards compatibility
1113 EvalString = EvalDict # for backwards compatibility
1103 #----------------------------------------------------------------------------
1114 #----------------------------------------------------------------------------
1104 def qw(words,flat=0,sep=None,maxsplit=-1):
1115 def qw(words,flat=0,sep=None,maxsplit=-1):
1105 """Similar to Perl's qw() operator, but with some more options.
1116 """Similar to Perl's qw() operator, but with some more options.
1106
1117
1107 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1118 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1108
1119
1109 words can also be a list itself, and with flat=1, the output will be
1120 words can also be a list itself, and with flat=1, the output will be
1110 recursively flattened. Examples:
1121 recursively flattened. Examples:
1111
1122
1112 >>> qw('1 2')
1123 >>> qw('1 2')
1113 ['1', '2']
1124 ['1', '2']
1114 >>> qw(['a b','1 2',['m n','p q']])
1125 >>> qw(['a b','1 2',['m n','p q']])
1115 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1126 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1116 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1127 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1117 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] """
1128 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] """
1118
1129
1119 if type(words) in StringTypes:
1130 if type(words) in StringTypes:
1120 return [word.strip() for word in words.split(sep,maxsplit)
1131 return [word.strip() for word in words.split(sep,maxsplit)
1121 if word and not word.isspace() ]
1132 if word and not word.isspace() ]
1122 if flat:
1133 if flat:
1123 return flatten(map(qw,words,[1]*len(words)))
1134 return flatten(map(qw,words,[1]*len(words)))
1124 return map(qw,words)
1135 return map(qw,words)
1125
1136
1126 #----------------------------------------------------------------------------
1137 #----------------------------------------------------------------------------
1127 def qwflat(words,sep=None,maxsplit=-1):
1138 def qwflat(words,sep=None,maxsplit=-1):
1128 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1139 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1129 return qw(words,1,sep,maxsplit)
1140 return qw(words,1,sep,maxsplit)
1130
1141
1131 #----------------------------------------------------------------------------
1142 #----------------------------------------------------------------------------
1132 def qw_lol(indata):
1143 def qw_lol(indata):
1133 """qw_lol('a b') -> [['a','b']],
1144 """qw_lol('a b') -> [['a','b']],
1134 otherwise it's just a call to qw().
1145 otherwise it's just a call to qw().
1135
1146
1136 We need this to make sure the modules_some keys *always* end up as a
1147 We need this to make sure the modules_some keys *always* end up as a
1137 list of lists."""
1148 list of lists."""
1138
1149
1139 if type(indata) in StringTypes:
1150 if type(indata) in StringTypes:
1140 return [qw(indata)]
1151 return [qw(indata)]
1141 else:
1152 else:
1142 return qw(indata)
1153 return qw(indata)
1143
1154
1144 #-----------------------------------------------------------------------------
1155 #-----------------------------------------------------------------------------
1145 def list_strings(arg):
1156 def list_strings(arg):
1146 """Always return a list of strings, given a string or list of strings
1157 """Always return a list of strings, given a string or list of strings
1147 as input."""
1158 as input."""
1148
1159
1149 if type(arg) in StringTypes: return [arg]
1160 if type(arg) in StringTypes: return [arg]
1150 else: return arg
1161 else: return arg
1151
1162
1152 #----------------------------------------------------------------------------
1163 #----------------------------------------------------------------------------
1153 def grep(pat,list,case=1):
1164 def grep(pat,list,case=1):
1154 """Simple minded grep-like function.
1165 """Simple minded grep-like function.
1155 grep(pat,list) returns occurrences of pat in list, None on failure.
1166 grep(pat,list) returns occurrences of pat in list, None on failure.
1156
1167
1157 It only does simple string matching, with no support for regexps. Use the
1168 It only does simple string matching, with no support for regexps. Use the
1158 option case=0 for case-insensitive matching."""
1169 option case=0 for case-insensitive matching."""
1159
1170
1160 # This is pretty crude. At least it should implement copying only references
1171 # This is pretty crude. At least it should implement copying only references
1161 # to the original data in case it's big. Now it copies the data for output.
1172 # to the original data in case it's big. Now it copies the data for output.
1162 out=[]
1173 out=[]
1163 if case:
1174 if case:
1164 for term in list:
1175 for term in list:
1165 if term.find(pat)>-1: out.append(term)
1176 if term.find(pat)>-1: out.append(term)
1166 else:
1177 else:
1167 lpat=pat.lower()
1178 lpat=pat.lower()
1168 for term in list:
1179 for term in list:
1169 if term.lower().find(lpat)>-1: out.append(term)
1180 if term.lower().find(lpat)>-1: out.append(term)
1170
1181
1171 if len(out): return out
1182 if len(out): return out
1172 else: return None
1183 else: return None
1173
1184
1174 #----------------------------------------------------------------------------
1185 #----------------------------------------------------------------------------
1175 def dgrep(pat,*opts):
1186 def dgrep(pat,*opts):
1176 """Return grep() on dir()+dir(__builtins__).
1187 """Return grep() on dir()+dir(__builtins__).
1177
1188
1178 A very common use of grep() when working interactively."""
1189 A very common use of grep() when working interactively."""
1179
1190
1180 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1191 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1181
1192
1182 #----------------------------------------------------------------------------
1193 #----------------------------------------------------------------------------
1183 def idgrep(pat):
1194 def idgrep(pat):
1184 """Case-insensitive dgrep()"""
1195 """Case-insensitive dgrep()"""
1185
1196
1186 return dgrep(pat,0)
1197 return dgrep(pat,0)
1187
1198
1188 #----------------------------------------------------------------------------
1199 #----------------------------------------------------------------------------
1189 def igrep(pat,list):
1200 def igrep(pat,list):
1190 """Synonym for case-insensitive grep."""
1201 """Synonym for case-insensitive grep."""
1191
1202
1192 return grep(pat,list,case=0)
1203 return grep(pat,list,case=0)
1193
1204
1194 #----------------------------------------------------------------------------
1205 #----------------------------------------------------------------------------
1195 def indent(str,nspaces=4,ntabs=0):
1206 def indent(str,nspaces=4,ntabs=0):
1196 """Indent a string a given number of spaces or tabstops.
1207 """Indent a string a given number of spaces or tabstops.
1197
1208
1198 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1209 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1199 """
1210 """
1200 if str is None:
1211 if str is None:
1201 return
1212 return
1202 ind = '\t'*ntabs+' '*nspaces
1213 ind = '\t'*ntabs+' '*nspaces
1203 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1214 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1204 if outstr.endswith(os.linesep+ind):
1215 if outstr.endswith(os.linesep+ind):
1205 return outstr[:-len(ind)]
1216 return outstr[:-len(ind)]
1206 else:
1217 else:
1207 return outstr
1218 return outstr
1208
1219
1209 #-----------------------------------------------------------------------------
1220 #-----------------------------------------------------------------------------
1210 def native_line_ends(filename,backup=1):
1221 def native_line_ends(filename,backup=1):
1211 """Convert (in-place) a file to line-ends native to the current OS.
1222 """Convert (in-place) a file to line-ends native to the current OS.
1212
1223
1213 If the optional backup argument is given as false, no backup of the
1224 If the optional backup argument is given as false, no backup of the
1214 original file is left. """
1225 original file is left. """
1215
1226
1216 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1227 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1217
1228
1218 bak_filename = filename + backup_suffixes[os.name]
1229 bak_filename = filename + backup_suffixes[os.name]
1219
1230
1220 original = open(filename).read()
1231 original = open(filename).read()
1221 shutil.copy2(filename,bak_filename)
1232 shutil.copy2(filename,bak_filename)
1222 try:
1233 try:
1223 new = open(filename,'wb')
1234 new = open(filename,'wb')
1224 new.write(os.linesep.join(original.splitlines()))
1235 new.write(os.linesep.join(original.splitlines()))
1225 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1236 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1226 new.close()
1237 new.close()
1227 except:
1238 except:
1228 os.rename(bak_filename,filename)
1239 os.rename(bak_filename,filename)
1229 if not backup:
1240 if not backup:
1230 try:
1241 try:
1231 os.remove(bak_filename)
1242 os.remove(bak_filename)
1232 except:
1243 except:
1233 pass
1244 pass
1234
1245
1235 #----------------------------------------------------------------------------
1246 #----------------------------------------------------------------------------
1236 def get_pager_cmd(pager_cmd = None):
1247 def get_pager_cmd(pager_cmd = None):
1237 """Return a pager command.
1248 """Return a pager command.
1238
1249
1239 Makes some attempts at finding an OS-correct one."""
1250 Makes some attempts at finding an OS-correct one."""
1240
1251
1241 if os.name == 'posix':
1252 if os.name == 'posix':
1242 default_pager_cmd = 'less -r' # -r for color control sequences
1253 default_pager_cmd = 'less -r' # -r for color control sequences
1243 elif os.name in ['nt','dos']:
1254 elif os.name in ['nt','dos']:
1244 default_pager_cmd = 'type'
1255 default_pager_cmd = 'type'
1245
1256
1246 if pager_cmd is None:
1257 if pager_cmd is None:
1247 try:
1258 try:
1248 pager_cmd = os.environ['PAGER']
1259 pager_cmd = os.environ['PAGER']
1249 except:
1260 except:
1250 pager_cmd = default_pager_cmd
1261 pager_cmd = default_pager_cmd
1251 return pager_cmd
1262 return pager_cmd
1252
1263
1253 #-----------------------------------------------------------------------------
1264 #-----------------------------------------------------------------------------
1254 def get_pager_start(pager,start):
1265 def get_pager_start(pager,start):
1255 """Return the string for paging files with an offset.
1266 """Return the string for paging files with an offset.
1256
1267
1257 This is the '+N' argument which less and more (under Unix) accept.
1268 This is the '+N' argument which less and more (under Unix) accept.
1258 """
1269 """
1259
1270
1260 if pager in ['less','more']:
1271 if pager in ['less','more']:
1261 if start:
1272 if start:
1262 start_string = '+' + str(start)
1273 start_string = '+' + str(start)
1263 else:
1274 else:
1264 start_string = ''
1275 start_string = ''
1265 else:
1276 else:
1266 start_string = ''
1277 start_string = ''
1267 return start_string
1278 return start_string
1268
1279
1269 #----------------------------------------------------------------------------
1280 #----------------------------------------------------------------------------
1270 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
1281 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
1271 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
1282 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
1272 import msvcrt
1283 import msvcrt
1273 def page_more():
1284 def page_more():
1274 """ Smart pausing between pages
1285 """ Smart pausing between pages
1275
1286
1276 @return: True if need print more lines, False if quit
1287 @return: True if need print more lines, False if quit
1277 """
1288 """
1278 Term.cout.write('---Return to continue, q to quit--- ')
1289 Term.cout.write('---Return to continue, q to quit--- ')
1279 ans = msvcrt.getch()
1290 ans = msvcrt.getch()
1280 if ans in ("q", "Q"):
1291 if ans in ("q", "Q"):
1281 result = False
1292 result = False
1282 else:
1293 else:
1283 result = True
1294 result = True
1284 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1295 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1285 return result
1296 return result
1286 else:
1297 else:
1287 def page_more():
1298 def page_more():
1288 ans = raw_input('---Return to continue, q to quit--- ')
1299 ans = raw_input('---Return to continue, q to quit--- ')
1289 if ans.lower().startswith('q'):
1300 if ans.lower().startswith('q'):
1290 return False
1301 return False
1291 else:
1302 else:
1292 return True
1303 return True
1293
1304
1294 esc_re = re.compile(r"(\x1b[^m]+m)")
1305 esc_re = re.compile(r"(\x1b[^m]+m)")
1295
1306
1296 def page_dumb(strng,start=0,screen_lines=25):
1307 def page_dumb(strng,start=0,screen_lines=25):
1297 """Very dumb 'pager' in Python, for when nothing else works.
1308 """Very dumb 'pager' in Python, for when nothing else works.
1298
1309
1299 Only moves forward, same interface as page(), except for pager_cmd and
1310 Only moves forward, same interface as page(), except for pager_cmd and
1300 mode."""
1311 mode."""
1301
1312
1302 out_ln = strng.splitlines()[start:]
1313 out_ln = strng.splitlines()[start:]
1303 screens = chop(out_ln,screen_lines-1)
1314 screens = chop(out_ln,screen_lines-1)
1304 if len(screens) == 1:
1315 if len(screens) == 1:
1305 print >>Term.cout, os.linesep.join(screens[0])
1316 print >>Term.cout, os.linesep.join(screens[0])
1306 else:
1317 else:
1307 last_escape = ""
1318 last_escape = ""
1308 for scr in screens[0:-1]:
1319 for scr in screens[0:-1]:
1309 hunk = os.linesep.join(scr)
1320 hunk = os.linesep.join(scr)
1310 print >>Term.cout, last_escape + hunk
1321 print >>Term.cout, last_escape + hunk
1311 if not page_more():
1322 if not page_more():
1312 return
1323 return
1313 esc_list = esc_re.findall(hunk)
1324 esc_list = esc_re.findall(hunk)
1314 if len(esc_list) > 0:
1325 if len(esc_list) > 0:
1315 last_escape = esc_list[-1]
1326 last_escape = esc_list[-1]
1316 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1327 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1317
1328
1318 #----------------------------------------------------------------------------
1329 #----------------------------------------------------------------------------
1319 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1330 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1320 """Print a string, piping through a pager after a certain length.
1331 """Print a string, piping through a pager after a certain length.
1321
1332
1322 The screen_lines parameter specifies the number of *usable* lines of your
1333 The screen_lines parameter specifies the number of *usable* lines of your
1323 terminal screen (total lines minus lines you need to reserve to show other
1334 terminal screen (total lines minus lines you need to reserve to show other
1324 information).
1335 information).
1325
1336
1326 If you set screen_lines to a number <=0, page() will try to auto-determine
1337 If you set screen_lines to a number <=0, page() will try to auto-determine
1327 your screen size and will only use up to (screen_size+screen_lines) for
1338 your screen size and will only use up to (screen_size+screen_lines) for
1328 printing, paging after that. That is, if you want auto-detection but need
1339 printing, paging after that. That is, if you want auto-detection but need
1329 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1340 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1330 auto-detection without any lines reserved simply use screen_lines = 0.
1341 auto-detection without any lines reserved simply use screen_lines = 0.
1331
1342
1332 If a string won't fit in the allowed lines, it is sent through the
1343 If a string won't fit in the allowed lines, it is sent through the
1333 specified pager command. If none given, look for PAGER in the environment,
1344 specified pager command. If none given, look for PAGER in the environment,
1334 and ultimately default to less.
1345 and ultimately default to less.
1335
1346
1336 If no system pager works, the string is sent through a 'dumb pager'
1347 If no system pager works, the string is sent through a 'dumb pager'
1337 written in python, very simplistic.
1348 written in python, very simplistic.
1338 """
1349 """
1339
1350
1340 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1351 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1341 TERM = os.environ.get('TERM','dumb')
1352 TERM = os.environ.get('TERM','dumb')
1342 if TERM in ['dumb','emacs'] and os.name != 'nt':
1353 if TERM in ['dumb','emacs'] and os.name != 'nt':
1343 print strng
1354 print strng
1344 return
1355 return
1345 # chop off the topmost part of the string we don't want to see
1356 # chop off the topmost part of the string we don't want to see
1346 str_lines = strng.split(os.linesep)[start:]
1357 str_lines = strng.split(os.linesep)[start:]
1347 str_toprint = os.linesep.join(str_lines)
1358 str_toprint = os.linesep.join(str_lines)
1348 num_newlines = len(str_lines)
1359 num_newlines = len(str_lines)
1349 len_str = len(str_toprint)
1360 len_str = len(str_toprint)
1350
1361
1351 # Dumb heuristics to guesstimate number of on-screen lines the string
1362 # Dumb heuristics to guesstimate number of on-screen lines the string
1352 # takes. Very basic, but good enough for docstrings in reasonable
1363 # takes. Very basic, but good enough for docstrings in reasonable
1353 # terminals. If someone later feels like refining it, it's not hard.
1364 # terminals. If someone later feels like refining it, it's not hard.
1354 numlines = max(num_newlines,int(len_str/80)+1)
1365 numlines = max(num_newlines,int(len_str/80)+1)
1355
1366
1356 if os.name == "nt":
1367 if os.name == "nt":
1357 screen_lines_def = get_console_size(defaulty=25)[1]
1368 screen_lines_def = get_console_size(defaulty=25)[1]
1358 else:
1369 else:
1359 screen_lines_def = 25 # default value if we can't auto-determine
1370 screen_lines_def = 25 # default value if we can't auto-determine
1360
1371
1361 # auto-determine screen size
1372 # auto-determine screen size
1362 if screen_lines <= 0:
1373 if screen_lines <= 0:
1363 if TERM=='xterm':
1374 if TERM=='xterm':
1364 try:
1375 try:
1365 import curses
1376 import curses
1366 if hasattr(curses,'initscr'):
1377 if hasattr(curses,'initscr'):
1367 use_curses = 1
1378 use_curses = 1
1368 else:
1379 else:
1369 use_curses = 0
1380 use_curses = 0
1370 except ImportError:
1381 except ImportError:
1371 use_curses = 0
1382 use_curses = 0
1372 else:
1383 else:
1373 # curses causes problems on many terminals other than xterm.
1384 # curses causes problems on many terminals other than xterm.
1374 use_curses = 0
1385 use_curses = 0
1375 if use_curses:
1386 if use_curses:
1376 scr = curses.initscr()
1387 scr = curses.initscr()
1377 screen_lines_real,screen_cols = scr.getmaxyx()
1388 screen_lines_real,screen_cols = scr.getmaxyx()
1378 curses.endwin()
1389 curses.endwin()
1379 screen_lines += screen_lines_real
1390 screen_lines += screen_lines_real
1380 #print '***Screen size:',screen_lines_real,'lines x',\
1391 #print '***Screen size:',screen_lines_real,'lines x',\
1381 #screen_cols,'columns.' # dbg
1392 #screen_cols,'columns.' # dbg
1382 else:
1393 else:
1383 screen_lines += screen_lines_def
1394 screen_lines += screen_lines_def
1384
1395
1385 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1396 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1386 if numlines <= screen_lines :
1397 if numlines <= screen_lines :
1387 #print '*** normal print' # dbg
1398 #print '*** normal print' # dbg
1388 print >>Term.cout, str_toprint
1399 print >>Term.cout, str_toprint
1389 else:
1400 else:
1390 # Try to open pager and default to internal one if that fails.
1401 # Try to open pager and default to internal one if that fails.
1391 # All failure modes are tagged as 'retval=1', to match the return
1402 # All failure modes are tagged as 'retval=1', to match the return
1392 # value of a failed system command. If any intermediate attempt
1403 # value of a failed system command. If any intermediate attempt
1393 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1404 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1394 pager_cmd = get_pager_cmd(pager_cmd)
1405 pager_cmd = get_pager_cmd(pager_cmd)
1395 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1406 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1396 if os.name == 'nt':
1407 if os.name == 'nt':
1397 if pager_cmd.startswith('type'):
1408 if pager_cmd.startswith('type'):
1398 # The default WinXP 'type' command is failing on complex strings.
1409 # The default WinXP 'type' command is failing on complex strings.
1399 retval = 1
1410 retval = 1
1400 else:
1411 else:
1401 tmpname = tempfile.mktemp('.txt')
1412 tmpname = tempfile.mktemp('.txt')
1402 tmpfile = file(tmpname,'wt')
1413 tmpfile = file(tmpname,'wt')
1403 tmpfile.write(strng)
1414 tmpfile.write(strng)
1404 tmpfile.close()
1415 tmpfile.close()
1405 cmd = "%s < %s" % (pager_cmd,tmpname)
1416 cmd = "%s < %s" % (pager_cmd,tmpname)
1406 if os.system(cmd):
1417 if os.system(cmd):
1407 retval = 1
1418 retval = 1
1408 else:
1419 else:
1409 retval = None
1420 retval = None
1410 os.remove(tmpname)
1421 os.remove(tmpname)
1411 else:
1422 else:
1412 try:
1423 try:
1413 retval = None
1424 retval = None
1414 # if I use popen4, things hang. No idea why.
1425 # if I use popen4, things hang. No idea why.
1415 #pager,shell_out = os.popen4(pager_cmd)
1426 #pager,shell_out = os.popen4(pager_cmd)
1416 pager = os.popen(pager_cmd,'w')
1427 pager = os.popen(pager_cmd,'w')
1417 pager.write(strng)
1428 pager.write(strng)
1418 pager.close()
1429 pager.close()
1419 retval = pager.close() # success returns None
1430 retval = pager.close() # success returns None
1420 except IOError,msg: # broken pipe when user quits
1431 except IOError,msg: # broken pipe when user quits
1421 if msg.args == (32,'Broken pipe'):
1432 if msg.args == (32,'Broken pipe'):
1422 retval = None
1433 retval = None
1423 else:
1434 else:
1424 retval = 1
1435 retval = 1
1425 except OSError:
1436 except OSError:
1426 # Other strange problems, sometimes seen in Win2k/cygwin
1437 # Other strange problems, sometimes seen in Win2k/cygwin
1427 retval = 1
1438 retval = 1
1428 if retval is not None:
1439 if retval is not None:
1429 page_dumb(strng,screen_lines=screen_lines)
1440 page_dumb(strng,screen_lines=screen_lines)
1430
1441
1431 #----------------------------------------------------------------------------
1442 #----------------------------------------------------------------------------
1432 def page_file(fname,start = 0, pager_cmd = None):
1443 def page_file(fname,start = 0, pager_cmd = None):
1433 """Page a file, using an optional pager command and starting line.
1444 """Page a file, using an optional pager command and starting line.
1434 """
1445 """
1435
1446
1436 pager_cmd = get_pager_cmd(pager_cmd)
1447 pager_cmd = get_pager_cmd(pager_cmd)
1437 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1448 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1438
1449
1439 try:
1450 try:
1440 if os.environ['TERM'] in ['emacs','dumb']:
1451 if os.environ['TERM'] in ['emacs','dumb']:
1441 raise EnvironmentError
1452 raise EnvironmentError
1442 xsys(pager_cmd + ' ' + fname)
1453 xsys(pager_cmd + ' ' + fname)
1443 except:
1454 except:
1444 try:
1455 try:
1445 if start > 0:
1456 if start > 0:
1446 start -= 1
1457 start -= 1
1447 page(open(fname).read(),start)
1458 page(open(fname).read(),start)
1448 except:
1459 except:
1449 print 'Unable to show file',`fname`
1460 print 'Unable to show file',`fname`
1450
1461
1451 #----------------------------------------------------------------------------
1462 #----------------------------------------------------------------------------
1452 def snip_print(str,width = 75,print_full = 0,header = ''):
1463 def snip_print(str,width = 75,print_full = 0,header = ''):
1453 """Print a string snipping the midsection to fit in width.
1464 """Print a string snipping the midsection to fit in width.
1454
1465
1455 print_full: mode control:
1466 print_full: mode control:
1456 - 0: only snip long strings
1467 - 0: only snip long strings
1457 - 1: send to page() directly.
1468 - 1: send to page() directly.
1458 - 2: snip long strings and ask for full length viewing with page()
1469 - 2: snip long strings and ask for full length viewing with page()
1459 Return 1 if snipping was necessary, 0 otherwise."""
1470 Return 1 if snipping was necessary, 0 otherwise."""
1460
1471
1461 if print_full == 1:
1472 if print_full == 1:
1462 page(header+str)
1473 page(header+str)
1463 return 0
1474 return 0
1464
1475
1465 print header,
1476 print header,
1466 if len(str) < width:
1477 if len(str) < width:
1467 print str
1478 print str
1468 snip = 0
1479 snip = 0
1469 else:
1480 else:
1470 whalf = int((width -5)/2)
1481 whalf = int((width -5)/2)
1471 print str[:whalf] + ' <...> ' + str[-whalf:]
1482 print str[:whalf] + ' <...> ' + str[-whalf:]
1472 snip = 1
1483 snip = 1
1473 if snip and print_full == 2:
1484 if snip and print_full == 2:
1474 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1485 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1475 page(str)
1486 page(str)
1476 return snip
1487 return snip
1477
1488
1478 #****************************************************************************
1489 #****************************************************************************
1479 # lists, dicts and structures
1490 # lists, dicts and structures
1480
1491
1481 def belong(candidates,checklist):
1492 def belong(candidates,checklist):
1482 """Check whether a list of items appear in a given list of options.
1493 """Check whether a list of items appear in a given list of options.
1483
1494
1484 Returns a list of 1 and 0, one for each candidate given."""
1495 Returns a list of 1 and 0, one for each candidate given."""
1485
1496
1486 return [x in checklist for x in candidates]
1497 return [x in checklist for x in candidates]
1487
1498
1488 #----------------------------------------------------------------------------
1499 #----------------------------------------------------------------------------
1489 def uniq_stable(elems):
1500 def uniq_stable(elems):
1490 """uniq_stable(elems) -> list
1501 """uniq_stable(elems) -> list
1491
1502
1492 Return from an iterable, a list of all the unique elements in the input,
1503 Return from an iterable, a list of all the unique elements in the input,
1493 but maintaining the order in which they first appear.
1504 but maintaining the order in which they first appear.
1494
1505
1495 A naive solution to this problem which just makes a dictionary with the
1506 A naive solution to this problem which just makes a dictionary with the
1496 elements as keys fails to respect the stability condition, since
1507 elements as keys fails to respect the stability condition, since
1497 dictionaries are unsorted by nature.
1508 dictionaries are unsorted by nature.
1498
1509
1499 Note: All elements in the input must be valid dictionary keys for this
1510 Note: All elements in the input must be valid dictionary keys for this
1500 routine to work, as it internally uses a dictionary for efficiency
1511 routine to work, as it internally uses a dictionary for efficiency
1501 reasons."""
1512 reasons."""
1502
1513
1503 unique = []
1514 unique = []
1504 unique_dict = {}
1515 unique_dict = {}
1505 for nn in elems:
1516 for nn in elems:
1506 if nn not in unique_dict:
1517 if nn not in unique_dict:
1507 unique.append(nn)
1518 unique.append(nn)
1508 unique_dict[nn] = None
1519 unique_dict[nn] = None
1509 return unique
1520 return unique
1510
1521
1511 #----------------------------------------------------------------------------
1522 #----------------------------------------------------------------------------
1512 class NLprinter:
1523 class NLprinter:
1513 """Print an arbitrarily nested list, indicating index numbers.
1524 """Print an arbitrarily nested list, indicating index numbers.
1514
1525
1515 An instance of this class called nlprint is available and callable as a
1526 An instance of this class called nlprint is available and callable as a
1516 function.
1527 function.
1517
1528
1518 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1529 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1519 and using 'sep' to separate the index from the value. """
1530 and using 'sep' to separate the index from the value. """
1520
1531
1521 def __init__(self):
1532 def __init__(self):
1522 self.depth = 0
1533 self.depth = 0
1523
1534
1524 def __call__(self,lst,pos='',**kw):
1535 def __call__(self,lst,pos='',**kw):
1525 """Prints the nested list numbering levels."""
1536 """Prints the nested list numbering levels."""
1526 kw.setdefault('indent',' ')
1537 kw.setdefault('indent',' ')
1527 kw.setdefault('sep',': ')
1538 kw.setdefault('sep',': ')
1528 kw.setdefault('start',0)
1539 kw.setdefault('start',0)
1529 kw.setdefault('stop',len(lst))
1540 kw.setdefault('stop',len(lst))
1530 # we need to remove start and stop from kw so they don't propagate
1541 # we need to remove start and stop from kw so they don't propagate
1531 # into a recursive call for a nested list.
1542 # into a recursive call for a nested list.
1532 start = kw['start']; del kw['start']
1543 start = kw['start']; del kw['start']
1533 stop = kw['stop']; del kw['stop']
1544 stop = kw['stop']; del kw['stop']
1534 if self.depth == 0 and 'header' in kw.keys():
1545 if self.depth == 0 and 'header' in kw.keys():
1535 print kw['header']
1546 print kw['header']
1536
1547
1537 for idx in range(start,stop):
1548 for idx in range(start,stop):
1538 elem = lst[idx]
1549 elem = lst[idx]
1539 if type(elem)==type([]):
1550 if type(elem)==type([]):
1540 self.depth += 1
1551 self.depth += 1
1541 self.__call__(elem,itpl('$pos$idx,'),**kw)
1552 self.__call__(elem,itpl('$pos$idx,'),**kw)
1542 self.depth -= 1
1553 self.depth -= 1
1543 else:
1554 else:
1544 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1555 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1545
1556
1546 nlprint = NLprinter()
1557 nlprint = NLprinter()
1547 #----------------------------------------------------------------------------
1558 #----------------------------------------------------------------------------
1548 def all_belong(candidates,checklist):
1559 def all_belong(candidates,checklist):
1549 """Check whether a list of items ALL appear in a given list of options.
1560 """Check whether a list of items ALL appear in a given list of options.
1550
1561
1551 Returns a single 1 or 0 value."""
1562 Returns a single 1 or 0 value."""
1552
1563
1553 return 1-(0 in [x in checklist for x in candidates])
1564 return 1-(0 in [x in checklist for x in candidates])
1554
1565
1555 #----------------------------------------------------------------------------
1566 #----------------------------------------------------------------------------
1556 def sort_compare(lst1,lst2,inplace = 1):
1567 def sort_compare(lst1,lst2,inplace = 1):
1557 """Sort and compare two lists.
1568 """Sort and compare two lists.
1558
1569
1559 By default it does it in place, thus modifying the lists. Use inplace = 0
1570 By default it does it in place, thus modifying the lists. Use inplace = 0
1560 to avoid that (at the cost of temporary copy creation)."""
1571 to avoid that (at the cost of temporary copy creation)."""
1561 if not inplace:
1572 if not inplace:
1562 lst1 = lst1[:]
1573 lst1 = lst1[:]
1563 lst2 = lst2[:]
1574 lst2 = lst2[:]
1564 lst1.sort(); lst2.sort()
1575 lst1.sort(); lst2.sort()
1565 return lst1 == lst2
1576 return lst1 == lst2
1566
1577
1567 #----------------------------------------------------------------------------
1578 #----------------------------------------------------------------------------
1568 def mkdict(**kwargs):
1579 def mkdict(**kwargs):
1569 """Return a dict from a keyword list.
1580 """Return a dict from a keyword list.
1570
1581
1571 It's just syntactic sugar for making ditcionary creation more convenient:
1582 It's just syntactic sugar for making ditcionary creation more convenient:
1572 # the standard way
1583 # the standard way
1573 >>>data = { 'red' : 1, 'green' : 2, 'blue' : 3 }
1584 >>>data = { 'red' : 1, 'green' : 2, 'blue' : 3 }
1574 # a cleaner way
1585 # a cleaner way
1575 >>>data = dict(red=1, green=2, blue=3)
1586 >>>data = dict(red=1, green=2, blue=3)
1576
1587
1577 If you need more than this, look at the Struct() class."""
1588 If you need more than this, look at the Struct() class."""
1578
1589
1579 return kwargs
1590 return kwargs
1580
1591
1581 #----------------------------------------------------------------------------
1592 #----------------------------------------------------------------------------
1582 def list2dict(lst):
1593 def list2dict(lst):
1583 """Takes a list of (key,value) pairs and turns it into a dict."""
1594 """Takes a list of (key,value) pairs and turns it into a dict."""
1584
1595
1585 dic = {}
1596 dic = {}
1586 for k,v in lst: dic[k] = v
1597 for k,v in lst: dic[k] = v
1587 return dic
1598 return dic
1588
1599
1589 #----------------------------------------------------------------------------
1600 #----------------------------------------------------------------------------
1590 def list2dict2(lst,default=''):
1601 def list2dict2(lst,default=''):
1591 """Takes a list and turns it into a dict.
1602 """Takes a list and turns it into a dict.
1592 Much slower than list2dict, but more versatile. This version can take
1603 Much slower than list2dict, but more versatile. This version can take
1593 lists with sublists of arbitrary length (including sclars)."""
1604 lists with sublists of arbitrary length (including sclars)."""
1594
1605
1595 dic = {}
1606 dic = {}
1596 for elem in lst:
1607 for elem in lst:
1597 if type(elem) in (types.ListType,types.TupleType):
1608 if type(elem) in (types.ListType,types.TupleType):
1598 size = len(elem)
1609 size = len(elem)
1599 if size == 0:
1610 if size == 0:
1600 pass
1611 pass
1601 elif size == 1:
1612 elif size == 1:
1602 dic[elem] = default
1613 dic[elem] = default
1603 else:
1614 else:
1604 k,v = elem[0], elem[1:]
1615 k,v = elem[0], elem[1:]
1605 if len(v) == 1: v = v[0]
1616 if len(v) == 1: v = v[0]
1606 dic[k] = v
1617 dic[k] = v
1607 else:
1618 else:
1608 dic[elem] = default
1619 dic[elem] = default
1609 return dic
1620 return dic
1610
1621
1611 #----------------------------------------------------------------------------
1622 #----------------------------------------------------------------------------
1612 def flatten(seq):
1623 def flatten(seq):
1613 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1624 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1614
1625
1615 return [x for subseq in seq for x in subseq]
1626 return [x for subseq in seq for x in subseq]
1616
1627
1617 #----------------------------------------------------------------------------
1628 #----------------------------------------------------------------------------
1618 def get_slice(seq,start=0,stop=None,step=1):
1629 def get_slice(seq,start=0,stop=None,step=1):
1619 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1630 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1620 if stop == None:
1631 if stop == None:
1621 stop = len(seq)
1632 stop = len(seq)
1622 item = lambda i: seq[i]
1633 item = lambda i: seq[i]
1623 return map(item,xrange(start,stop,step))
1634 return map(item,xrange(start,stop,step))
1624
1635
1625 #----------------------------------------------------------------------------
1636 #----------------------------------------------------------------------------
1626 def chop(seq,size):
1637 def chop(seq,size):
1627 """Chop a sequence into chunks of the given size."""
1638 """Chop a sequence into chunks of the given size."""
1628 chunk = lambda i: seq[i:i+size]
1639 chunk = lambda i: seq[i:i+size]
1629 return map(chunk,xrange(0,len(seq),size))
1640 return map(chunk,xrange(0,len(seq),size))
1630
1641
1631 #----------------------------------------------------------------------------
1642 #----------------------------------------------------------------------------
1632 # with is a keyword as of python 2.5, so this function is renamed to withobj
1643 # with is a keyword as of python 2.5, so this function is renamed to withobj
1633 # from its old 'with' name.
1644 # from its old 'with' name.
1634 def with_obj(object, **args):
1645 def with_obj(object, **args):
1635 """Set multiple attributes for an object, similar to Pascal's with.
1646 """Set multiple attributes for an object, similar to Pascal's with.
1636
1647
1637 Example:
1648 Example:
1638 with_obj(jim,
1649 with_obj(jim,
1639 born = 1960,
1650 born = 1960,
1640 haircolour = 'Brown',
1651 haircolour = 'Brown',
1641 eyecolour = 'Green')
1652 eyecolour = 'Green')
1642
1653
1643 Credit: Greg Ewing, in
1654 Credit: Greg Ewing, in
1644 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1655 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1645
1656
1646 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1657 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1647 has become a keyword for Python 2.5, so we had to rename it."""
1658 has become a keyword for Python 2.5, so we had to rename it."""
1648
1659
1649 object.__dict__.update(args)
1660 object.__dict__.update(args)
1650
1661
1651 #----------------------------------------------------------------------------
1662 #----------------------------------------------------------------------------
1652 def setattr_list(obj,alist,nspace = None):
1663 def setattr_list(obj,alist,nspace = None):
1653 """Set a list of attributes for an object taken from a namespace.
1664 """Set a list of attributes for an object taken from a namespace.
1654
1665
1655 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1666 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1656 alist with their values taken from nspace, which must be a dict (something
1667 alist with their values taken from nspace, which must be a dict (something
1657 like locals() will often do) If nspace isn't given, locals() of the
1668 like locals() will often do) If nspace isn't given, locals() of the
1658 *caller* is used, so in most cases you can omit it.
1669 *caller* is used, so in most cases you can omit it.
1659
1670
1660 Note that alist can be given as a string, which will be automatically
1671 Note that alist can be given as a string, which will be automatically
1661 split into a list on whitespace. If given as a list, it must be a list of
1672 split into a list on whitespace. If given as a list, it must be a list of
1662 *strings* (the variable names themselves), not of variables."""
1673 *strings* (the variable names themselves), not of variables."""
1663
1674
1664 # this grabs the local variables from the *previous* call frame -- that is
1675 # this grabs the local variables from the *previous* call frame -- that is
1665 # the locals from the function that called setattr_list().
1676 # the locals from the function that called setattr_list().
1666 # - snipped from weave.inline()
1677 # - snipped from weave.inline()
1667 if nspace is None:
1678 if nspace is None:
1668 call_frame = sys._getframe().f_back
1679 call_frame = sys._getframe().f_back
1669 nspace = call_frame.f_locals
1680 nspace = call_frame.f_locals
1670
1681
1671 if type(alist) in StringTypes:
1682 if type(alist) in StringTypes:
1672 alist = alist.split()
1683 alist = alist.split()
1673 for attr in alist:
1684 for attr in alist:
1674 val = eval(attr,nspace)
1685 val = eval(attr,nspace)
1675 setattr(obj,attr,val)
1686 setattr(obj,attr,val)
1676
1687
1677 #----------------------------------------------------------------------------
1688 #----------------------------------------------------------------------------
1678 def getattr_list(obj,alist,*args):
1689 def getattr_list(obj,alist,*args):
1679 """getattr_list(obj,alist[, default]) -> attribute list.
1690 """getattr_list(obj,alist[, default]) -> attribute list.
1680
1691
1681 Get a list of named attributes for an object. When a default argument is
1692 Get a list of named attributes for an object. When a default argument is
1682 given, it is returned when the attribute doesn't exist; without it, an
1693 given, it is returned when the attribute doesn't exist; without it, an
1683 exception is raised in that case.
1694 exception is raised in that case.
1684
1695
1685 Note that alist can be given as a string, which will be automatically
1696 Note that alist can be given as a string, which will be automatically
1686 split into a list on whitespace. If given as a list, it must be a list of
1697 split into a list on whitespace. If given as a list, it must be a list of
1687 *strings* (the variable names themselves), not of variables."""
1698 *strings* (the variable names themselves), not of variables."""
1688
1699
1689 if type(alist) in StringTypes:
1700 if type(alist) in StringTypes:
1690 alist = alist.split()
1701 alist = alist.split()
1691 if args:
1702 if args:
1692 if len(args)==1:
1703 if len(args)==1:
1693 default = args[0]
1704 default = args[0]
1694 return map(lambda attr: getattr(obj,attr,default),alist)
1705 return map(lambda attr: getattr(obj,attr,default),alist)
1695 else:
1706 else:
1696 raise ValueError,'getattr_list() takes only one optional argument'
1707 raise ValueError,'getattr_list() takes only one optional argument'
1697 else:
1708 else:
1698 return map(lambda attr: getattr(obj,attr),alist)
1709 return map(lambda attr: getattr(obj,attr),alist)
1699
1710
1700 #----------------------------------------------------------------------------
1711 #----------------------------------------------------------------------------
1701 def map_method(method,object_list,*argseq,**kw):
1712 def map_method(method,object_list,*argseq,**kw):
1702 """map_method(method,object_list,*args,**kw) -> list
1713 """map_method(method,object_list,*args,**kw) -> list
1703
1714
1704 Return a list of the results of applying the methods to the items of the
1715 Return a list of the results of applying the methods to the items of the
1705 argument sequence(s). If more than one sequence is given, the method is
1716 argument sequence(s). If more than one sequence is given, the method is
1706 called with an argument list consisting of the corresponding item of each
1717 called with an argument list consisting of the corresponding item of each
1707 sequence. All sequences must be of the same length.
1718 sequence. All sequences must be of the same length.
1708
1719
1709 Keyword arguments are passed verbatim to all objects called.
1720 Keyword arguments are passed verbatim to all objects called.
1710
1721
1711 This is Python code, so it's not nearly as fast as the builtin map()."""
1722 This is Python code, so it's not nearly as fast as the builtin map()."""
1712
1723
1713 out_list = []
1724 out_list = []
1714 idx = 0
1725 idx = 0
1715 for object in object_list:
1726 for object in object_list:
1716 try:
1727 try:
1717 handler = getattr(object, method)
1728 handler = getattr(object, method)
1718 except AttributeError:
1729 except AttributeError:
1719 out_list.append(None)
1730 out_list.append(None)
1720 else:
1731 else:
1721 if argseq:
1732 if argseq:
1722 args = map(lambda lst:lst[idx],argseq)
1733 args = map(lambda lst:lst[idx],argseq)
1723 #print 'ob',object,'hand',handler,'ar',args # dbg
1734 #print 'ob',object,'hand',handler,'ar',args # dbg
1724 out_list.append(handler(args,**kw))
1735 out_list.append(handler(args,**kw))
1725 else:
1736 else:
1726 out_list.append(handler(**kw))
1737 out_list.append(handler(**kw))
1727 idx += 1
1738 idx += 1
1728 return out_list
1739 return out_list
1729
1740
1730 #----------------------------------------------------------------------------
1741 #----------------------------------------------------------------------------
1731 def import_fail_info(mod_name,fns=None):
1742 def import_fail_info(mod_name,fns=None):
1732 """Inform load failure for a module."""
1743 """Inform load failure for a module."""
1733
1744
1734 if fns == None:
1745 if fns == None:
1735 warn("Loading of %s failed.\n" % (mod_name,))
1746 warn("Loading of %s failed.\n" % (mod_name,))
1736 else:
1747 else:
1737 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
1748 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
1738
1749
1739 #----------------------------------------------------------------------------
1750 #----------------------------------------------------------------------------
1740 # Proposed popitem() extension, written as a method
1751 # Proposed popitem() extension, written as a method
1741
1752
1742
1753
1743 class NotGiven: pass
1754 class NotGiven: pass
1744
1755
1745 def popkey(dct,key,default=NotGiven):
1756 def popkey(dct,key,default=NotGiven):
1746 """Return dct[key] and delete dct[key].
1757 """Return dct[key] and delete dct[key].
1747
1758
1748 If default is given, return it if dct[key] doesn't exist, otherwise raise
1759 If default is given, return it if dct[key] doesn't exist, otherwise raise
1749 KeyError. """
1760 KeyError. """
1750
1761
1751 try:
1762 try:
1752 val = dct[key]
1763 val = dct[key]
1753 except KeyError:
1764 except KeyError:
1754 if default is NotGiven:
1765 if default is NotGiven:
1755 raise
1766 raise
1756 else:
1767 else:
1757 return default
1768 return default
1758 else:
1769 else:
1759 del dct[key]
1770 del dct[key]
1760 return val
1771 return val
1761
1772
1762 def wrap_deprecated(func, suggest = '<nothing>'):
1773 def wrap_deprecated(func, suggest = '<nothing>'):
1763 def newFunc(*args, **kwargs):
1774 def newFunc(*args, **kwargs):
1764 warnings.warn("Call to deprecated function %s, use %s instead" %
1775 warnings.warn("Call to deprecated function %s, use %s instead" %
1765 ( func.__name__, suggest),
1776 ( func.__name__, suggest),
1766 category=DeprecationWarning,
1777 category=DeprecationWarning,
1767 stacklevel = 2)
1778 stacklevel = 2)
1768 return func(*args, **kwargs)
1779 return func(*args, **kwargs)
1769 return newFunc
1780 return newFunc
1770
1781
1771 #*************************** end of file <genutils.py> **********************
1782 #*************************** end of file <genutils.py> **********************
1772
1783
General Comments 0
You need to be logged in to leave comments. Login now