|
@@
-1,2148
+1,2164
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 2998 2008-01-31 10:06:04Z vivainio $"""
|
|
8
|
$Id: genutils.py 2998 2008-01-31 10:06:04Z 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
|
try:
|
|
25
|
try:
|
|
26
|
import doctest
|
|
26
|
import doctest
|
|
27
|
except ImportError:
|
|
27
|
except ImportError:
|
|
28
|
pass
|
|
28
|
pass
|
|
29
|
import os
|
|
29
|
import os
|
|
30
|
import platform
|
|
30
|
import platform
|
|
31
|
import re
|
|
31
|
import re
|
|
32
|
import shlex
|
|
32
|
import shlex
|
|
33
|
import shutil
|
|
33
|
import shutil
|
|
34
|
import subprocess
|
|
34
|
import subprocess
|
|
35
|
import sys
|
|
35
|
import sys
|
|
36
|
import tempfile
|
|
36
|
import tempfile
|
|
37
|
import time
|
|
37
|
import time
|
|
38
|
import types
|
|
38
|
import types
|
|
39
|
import warnings
|
|
39
|
import warnings
|
|
40
|
|
|
40
|
|
|
41
|
# Curses and termios are Unix-only modules
|
|
41
|
# Curses and termios are Unix-only modules
|
|
42
|
try:
|
|
42
|
try:
|
|
43
|
import curses
|
|
43
|
import curses
|
|
44
|
# We need termios as well, so if its import happens to raise, we bail on
|
|
44
|
# We need termios as well, so if its import happens to raise, we bail on
|
|
45
|
# using curses altogether.
|
|
45
|
# using curses altogether.
|
|
46
|
import termios
|
|
46
|
import termios
|
|
47
|
except ImportError:
|
|
47
|
except ImportError:
|
|
48
|
USE_CURSES = False
|
|
48
|
USE_CURSES = False
|
|
49
|
else:
|
|
49
|
else:
|
|
50
|
# Curses on Solaris may not be complete, so we can't use it there
|
|
50
|
# Curses on Solaris may not be complete, so we can't use it there
|
|
51
|
USE_CURSES = hasattr(curses,'initscr')
|
|
51
|
USE_CURSES = hasattr(curses,'initscr')
|
|
52
|
|
|
52
|
|
|
53
|
# Other IPython utilities
|
|
53
|
# Other IPython utilities
|
|
54
|
import IPython
|
|
54
|
import IPython
|
|
55
|
from IPython.Itpl import Itpl,itpl,printpl
|
|
55
|
from IPython.Itpl import Itpl,itpl,printpl
|
|
56
|
from IPython import DPyGetOpt, platutils
|
|
56
|
from IPython import DPyGetOpt, platutils
|
|
57
|
from IPython.generics import result_display
|
|
57
|
from IPython.generics import result_display
|
|
58
|
import IPython.ipapi
|
|
58
|
import IPython.ipapi
|
|
59
|
from IPython.external.path import path
|
|
59
|
from IPython.external.path import path
|
|
60
|
if os.name == "nt":
|
|
60
|
if os.name == "nt":
|
|
61
|
from IPython.winconsole import get_console_size
|
|
61
|
from IPython.winconsole import get_console_size
|
|
62
|
|
|
62
|
|
|
63
|
try:
|
|
63
|
try:
|
|
64
|
set
|
|
64
|
set
|
|
65
|
except:
|
|
65
|
except:
|
|
66
|
from sets import Set as set
|
|
66
|
from sets import Set as set
|
|
67
|
|
|
67
|
|
|
68
|
|
|
68
|
|
|
69
|
#****************************************************************************
|
|
69
|
#****************************************************************************
|
|
70
|
# Exceptions
|
|
70
|
# Exceptions
|
|
71
|
class Error(Exception):
|
|
71
|
class Error(Exception):
|
|
72
|
"""Base class for exceptions in this module."""
|
|
72
|
"""Base class for exceptions in this module."""
|
|
73
|
pass
|
|
73
|
pass
|
|
74
|
|
|
74
|
|
|
75
|
#----------------------------------------------------------------------------
|
|
75
|
#----------------------------------------------------------------------------
|
|
76
|
class IOStream:
|
|
76
|
class IOStream:
|
|
77
|
def __init__(self,stream,fallback):
|
|
77
|
def __init__(self,stream,fallback):
|
|
78
|
if not hasattr(stream,'write') or not hasattr(stream,'flush'):
|
|
78
|
if not hasattr(stream,'write') or not hasattr(stream,'flush'):
|
|
79
|
stream = fallback
|
|
79
|
stream = fallback
|
|
80
|
self.stream = stream
|
|
80
|
self.stream = stream
|
|
81
|
self._swrite = stream.write
|
|
81
|
self._swrite = stream.write
|
|
82
|
self.flush = stream.flush
|
|
82
|
self.flush = stream.flush
|
|
83
|
|
|
83
|
|
|
84
|
def write(self,data):
|
|
84
|
def write(self,data):
|
|
85
|
try:
|
|
85
|
try:
|
|
86
|
self._swrite(data)
|
|
86
|
self._swrite(data)
|
|
87
|
except:
|
|
87
|
except:
|
|
88
|
try:
|
|
88
|
try:
|
|
89
|
# print handles some unicode issues which may trip a plain
|
|
89
|
# print handles some unicode issues which may trip a plain
|
|
90
|
# write() call. Attempt to emulate write() by using a
|
|
90
|
# write() call. Attempt to emulate write() by using a
|
|
91
|
# trailing comma
|
|
91
|
# trailing comma
|
|
92
|
print >> self.stream, data,
|
|
92
|
print >> self.stream, data,
|
|
93
|
except:
|
|
93
|
except:
|
|
94
|
# if we get here, something is seriously broken.
|
|
94
|
# if we get here, something is seriously broken.
|
|
95
|
print >> sys.stderr, \
|
|
95
|
print >> sys.stderr, \
|
|
96
|
'ERROR - failed to write data to stream:', self.stream
|
|
96
|
'ERROR - failed to write data to stream:', self.stream
|
|
97
|
|
|
97
|
|
|
98
|
def close(self):
|
|
98
|
def close(self):
|
|
99
|
pass
|
|
99
|
pass
|
|
100
|
|
|
100
|
|
|
101
|
|
|
101
|
|
|
102
|
class IOTerm:
|
|
102
|
class IOTerm:
|
|
103
|
""" Term holds the file or file-like objects for handling I/O operations.
|
|
103
|
""" Term holds the file or file-like objects for handling I/O operations.
|
|
104
|
|
|
104
|
|
|
105
|
These are normally just sys.stdin, sys.stdout and sys.stderr but for
|
|
105
|
These are normally just sys.stdin, sys.stdout and sys.stderr but for
|
|
106
|
Windows they can can replaced to allow editing the strings before they are
|
|
106
|
Windows they can can replaced to allow editing the strings before they are
|
|
107
|
displayed."""
|
|
107
|
displayed."""
|
|
108
|
|
|
108
|
|
|
109
|
# In the future, having IPython channel all its I/O operations through
|
|
109
|
# In the future, having IPython channel all its I/O operations through
|
|
110
|
# this class will make it easier to embed it into other environments which
|
|
110
|
# this class will make it easier to embed it into other environments which
|
|
111
|
# are not a normal terminal (such as a GUI-based shell)
|
|
111
|
# are not a normal terminal (such as a GUI-based shell)
|
|
112
|
def __init__(self,cin=None,cout=None,cerr=None):
|
|
112
|
def __init__(self,cin=None,cout=None,cerr=None):
|
|
113
|
self.cin = IOStream(cin,sys.stdin)
|
|
113
|
self.cin = IOStream(cin,sys.stdin)
|
|
114
|
self.cout = IOStream(cout,sys.stdout)
|
|
114
|
self.cout = IOStream(cout,sys.stdout)
|
|
115
|
self.cerr = IOStream(cerr,sys.stderr)
|
|
115
|
self.cerr = IOStream(cerr,sys.stderr)
|
|
116
|
|
|
116
|
|
|
117
|
# Global variable to be used for all I/O
|
|
117
|
# Global variable to be used for all I/O
|
|
118
|
Term = IOTerm()
|
|
118
|
Term = IOTerm()
|
|
119
|
|
|
119
|
|
|
120
|
import IPython.rlineimpl as readline
|
|
120
|
import IPython.rlineimpl as readline
|
|
121
|
# Remake Term to use the readline i/o facilities
|
|
121
|
# Remake Term to use the readline i/o facilities
|
|
122
|
if sys.platform == 'win32' and readline.have_readline:
|
|
122
|
if sys.platform == 'win32' and readline.have_readline:
|
|
123
|
|
|
123
|
|
|
124
|
Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
|
|
124
|
Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
|
|
125
|
|
|
125
|
|
|
126
|
|
|
126
|
|
|
127
|
#****************************************************************************
|
|
127
|
#****************************************************************************
|
|
128
|
# Generic warning/error printer, used by everything else
|
|
128
|
# Generic warning/error printer, used by everything else
|
|
129
|
def warn(msg,level=2,exit_val=1):
|
|
129
|
def warn(msg,level=2,exit_val=1):
|
|
130
|
"""Standard warning printer. Gives formatting consistency.
|
|
130
|
"""Standard warning printer. Gives formatting consistency.
|
|
131
|
|
|
131
|
|
|
132
|
Output is sent to Term.cerr (sys.stderr by default).
|
|
132
|
Output is sent to Term.cerr (sys.stderr by default).
|
|
133
|
|
|
133
|
|
|
134
|
Options:
|
|
134
|
Options:
|
|
135
|
|
|
135
|
|
|
136
|
-level(2): allows finer control:
|
|
136
|
-level(2): allows finer control:
|
|
137
|
0 -> Do nothing, dummy function.
|
|
137
|
0 -> Do nothing, dummy function.
|
|
138
|
1 -> Print message.
|
|
138
|
1 -> Print message.
|
|
139
|
2 -> Print 'WARNING:' + message. (Default level).
|
|
139
|
2 -> Print 'WARNING:' + message. (Default level).
|
|
140
|
3 -> Print 'ERROR:' + message.
|
|
140
|
3 -> Print 'ERROR:' + message.
|
|
141
|
4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
|
|
141
|
4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
|
|
142
|
|
|
142
|
|
|
143
|
-exit_val (1): exit value returned by sys.exit() for a level 4
|
|
143
|
-exit_val (1): exit value returned by sys.exit() for a level 4
|
|
144
|
warning. Ignored for all other levels."""
|
|
144
|
warning. Ignored for all other levels."""
|
|
145
|
|
|
145
|
|
|
146
|
if level>0:
|
|
146
|
if level>0:
|
|
147
|
header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
|
|
147
|
header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
|
|
148
|
print >> Term.cerr, '%s%s' % (header[level],msg)
|
|
148
|
print >> Term.cerr, '%s%s' % (header[level],msg)
|
|
149
|
if level == 4:
|
|
149
|
if level == 4:
|
|
150
|
print >> Term.cerr,'Exiting.\n'
|
|
150
|
print >> Term.cerr,'Exiting.\n'
|
|
151
|
sys.exit(exit_val)
|
|
151
|
sys.exit(exit_val)
|
|
152
|
|
|
152
|
|
|
153
|
def info(msg):
|
|
153
|
def info(msg):
|
|
154
|
"""Equivalent to warn(msg,level=1)."""
|
|
154
|
"""Equivalent to warn(msg,level=1)."""
|
|
155
|
|
|
155
|
|
|
156
|
warn(msg,level=1)
|
|
156
|
warn(msg,level=1)
|
|
157
|
|
|
157
|
|
|
158
|
def error(msg):
|
|
158
|
def error(msg):
|
|
159
|
"""Equivalent to warn(msg,level=3)."""
|
|
159
|
"""Equivalent to warn(msg,level=3)."""
|
|
160
|
|
|
160
|
|
|
161
|
warn(msg,level=3)
|
|
161
|
warn(msg,level=3)
|
|
162
|
|
|
162
|
|
|
163
|
def fatal(msg,exit_val=1):
|
|
163
|
def fatal(msg,exit_val=1):
|
|
164
|
"""Equivalent to warn(msg,exit_val=exit_val,level=4)."""
|
|
164
|
"""Equivalent to warn(msg,exit_val=exit_val,level=4)."""
|
|
165
|
|
|
165
|
|
|
166
|
warn(msg,exit_val=exit_val,level=4)
|
|
166
|
warn(msg,exit_val=exit_val,level=4)
|
|
167
|
|
|
167
|
|
|
168
|
#---------------------------------------------------------------------------
|
|
168
|
#---------------------------------------------------------------------------
|
|
169
|
# Debugging routines
|
|
169
|
# Debugging routines
|
|
170
|
#
|
|
170
|
#
|
|
171
|
def debugx(expr,pre_msg=''):
|
|
171
|
def debugx(expr,pre_msg=''):
|
|
172
|
"""Print the value of an expression from the caller's frame.
|
|
172
|
"""Print the value of an expression from the caller's frame.
|
|
173
|
|
|
173
|
|
|
174
|
Takes an expression, evaluates it in the caller's frame and prints both
|
|
174
|
Takes an expression, evaluates it in the caller's frame and prints both
|
|
175
|
the given expression and the resulting value (as well as a debug mark
|
|
175
|
the given expression and the resulting value (as well as a debug mark
|
|
176
|
indicating the name of the calling function. The input must be of a form
|
|
176
|
indicating the name of the calling function. The input must be of a form
|
|
177
|
suitable for eval().
|
|
177
|
suitable for eval().
|
|
178
|
|
|
178
|
|
|
179
|
An optional message can be passed, which will be prepended to the printed
|
|
179
|
An optional message can be passed, which will be prepended to the printed
|
|
180
|
expr->value pair."""
|
|
180
|
expr->value pair."""
|
|
181
|
|
|
181
|
|
|
182
|
cf = sys._getframe(1)
|
|
182
|
cf = sys._getframe(1)
|
|
183
|
print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
|
|
183
|
print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
|
|
184
|
eval(expr,cf.f_globals,cf.f_locals))
|
|
184
|
eval(expr,cf.f_globals,cf.f_locals))
|
|
185
|
|
|
185
|
|
|
186
|
# deactivate it by uncommenting the following line, which makes it a no-op
|
|
186
|
# deactivate it by uncommenting the following line, which makes it a no-op
|
|
187
|
#def debugx(expr,pre_msg=''): pass
|
|
187
|
#def debugx(expr,pre_msg=''): pass
|
|
188
|
|
|
188
|
|
|
189
|
#----------------------------------------------------------------------------
|
|
189
|
#----------------------------------------------------------------------------
|
|
190
|
StringTypes = types.StringTypes
|
|
190
|
StringTypes = types.StringTypes
|
|
191
|
|
|
191
|
|
|
192
|
# Basic timing functionality
|
|
192
|
# Basic timing functionality
|
|
193
|
|
|
193
|
|
|
194
|
# If possible (Unix), use the resource module instead of time.clock()
|
|
194
|
# If possible (Unix), use the resource module instead of time.clock()
|
|
195
|
try:
|
|
195
|
try:
|
|
196
|
import resource
|
|
196
|
import resource
|
|
197
|
def clocku():
|
|
197
|
def clocku():
|
|
198
|
"""clocku() -> floating point number
|
|
198
|
"""clocku() -> floating point number
|
|
199
|
|
|
199
|
|
|
200
|
Return the *USER* CPU time in seconds since the start of the process.
|
|
200
|
Return the *USER* CPU time in seconds since the start of the process.
|
|
201
|
This is done via a call to resource.getrusage, so it avoids the
|
|
201
|
This is done via a call to resource.getrusage, so it avoids the
|
|
202
|
wraparound problems in time.clock()."""
|
|
202
|
wraparound problems in time.clock()."""
|
|
203
|
|
|
203
|
|
|
204
|
return resource.getrusage(resource.RUSAGE_SELF)[0]
|
|
204
|
return resource.getrusage(resource.RUSAGE_SELF)[0]
|
|
205
|
|
|
205
|
|
|
206
|
def clocks():
|
|
206
|
def clocks():
|
|
207
|
"""clocks() -> floating point number
|
|
207
|
"""clocks() -> floating point number
|
|
208
|
|
|
208
|
|
|
209
|
Return the *SYSTEM* CPU time in seconds since the start of the process.
|
|
209
|
Return the *SYSTEM* CPU time in seconds since the start of the process.
|
|
210
|
This is done via a call to resource.getrusage, so it avoids the
|
|
210
|
This is done via a call to resource.getrusage, so it avoids the
|
|
211
|
wraparound problems in time.clock()."""
|
|
211
|
wraparound problems in time.clock()."""
|
|
212
|
|
|
212
|
|
|
213
|
return resource.getrusage(resource.RUSAGE_SELF)[1]
|
|
213
|
return resource.getrusage(resource.RUSAGE_SELF)[1]
|
|
214
|
|
|
214
|
|
|
215
|
def clock():
|
|
215
|
def clock():
|
|
216
|
"""clock() -> floating point number
|
|
216
|
"""clock() -> floating point number
|
|
217
|
|
|
217
|
|
|
218
|
Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
|
|
218
|
Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
|
|
219
|
the process. This is done via a call to resource.getrusage, so it
|
|
219
|
the process. This is done via a call to resource.getrusage, so it
|
|
220
|
avoids the wraparound problems in time.clock()."""
|
|
220
|
avoids the wraparound problems in time.clock()."""
|
|
221
|
|
|
221
|
|
|
222
|
u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
|
|
222
|
u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
|
|
223
|
return u+s
|
|
223
|
return u+s
|
|
224
|
|
|
224
|
|
|
225
|
def clock2():
|
|
225
|
def clock2():
|
|
226
|
"""clock2() -> (t_user,t_system)
|
|
226
|
"""clock2() -> (t_user,t_system)
|
|
227
|
|
|
227
|
|
|
228
|
Similar to clock(), but return a tuple of user/system times."""
|
|
228
|
Similar to clock(), but return a tuple of user/system times."""
|
|
229
|
return resource.getrusage(resource.RUSAGE_SELF)[:2]
|
|
229
|
return resource.getrusage(resource.RUSAGE_SELF)[:2]
|
|
230
|
|
|
230
|
|
|
231
|
except ImportError:
|
|
231
|
except ImportError:
|
|
232
|
# There is no distinction of user/system time under windows, so we just use
|
|
232
|
# There is no distinction of user/system time under windows, so we just use
|
|
233
|
# time.clock() for everything...
|
|
233
|
# time.clock() for everything...
|
|
234
|
clocku = clocks = clock = time.clock
|
|
234
|
clocku = clocks = clock = time.clock
|
|
235
|
def clock2():
|
|
235
|
def clock2():
|
|
236
|
"""Under windows, system CPU time can't be measured.
|
|
236
|
"""Under windows, system CPU time can't be measured.
|
|
237
|
|
|
237
|
|
|
238
|
This just returns clock() and zero."""
|
|
238
|
This just returns clock() and zero."""
|
|
239
|
return time.clock(),0.0
|
|
239
|
return time.clock(),0.0
|
|
240
|
|
|
240
|
|
|
241
|
def timings_out(reps,func,*args,**kw):
|
|
241
|
def timings_out(reps,func,*args,**kw):
|
|
242
|
"""timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
|
|
242
|
"""timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
|
|
243
|
|
|
243
|
|
|
244
|
Execute a function reps times, return a tuple with the elapsed total
|
|
244
|
Execute a function reps times, return a tuple with the elapsed total
|
|
245
|
CPU time in seconds, the time per call and the function's output.
|
|
245
|
CPU time in seconds, the time per call and the function's output.
|
|
246
|
|
|
246
|
|
|
247
|
Under Unix, the return value is the sum of user+system time consumed by
|
|
247
|
Under Unix, the return value is the sum of user+system time consumed by
|
|
248
|
the process, computed via the resource module. This prevents problems
|
|
248
|
the process, computed via the resource module. This prevents problems
|
|
249
|
related to the wraparound effect which the time.clock() function has.
|
|
249
|
related to the wraparound effect which the time.clock() function has.
|
|
250
|
|
|
250
|
|
|
251
|
Under Windows the return value is in wall clock seconds. See the
|
|
251
|
Under Windows the return value is in wall clock seconds. See the
|
|
252
|
documentation for the time module for more details."""
|
|
252
|
documentation for the time module for more details."""
|
|
253
|
|
|
253
|
|
|
254
|
reps = int(reps)
|
|
254
|
reps = int(reps)
|
|
255
|
assert reps >=1, 'reps must be >= 1'
|
|
255
|
assert reps >=1, 'reps must be >= 1'
|
|
256
|
if reps==1:
|
|
256
|
if reps==1:
|
|
257
|
start = clock()
|
|
257
|
start = clock()
|
|
258
|
out = func(*args,**kw)
|
|
258
|
out = func(*args,**kw)
|
|
259
|
tot_time = clock()-start
|
|
259
|
tot_time = clock()-start
|
|
260
|
else:
|
|
260
|
else:
|
|
261
|
rng = xrange(reps-1) # the last time is executed separately to store output
|
|
261
|
rng = xrange(reps-1) # the last time is executed separately to store output
|
|
262
|
start = clock()
|
|
262
|
start = clock()
|
|
263
|
for dummy in rng: func(*args,**kw)
|
|
263
|
for dummy in rng: func(*args,**kw)
|
|
264
|
out = func(*args,**kw) # one last time
|
|
264
|
out = func(*args,**kw) # one last time
|
|
265
|
tot_time = clock()-start
|
|
265
|
tot_time = clock()-start
|
|
266
|
av_time = tot_time / reps
|
|
266
|
av_time = tot_time / reps
|
|
267
|
return tot_time,av_time,out
|
|
267
|
return tot_time,av_time,out
|
|
268
|
|
|
268
|
|
|
269
|
def timings(reps,func,*args,**kw):
|
|
269
|
def timings(reps,func,*args,**kw):
|
|
270
|
"""timings(reps,func,*args,**kw) -> (t_total,t_per_call)
|
|
270
|
"""timings(reps,func,*args,**kw) -> (t_total,t_per_call)
|
|
271
|
|
|
271
|
|
|
272
|
Execute a function reps times, return a tuple with the elapsed total CPU
|
|
272
|
Execute a function reps times, return a tuple with the elapsed total CPU
|
|
273
|
time in seconds and the time per call. These are just the first two values
|
|
273
|
time in seconds and the time per call. These are just the first two values
|
|
274
|
in timings_out()."""
|
|
274
|
in timings_out()."""
|
|
275
|
|
|
275
|
|
|
276
|
return timings_out(reps,func,*args,**kw)[0:2]
|
|
276
|
return timings_out(reps,func,*args,**kw)[0:2]
|
|
277
|
|
|
277
|
|
|
278
|
def timing(func,*args,**kw):
|
|
278
|
def timing(func,*args,**kw):
|
|
279
|
"""timing(func,*args,**kw) -> t_total
|
|
279
|
"""timing(func,*args,**kw) -> t_total
|
|
280
|
|
|
280
|
|
|
281
|
Execute a function once, return the elapsed total CPU time in
|
|
281
|
Execute a function once, return the elapsed total CPU time in
|
|
282
|
seconds. This is just the first value in timings_out()."""
|
|
282
|
seconds. This is just the first value in timings_out()."""
|
|
283
|
|
|
283
|
|
|
284
|
return timings_out(1,func,*args,**kw)[0]
|
|
284
|
return timings_out(1,func,*args,**kw)[0]
|
|
285
|
|
|
285
|
|
|
286
|
#****************************************************************************
|
|
286
|
#****************************************************************************
|
|
287
|
# file and system
|
|
287
|
# file and system
|
|
288
|
|
|
288
|
|
|
289
|
def arg_split(s,posix=False):
|
|
289
|
def arg_split(s,posix=False):
|
|
290
|
"""Split a command line's arguments in a shell-like manner.
|
|
290
|
"""Split a command line's arguments in a shell-like manner.
|
|
291
|
|
|
291
|
|
|
292
|
This is a modified version of the standard library's shlex.split()
|
|
292
|
This is a modified version of the standard library's shlex.split()
|
|
293
|
function, but with a default of posix=False for splitting, so that quotes
|
|
293
|
function, but with a default of posix=False for splitting, so that quotes
|
|
294
|
in inputs are respected."""
|
|
294
|
in inputs are respected."""
|
|
295
|
|
|
295
|
|
|
296
|
# XXX - there may be unicode-related problems here!!! I'm not sure that
|
|
296
|
# XXX - there may be unicode-related problems here!!! I'm not sure that
|
|
297
|
# shlex is truly unicode-safe, so it might be necessary to do
|
|
297
|
# shlex is truly unicode-safe, so it might be necessary to do
|
|
298
|
#
|
|
298
|
#
|
|
299
|
# s = s.encode(sys.stdin.encoding)
|
|
299
|
# s = s.encode(sys.stdin.encoding)
|
|
300
|
#
|
|
300
|
#
|
|
301
|
# first, to ensure that shlex gets a normal string. Input from anyone who
|
|
301
|
# first, to ensure that shlex gets a normal string. Input from anyone who
|
|
302
|
# knows more about unicode and shlex than I would be good to have here...
|
|
302
|
# knows more about unicode and shlex than I would be good to have here...
|
|
303
|
lex = shlex.shlex(s, posix=posix)
|
|
303
|
lex = shlex.shlex(s, posix=posix)
|
|
304
|
lex.whitespace_split = True
|
|
304
|
lex.whitespace_split = True
|
|
305
|
return list(lex)
|
|
305
|
return list(lex)
|
|
306
|
|
|
306
|
|
|
307
|
def system(cmd,verbose=0,debug=0,header=''):
|
|
307
|
def system(cmd,verbose=0,debug=0,header=''):
|
|
308
|
"""Execute a system command, return its exit status.
|
|
308
|
"""Execute a system command, return its exit status.
|
|
309
|
|
|
309
|
|
|
310
|
Options:
|
|
310
|
Options:
|
|
311
|
|
|
311
|
|
|
312
|
- verbose (0): print the command to be executed.
|
|
312
|
- verbose (0): print the command to be executed.
|
|
313
|
|
|
313
|
|
|
314
|
- debug (0): only print, do not actually execute.
|
|
314
|
- debug (0): only print, do not actually execute.
|
|
315
|
|
|
315
|
|
|
316
|
- 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
|
|
317
|
is only prepended to the command, no newlines are added).
|
|
317
|
is only prepended to the command, no newlines are added).
|
|
318
|
|
|
318
|
|
|
319
|
Note: a stateful version of this function is available through the
|
|
319
|
Note: a stateful version of this function is available through the
|
|
320
|
SystemExec class."""
|
|
320
|
SystemExec class."""
|
|
321
|
|
|
321
|
|
|
322
|
stat = 0
|
|
322
|
stat = 0
|
|
323
|
if verbose or debug: print header+cmd
|
|
323
|
if verbose or debug: print header+cmd
|
|
324
|
sys.stdout.flush()
|
|
324
|
sys.stdout.flush()
|
|
325
|
if not debug: stat = os.system(cmd)
|
|
325
|
if not debug: stat = os.system(cmd)
|
|
326
|
return stat
|
|
326
|
return stat
|
|
327
|
|
|
327
|
|
|
328
|
def abbrev_cwd():
|
|
328
|
def abbrev_cwd():
|
|
329
|
""" Return abbreviated version of cwd, e.g. d:mydir """
|
|
329
|
""" Return abbreviated version of cwd, e.g. d:mydir """
|
|
330
|
cwd = os.getcwd().replace('\\','/')
|
|
330
|
cwd = os.getcwd().replace('\\','/')
|
|
331
|
drivepart = ''
|
|
331
|
drivepart = ''
|
|
332
|
tail = cwd
|
|
332
|
tail = cwd
|
|
333
|
if sys.platform == 'win32':
|
|
333
|
if sys.platform == 'win32':
|
|
334
|
if len(cwd) < 4:
|
|
334
|
if len(cwd) < 4:
|
|
335
|
return cwd
|
|
335
|
return cwd
|
|
336
|
drivepart,tail = os.path.splitdrive(cwd)
|
|
336
|
drivepart,tail = os.path.splitdrive(cwd)
|
|
337
|
|
|
337
|
|
|
338
|
|
|
338
|
|
|
339
|
parts = tail.split('/')
|
|
339
|
parts = tail.split('/')
|
|
340
|
if len(parts) > 2:
|
|
340
|
if len(parts) > 2:
|
|
341
|
tail = '/'.join(parts[-2:])
|
|
341
|
tail = '/'.join(parts[-2:])
|
|
342
|
|
|
342
|
|
|
343
|
return (drivepart + (
|
|
343
|
return (drivepart + (
|
|
344
|
cwd == '/' and '/' or tail))
|
|
344
|
cwd == '/' and '/' or tail))
|
|
345
|
|
|
345
|
|
|
346
|
|
|
346
|
|
|
347
|
# This function is used by ipython in a lot of places to make system calls.
|
|
347
|
# This function is used by ipython in a lot of places to make system calls.
|
|
348
|
# We need it to be slightly different under win32, due to the vagaries of
|
|
348
|
# We need it to be slightly different under win32, due to the vagaries of
|
|
349
|
# 'network shares'. A win32 override is below.
|
|
349
|
# 'network shares'. A win32 override is below.
|
|
350
|
|
|
350
|
|
|
351
|
def shell(cmd,verbose=0,debug=0,header=''):
|
|
351
|
def shell(cmd,verbose=0,debug=0,header=''):
|
|
352
|
"""Execute a command in the system shell, always return None.
|
|
352
|
"""Execute a command in the system shell, always return None.
|
|
353
|
|
|
353
|
|
|
354
|
Options:
|
|
354
|
Options:
|
|
355
|
|
|
355
|
|
|
356
|
- verbose (0): print the command to be executed.
|
|
356
|
- verbose (0): print the command to be executed.
|
|
357
|
|
|
357
|
|
|
358
|
- debug (0): only print, do not actually execute.
|
|
358
|
- debug (0): only print, do not actually execute.
|
|
359
|
|
|
359
|
|
|
360
|
- header (''): Header to print on screen prior to the executed command (it
|
|
360
|
- header (''): Header to print on screen prior to the executed command (it
|
|
361
|
is only prepended to the command, no newlines are added).
|
|
361
|
is only prepended to the command, no newlines are added).
|
|
362
|
|
|
362
|
|
|
363
|
Note: this is similar to genutils.system(), but it returns None so it can
|
|
363
|
Note: this is similar to genutils.system(), but it returns None so it can
|
|
364
|
be conveniently used in interactive loops without getting the return value
|
|
364
|
be conveniently used in interactive loops without getting the return value
|
|
365
|
(typically 0) printed many times."""
|
|
365
|
(typically 0) printed many times."""
|
|
366
|
|
|
366
|
|
|
367
|
stat = 0
|
|
367
|
stat = 0
|
|
368
|
if verbose or debug: print header+cmd
|
|
368
|
if verbose or debug: print header+cmd
|
|
369
|
# flush stdout so we don't mangle python's buffering
|
|
369
|
# flush stdout so we don't mangle python's buffering
|
|
370
|
sys.stdout.flush()
|
|
370
|
sys.stdout.flush()
|
|
371
|
|
|
371
|
|
|
372
|
if not debug:
|
|
372
|
if not debug:
|
|
373
|
platutils.set_term_title("IPy " + cmd)
|
|
373
|
platutils.set_term_title("IPy " + cmd)
|
|
374
|
os.system(cmd)
|
|
374
|
os.system(cmd)
|
|
375
|
platutils.set_term_title("IPy " + abbrev_cwd())
|
|
375
|
platutils.set_term_title("IPy " + abbrev_cwd())
|
|
376
|
|
|
376
|
|
|
377
|
# override shell() for win32 to deal with network shares
|
|
377
|
# override shell() for win32 to deal with network shares
|
|
378
|
if os.name in ('nt','dos'):
|
|
378
|
if os.name in ('nt','dos'):
|
|
379
|
|
|
379
|
|
|
380
|
shell_ori = shell
|
|
380
|
shell_ori = shell
|
|
381
|
|
|
381
|
|
|
382
|
def shell(cmd,verbose=0,debug=0,header=''):
|
|
382
|
def shell(cmd,verbose=0,debug=0,header=''):
|
|
383
|
if os.getcwd().startswith(r"\\"):
|
|
383
|
if os.getcwd().startswith(r"\\"):
|
|
384
|
path = os.getcwd()
|
|
384
|
path = os.getcwd()
|
|
385
|
# change to c drive (cannot be on UNC-share when issuing os.system,
|
|
385
|
# change to c drive (cannot be on UNC-share when issuing os.system,
|
|
386
|
# as cmd.exe cannot handle UNC addresses)
|
|
386
|
# as cmd.exe cannot handle UNC addresses)
|
|
387
|
os.chdir("c:")
|
|
387
|
os.chdir("c:")
|
|
388
|
# issue pushd to the UNC-share and then run the command
|
|
388
|
# issue pushd to the UNC-share and then run the command
|
|
389
|
try:
|
|
389
|
try:
|
|
390
|
shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
|
|
390
|
shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
|
|
391
|
finally:
|
|
391
|
finally:
|
|
392
|
os.chdir(path)
|
|
392
|
os.chdir(path)
|
|
393
|
else:
|
|
393
|
else:
|
|
394
|
shell_ori(cmd,verbose,debug,header)
|
|
394
|
shell_ori(cmd,verbose,debug,header)
|
|
395
|
|
|
395
|
|
|
396
|
shell.__doc__ = shell_ori.__doc__
|
|
396
|
shell.__doc__ = shell_ori.__doc__
|
|
397
|
|
|
397
|
|
|
398
|
def getoutput(cmd,verbose=0,debug=0,header='',split=0):
|
|
398
|
def getoutput(cmd,verbose=0,debug=0,header='',split=0):
|
|
399
|
"""Dummy substitute for perl's backquotes.
|
|
399
|
"""Dummy substitute for perl's backquotes.
|
|
400
|
|
|
400
|
|
|
401
|
Executes a command and returns the output.
|
|
401
|
Executes a command and returns the output.
|
|
402
|
|
|
402
|
|
|
403
|
Accepts the same arguments as system(), plus:
|
|
403
|
Accepts the same arguments as system(), plus:
|
|
404
|
|
|
404
|
|
|
405
|
- split(0): if true, the output is returned as a list split on newlines.
|
|
405
|
- split(0): if true, the output is returned as a list split on newlines.
|
|
406
|
|
|
406
|
|
|
407
|
Note: a stateful version of this function is available through the
|
|
407
|
Note: a stateful version of this function is available through the
|
|
408
|
SystemExec class.
|
|
408
|
SystemExec class.
|
|
409
|
|
|
409
|
|
|
410
|
This is pretty much deprecated and rarely used,
|
|
410
|
This is pretty much deprecated and rarely used,
|
|
411
|
genutils.getoutputerror may be what you need.
|
|
411
|
genutils.getoutputerror may be what you need.
|
|
412
|
|
|
412
|
|
|
413
|
"""
|
|
413
|
"""
|
|
414
|
|
|
414
|
|
|
415
|
if verbose or debug: print header+cmd
|
|
415
|
if verbose or debug: print header+cmd
|
|
416
|
if not debug:
|
|
416
|
if not debug:
|
|
417
|
output = os.popen(cmd).read()
|
|
417
|
output = os.popen(cmd).read()
|
|
418
|
# stipping last \n is here for backwards compat.
|
|
418
|
# stipping last \n is here for backwards compat.
|
|
419
|
if output.endswith('\n'):
|
|
419
|
if output.endswith('\n'):
|
|
420
|
output = output[:-1]
|
|
420
|
output = output[:-1]
|
|
421
|
if split:
|
|
421
|
if split:
|
|
422
|
return output.split('\n')
|
|
422
|
return output.split('\n')
|
|
423
|
else:
|
|
423
|
else:
|
|
424
|
return output
|
|
424
|
return output
|
|
425
|
|
|
425
|
|
|
426
|
def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
|
|
426
|
def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
|
|
427
|
"""Return (standard output,standard error) of executing cmd in a shell.
|
|
427
|
"""Return (standard output,standard error) of executing cmd in a shell.
|
|
428
|
|
|
428
|
|
|
429
|
Accepts the same arguments as system(), plus:
|
|
429
|
Accepts the same arguments as system(), plus:
|
|
430
|
|
|
430
|
|
|
431
|
- split(0): if true, each of stdout/err is returned as a list split on
|
|
431
|
- split(0): if true, each of stdout/err is returned as a list split on
|
|
432
|
newlines.
|
|
432
|
newlines.
|
|
433
|
|
|
433
|
|
|
434
|
Note: a stateful version of this function is available through the
|
|
434
|
Note: a stateful version of this function is available through the
|
|
435
|
SystemExec class."""
|
|
435
|
SystemExec class."""
|
|
436
|
|
|
436
|
|
|
437
|
if verbose or debug: print header+cmd
|
|
437
|
if verbose or debug: print header+cmd
|
|
438
|
if not cmd:
|
|
438
|
if not cmd:
|
|
439
|
if split:
|
|
439
|
if split:
|
|
440
|
return [],[]
|
|
440
|
return [],[]
|
|
441
|
else:
|
|
441
|
else:
|
|
442
|
return '',''
|
|
442
|
return '',''
|
|
443
|
if not debug:
|
|
443
|
if not debug:
|
|
444
|
pin,pout,perr = os.popen3(cmd)
|
|
444
|
pin,pout,perr = os.popen3(cmd)
|
|
445
|
tout = pout.read().rstrip()
|
|
445
|
tout = pout.read().rstrip()
|
|
446
|
terr = perr.read().rstrip()
|
|
446
|
terr = perr.read().rstrip()
|
|
447
|
pin.close()
|
|
447
|
pin.close()
|
|
448
|
pout.close()
|
|
448
|
pout.close()
|
|
449
|
perr.close()
|
|
449
|
perr.close()
|
|
450
|
if split:
|
|
450
|
if split:
|
|
451
|
return tout.split('\n'),terr.split('\n')
|
|
451
|
return tout.split('\n'),terr.split('\n')
|
|
452
|
else:
|
|
452
|
else:
|
|
453
|
return tout,terr
|
|
453
|
return tout,terr
|
|
454
|
|
|
454
|
|
|
455
|
# for compatibility with older naming conventions
|
|
455
|
# for compatibility with older naming conventions
|
|
456
|
xsys = system
|
|
456
|
xsys = system
|
|
457
|
bq = getoutput
|
|
457
|
bq = getoutput
|
|
458
|
|
|
458
|
|
|
459
|
class SystemExec:
|
|
459
|
class SystemExec:
|
|
460
|
"""Access the system and getoutput functions through a stateful interface.
|
|
460
|
"""Access the system and getoutput functions through a stateful interface.
|
|
461
|
|
|
461
|
|
|
462
|
Note: here we refer to the system and getoutput functions from this
|
|
462
|
Note: here we refer to the system and getoutput functions from this
|
|
463
|
library, not the ones from the standard python library.
|
|
463
|
library, not the ones from the standard python library.
|
|
464
|
|
|
464
|
|
|
465
|
This class offers the system and getoutput functions as methods, but the
|
|
465
|
This class offers the system and getoutput functions as methods, but the
|
|
466
|
verbose, debug and header parameters can be set for the instance (at
|
|
466
|
verbose, debug and header parameters can be set for the instance (at
|
|
467
|
creation time or later) so that they don't need to be specified on each
|
|
467
|
creation time or later) so that they don't need to be specified on each
|
|
468
|
call.
|
|
468
|
call.
|
|
469
|
|
|
469
|
|
|
470
|
For efficiency reasons, there's no way to override the parameters on a
|
|
470
|
For efficiency reasons, there's no way to override the parameters on a
|
|
471
|
per-call basis other than by setting instance attributes. If you need
|
|
471
|
per-call basis other than by setting instance attributes. If you need
|
|
472
|
local overrides, it's best to directly call system() or getoutput().
|
|
472
|
local overrides, it's best to directly call system() or getoutput().
|
|
473
|
|
|
473
|
|
|
474
|
The following names are provided as alternate options:
|
|
474
|
The following names are provided as alternate options:
|
|
475
|
- xsys: alias to system
|
|
475
|
- xsys: alias to system
|
|
476
|
- bq: alias to getoutput
|
|
476
|
- bq: alias to getoutput
|
|
477
|
|
|
477
|
|
|
478
|
An instance can then be created as:
|
|
478
|
An instance can then be created as:
|
|
479
|
>>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
|
|
479
|
>>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
|
|
480
|
"""
|
|
480
|
"""
|
|
481
|
|
|
481
|
|
|
482
|
def __init__(self,verbose=0,debug=0,header='',split=0):
|
|
482
|
def __init__(self,verbose=0,debug=0,header='',split=0):
|
|
483
|
"""Specify the instance's values for verbose, debug and header."""
|
|
483
|
"""Specify the instance's values for verbose, debug and header."""
|
|
484
|
setattr_list(self,'verbose debug header split')
|
|
484
|
setattr_list(self,'verbose debug header split')
|
|
485
|
|
|
485
|
|
|
486
|
def system(self,cmd):
|
|
486
|
def system(self,cmd):
|
|
487
|
"""Stateful interface to system(), with the same keyword parameters."""
|
|
487
|
"""Stateful interface to system(), with the same keyword parameters."""
|
|
488
|
|
|
488
|
|
|
489
|
system(cmd,self.verbose,self.debug,self.header)
|
|
489
|
system(cmd,self.verbose,self.debug,self.header)
|
|
490
|
|
|
490
|
|
|
491
|
def shell(self,cmd):
|
|
491
|
def shell(self,cmd):
|
|
492
|
"""Stateful interface to shell(), with the same keyword parameters."""
|
|
492
|
"""Stateful interface to shell(), with the same keyword parameters."""
|
|
493
|
|
|
493
|
|
|
494
|
shell(cmd,self.verbose,self.debug,self.header)
|
|
494
|
shell(cmd,self.verbose,self.debug,self.header)
|
|
495
|
|
|
495
|
|
|
496
|
xsys = system # alias
|
|
496
|
xsys = system # alias
|
|
497
|
|
|
497
|
|
|
498
|
def getoutput(self,cmd):
|
|
498
|
def getoutput(self,cmd):
|
|
499
|
"""Stateful interface to getoutput()."""
|
|
499
|
"""Stateful interface to getoutput()."""
|
|
500
|
|
|
500
|
|
|
501
|
return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
|
|
501
|
return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
|
|
502
|
|
|
502
|
|
|
503
|
def getoutputerror(self,cmd):
|
|
503
|
def getoutputerror(self,cmd):
|
|
504
|
"""Stateful interface to getoutputerror()."""
|
|
504
|
"""Stateful interface to getoutputerror()."""
|
|
505
|
|
|
505
|
|
|
506
|
return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
|
|
506
|
return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
|
|
507
|
|
|
507
|
|
|
508
|
bq = getoutput # alias
|
|
508
|
bq = getoutput # alias
|
|
509
|
|
|
509
|
|
|
510
|
#-----------------------------------------------------------------------------
|
|
510
|
#-----------------------------------------------------------------------------
|
|
511
|
def mutex_opts(dict,ex_op):
|
|
511
|
def mutex_opts(dict,ex_op):
|
|
512
|
"""Check for presence of mutually exclusive keys in a dict.
|
|
512
|
"""Check for presence of mutually exclusive keys in a dict.
|
|
513
|
|
|
513
|
|
|
514
|
Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
|
|
514
|
Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
|
|
515
|
for op1,op2 in ex_op:
|
|
515
|
for op1,op2 in ex_op:
|
|
516
|
if op1 in dict and op2 in dict:
|
|
516
|
if op1 in dict and op2 in dict:
|
|
517
|
raise ValueError,'\n*** ERROR in Arguments *** '\
|
|
517
|
raise ValueError,'\n*** ERROR in Arguments *** '\
|
|
518
|
'Options '+op1+' and '+op2+' are mutually exclusive.'
|
|
518
|
'Options '+op1+' and '+op2+' are mutually exclusive.'
|
|
519
|
|
|
519
|
|
|
520
|
#-----------------------------------------------------------------------------
|
|
520
|
#-----------------------------------------------------------------------------
|
|
521
|
def get_py_filename(name):
|
|
521
|
def get_py_filename(name):
|
|
522
|
"""Return a valid python filename in the current directory.
|
|
522
|
"""Return a valid python filename in the current directory.
|
|
523
|
|
|
523
|
|
|
524
|
If the given name is not a file, it adds '.py' and searches again.
|
|
524
|
If the given name is not a file, it adds '.py' and searches again.
|
|
525
|
Raises IOError with an informative message if the file isn't found."""
|
|
525
|
Raises IOError with an informative message if the file isn't found."""
|
|
526
|
|
|
526
|
|
|
527
|
name = os.path.expanduser(name)
|
|
527
|
name = os.path.expanduser(name)
|
|
528
|
if not os.path.isfile(name) and not name.endswith('.py'):
|
|
528
|
if not os.path.isfile(name) and not name.endswith('.py'):
|
|
529
|
name += '.py'
|
|
529
|
name += '.py'
|
|
530
|
if os.path.isfile(name):
|
|
530
|
if os.path.isfile(name):
|
|
531
|
return name
|
|
531
|
return name
|
|
532
|
else:
|
|
532
|
else:
|
|
533
|
raise IOError,'File `%s` not found.' % name
|
|
533
|
raise IOError,'File `%s` not found.' % name
|
|
534
|
|
|
534
|
|
|
535
|
#-----------------------------------------------------------------------------
|
|
535
|
#-----------------------------------------------------------------------------
|
|
536
|
def filefind(fname,alt_dirs = None):
|
|
536
|
def filefind(fname,alt_dirs = None):
|
|
537
|
"""Return the given filename either in the current directory, if it
|
|
537
|
"""Return the given filename either in the current directory, if it
|
|
538
|
exists, or in a specified list of directories.
|
|
538
|
exists, or in a specified list of directories.
|
|
539
|
|
|
539
|
|
|
540
|
~ expansion is done on all file and directory names.
|
|
540
|
~ expansion is done on all file and directory names.
|
|
541
|
|
|
541
|
|
|
542
|
Upon an unsuccessful search, raise an IOError exception."""
|
|
542
|
Upon an unsuccessful search, raise an IOError exception."""
|
|
543
|
|
|
543
|
|
|
544
|
if alt_dirs is None:
|
|
544
|
if alt_dirs is None:
|
|
545
|
try:
|
|
545
|
try:
|
|
546
|
alt_dirs = get_home_dir()
|
|
546
|
alt_dirs = get_home_dir()
|
|
547
|
except HomeDirError:
|
|
547
|
except HomeDirError:
|
|
548
|
alt_dirs = os.getcwd()
|
|
548
|
alt_dirs = os.getcwd()
|
|
549
|
search = [fname] + list_strings(alt_dirs)
|
|
549
|
search = [fname] + list_strings(alt_dirs)
|
|
550
|
search = map(os.path.expanduser,search)
|
|
550
|
search = map(os.path.expanduser,search)
|
|
551
|
#print 'search list for',fname,'list:',search # dbg
|
|
551
|
#print 'search list for',fname,'list:',search # dbg
|
|
552
|
fname = search[0]
|
|
552
|
fname = search[0]
|
|
553
|
if os.path.isfile(fname):
|
|
553
|
if os.path.isfile(fname):
|
|
554
|
return fname
|
|
554
|
return fname
|
|
555
|
for direc in search[1:]:
|
|
555
|
for direc in search[1:]:
|
|
556
|
testname = os.path.join(direc,fname)
|
|
556
|
testname = os.path.join(direc,fname)
|
|
557
|
#print 'testname',testname # dbg
|
|
557
|
#print 'testname',testname # dbg
|
|
558
|
if os.path.isfile(testname):
|
|
558
|
if os.path.isfile(testname):
|
|
559
|
return testname
|
|
559
|
return testname
|
|
560
|
raise IOError,'File' + `fname` + \
|
|
560
|
raise IOError,'File' + `fname` + \
|
|
561
|
' not found in current or supplied directories:' + `alt_dirs`
|
|
561
|
' not found in current or supplied directories:' + `alt_dirs`
|
|
562
|
|
|
562
|
|
|
563
|
#----------------------------------------------------------------------------
|
|
563
|
#----------------------------------------------------------------------------
|
|
564
|
def file_read(filename):
|
|
564
|
def file_read(filename):
|
|
565
|
"""Read a file and close it. Returns the file source."""
|
|
565
|
"""Read a file and close it. Returns the file source."""
|
|
566
|
fobj = open(filename,'r');
|
|
566
|
fobj = open(filename,'r');
|
|
567
|
source = fobj.read();
|
|
567
|
source = fobj.read();
|
|
568
|
fobj.close()
|
|
568
|
fobj.close()
|
|
569
|
return source
|
|
569
|
return source
|
|
570
|
|
|
570
|
|
|
571
|
def file_readlines(filename):
|
|
571
|
def file_readlines(filename):
|
|
572
|
"""Read a file and close it. Returns the file source using readlines()."""
|
|
572
|
"""Read a file and close it. Returns the file source using readlines()."""
|
|
573
|
fobj = open(filename,'r');
|
|
573
|
fobj = open(filename,'r');
|
|
574
|
lines = fobj.readlines();
|
|
574
|
lines = fobj.readlines();
|
|
575
|
fobj.close()
|
|
575
|
fobj.close()
|
|
576
|
return lines
|
|
576
|
return lines
|
|
577
|
|
|
577
|
|
|
578
|
#----------------------------------------------------------------------------
|
|
578
|
#----------------------------------------------------------------------------
|
|
579
|
def target_outdated(target,deps):
|
|
579
|
def target_outdated(target,deps):
|
|
580
|
"""Determine whether a target is out of date.
|
|
580
|
"""Determine whether a target is out of date.
|
|
581
|
|
|
581
|
|
|
582
|
target_outdated(target,deps) -> 1/0
|
|
582
|
target_outdated(target,deps) -> 1/0
|
|
583
|
|
|
583
|
|
|
584
|
deps: list of filenames which MUST exist.
|
|
584
|
deps: list of filenames which MUST exist.
|
|
585
|
target: single filename which may or may not exist.
|
|
585
|
target: single filename which may or may not exist.
|
|
586
|
|
|
586
|
|
|
587
|
If target doesn't exist or is older than any file listed in deps, return
|
|
587
|
If target doesn't exist or is older than any file listed in deps, return
|
|
588
|
true, otherwise return false.
|
|
588
|
true, otherwise return false.
|
|
589
|
"""
|
|
589
|
"""
|
|
590
|
try:
|
|
590
|
try:
|
|
591
|
target_time = os.path.getmtime(target)
|
|
591
|
target_time = os.path.getmtime(target)
|
|
592
|
except os.error:
|
|
592
|
except os.error:
|
|
593
|
return 1
|
|
593
|
return 1
|
|
594
|
for dep in deps:
|
|
594
|
for dep in deps:
|
|
595
|
dep_time = os.path.getmtime(dep)
|
|
595
|
dep_time = os.path.getmtime(dep)
|
|
596
|
if dep_time > target_time:
|
|
596
|
if dep_time > target_time:
|
|
597
|
#print "For target",target,"Dep failed:",dep # dbg
|
|
597
|
#print "For target",target,"Dep failed:",dep # dbg
|
|
598
|
#print "times (dep,tar):",dep_time,target_time # dbg
|
|
598
|
#print "times (dep,tar):",dep_time,target_time # dbg
|
|
599
|
return 1
|
|
599
|
return 1
|
|
600
|
return 0
|
|
600
|
return 0
|
|
601
|
|
|
601
|
|
|
602
|
#-----------------------------------------------------------------------------
|
|
602
|
#-----------------------------------------------------------------------------
|
|
603
|
def target_update(target,deps,cmd):
|
|
603
|
def target_update(target,deps,cmd):
|
|
604
|
"""Update a target with a given command given a list of dependencies.
|
|
604
|
"""Update a target with a given command given a list of dependencies.
|
|
605
|
|
|
605
|
|
|
606
|
target_update(target,deps,cmd) -> runs cmd if target is outdated.
|
|
606
|
target_update(target,deps,cmd) -> runs cmd if target is outdated.
|
|
607
|
|
|
607
|
|
|
608
|
This is just a wrapper around target_outdated() which calls the given
|
|
608
|
This is just a wrapper around target_outdated() which calls the given
|
|
609
|
command if target is outdated."""
|
|
609
|
command if target is outdated."""
|
|
610
|
|
|
610
|
|
|
611
|
if target_outdated(target,deps):
|
|
611
|
if target_outdated(target,deps):
|
|
612
|
xsys(cmd)
|
|
612
|
xsys(cmd)
|
|
613
|
|
|
613
|
|
|
614
|
#----------------------------------------------------------------------------
|
|
614
|
#----------------------------------------------------------------------------
|
|
615
|
def unquote_ends(istr):
|
|
615
|
def unquote_ends(istr):
|
|
616
|
"""Remove a single pair of quotes from the endpoints of a string."""
|
|
616
|
"""Remove a single pair of quotes from the endpoints of a string."""
|
|
617
|
|
|
617
|
|
|
618
|
if not istr:
|
|
618
|
if not istr:
|
|
619
|
return istr
|
|
619
|
return istr
|
|
620
|
if (istr[0]=="'" and istr[-1]=="'") or \
|
|
620
|
if (istr[0]=="'" and istr[-1]=="'") or \
|
|
621
|
(istr[0]=='"' and istr[-1]=='"'):
|
|
621
|
(istr[0]=='"' and istr[-1]=='"'):
|
|
622
|
return istr[1:-1]
|
|
622
|
return istr[1:-1]
|
|
623
|
else:
|
|
623
|
else:
|
|
624
|
return istr
|
|
624
|
return istr
|
|
625
|
|
|
625
|
|
|
626
|
#----------------------------------------------------------------------------
|
|
626
|
#----------------------------------------------------------------------------
|
|
627
|
def process_cmdline(argv,names=[],defaults={},usage=''):
|
|
627
|
def process_cmdline(argv,names=[],defaults={},usage=''):
|
|
628
|
""" Process command-line options and arguments.
|
|
628
|
""" Process command-line options and arguments.
|
|
629
|
|
|
629
|
|
|
630
|
Arguments:
|
|
630
|
Arguments:
|
|
631
|
|
|
631
|
|
|
632
|
- argv: list of arguments, typically sys.argv.
|
|
632
|
- argv: list of arguments, typically sys.argv.
|
|
633
|
|
|
633
|
|
|
634
|
- names: list of option names. See DPyGetOpt docs for details on options
|
|
634
|
- names: list of option names. See DPyGetOpt docs for details on options
|
|
635
|
syntax.
|
|
635
|
syntax.
|
|
636
|
|
|
636
|
|
|
637
|
- defaults: dict of default values.
|
|
637
|
- defaults: dict of default values.
|
|
638
|
|
|
638
|
|
|
639
|
- usage: optional usage notice to print if a wrong argument is passed.
|
|
639
|
- usage: optional usage notice to print if a wrong argument is passed.
|
|
640
|
|
|
640
|
|
|
641
|
Return a dict of options and a list of free arguments."""
|
|
641
|
Return a dict of options and a list of free arguments."""
|
|
642
|
|
|
642
|
|
|
643
|
getopt = DPyGetOpt.DPyGetOpt()
|
|
643
|
getopt = DPyGetOpt.DPyGetOpt()
|
|
644
|
getopt.setIgnoreCase(0)
|
|
644
|
getopt.setIgnoreCase(0)
|
|
645
|
getopt.parseConfiguration(names)
|
|
645
|
getopt.parseConfiguration(names)
|
|
646
|
|
|
646
|
|
|
647
|
try:
|
|
647
|
try:
|
|
648
|
getopt.processArguments(argv)
|
|
648
|
getopt.processArguments(argv)
|
|
649
|
except DPyGetOpt.ArgumentError, exc:
|
|
649
|
except DPyGetOpt.ArgumentError, exc:
|
|
650
|
print usage
|
|
650
|
print usage
|
|
651
|
warn('"%s"' % exc,level=4)
|
|
651
|
warn('"%s"' % exc,level=4)
|
|
652
|
|
|
652
|
|
|
653
|
defaults.update(getopt.optionValues)
|
|
653
|
defaults.update(getopt.optionValues)
|
|
654
|
args = getopt.freeValues
|
|
654
|
args = getopt.freeValues
|
|
655
|
|
|
655
|
|
|
656
|
return defaults,args
|
|
656
|
return defaults,args
|
|
657
|
|
|
657
|
|
|
658
|
#----------------------------------------------------------------------------
|
|
658
|
#----------------------------------------------------------------------------
|
|
659
|
def optstr2types(ostr):
|
|
659
|
def optstr2types(ostr):
|
|
660
|
"""Convert a string of option names to a dict of type mappings.
|
|
660
|
"""Convert a string of option names to a dict of type mappings.
|
|
661
|
|
|
661
|
|
|
662
|
optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
|
|
662
|
optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
|
|
663
|
|
|
663
|
|
|
664
|
This is used to get the types of all the options in a string formatted
|
|
664
|
This is used to get the types of all the options in a string formatted
|
|
665
|
with the conventions of DPyGetOpt. The 'type' None is used for options
|
|
665
|
with the conventions of DPyGetOpt. The 'type' None is used for options
|
|
666
|
which are strings (they need no further conversion). This function's main
|
|
666
|
which are strings (they need no further conversion). This function's main
|
|
667
|
use is to get a typemap for use with read_dict().
|
|
667
|
use is to get a typemap for use with read_dict().
|
|
668
|
"""
|
|
668
|
"""
|
|
669
|
|
|
669
|
|
|
670
|
typeconv = {None:'',int:'',float:''}
|
|
670
|
typeconv = {None:'',int:'',float:''}
|
|
671
|
typemap = {'s':None,'i':int,'f':float}
|
|
671
|
typemap = {'s':None,'i':int,'f':float}
|
|
672
|
opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
|
|
672
|
opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
|
|
673
|
|
|
673
|
|
|
674
|
for w in ostr.split():
|
|
674
|
for w in ostr.split():
|
|
675
|
oname,alias,otype = opt_re.match(w).groups()
|
|
675
|
oname,alias,otype = opt_re.match(w).groups()
|
|
676
|
if otype == '' or alias == '!': # simple switches are integers too
|
|
676
|
if otype == '' or alias == '!': # simple switches are integers too
|
|
677
|
otype = 'i'
|
|
677
|
otype = 'i'
|
|
678
|
typeconv[typemap[otype]] += oname + ' '
|
|
678
|
typeconv[typemap[otype]] += oname + ' '
|
|
679
|
return typeconv
|
|
679
|
return typeconv
|
|
680
|
|
|
680
|
|
|
681
|
#----------------------------------------------------------------------------
|
|
681
|
#----------------------------------------------------------------------------
|
|
682
|
def read_dict(filename,type_conv=None,**opt):
|
|
682
|
def read_dict(filename,type_conv=None,**opt):
|
|
683
|
r"""Read a dictionary of key=value pairs from an input file, optionally
|
|
683
|
r"""Read a dictionary of key=value pairs from an input file, optionally
|
|
684
|
performing conversions on the resulting values.
|
|
684
|
performing conversions on the resulting values.
|
|
685
|
|
|
685
|
|
|
686
|
read_dict(filename,type_conv,**opt) -> dict
|
|
686
|
read_dict(filename,type_conv,**opt) -> dict
|
|
687
|
|
|
687
|
|
|
688
|
Only one value per line is accepted, the format should be
|
|
688
|
Only one value per line is accepted, the format should be
|
|
689
|
# optional comments are ignored
|
|
689
|
# optional comments are ignored
|
|
690
|
key value\n
|
|
690
|
key value\n
|
|
691
|
|
|
691
|
|
|
692
|
Args:
|
|
692
|
Args:
|
|
693
|
|
|
693
|
|
|
694
|
- type_conv: A dictionary specifying which keys need to be converted to
|
|
694
|
- type_conv: A dictionary specifying which keys need to be converted to
|
|
695
|
which types. By default all keys are read as strings. This dictionary
|
|
695
|
which types. By default all keys are read as strings. This dictionary
|
|
696
|
should have as its keys valid conversion functions for strings
|
|
696
|
should have as its keys valid conversion functions for strings
|
|
697
|
(int,long,float,complex, or your own). The value for each key
|
|
697
|
(int,long,float,complex, or your own). The value for each key
|
|
698
|
(converter) should be a whitespace separated string containing the names
|
|
698
|
(converter) should be a whitespace separated string containing the names
|
|
699
|
of all the entries in the file to be converted using that function. For
|
|
699
|
of all the entries in the file to be converted using that function. For
|
|
700
|
keys to be left alone, use None as the conversion function (only needed
|
|
700
|
keys to be left alone, use None as the conversion function (only needed
|
|
701
|
with purge=1, see below).
|
|
701
|
with purge=1, see below).
|
|
702
|
|
|
702
|
|
|
703
|
- opt: dictionary with extra options as below (default in parens)
|
|
703
|
- opt: dictionary with extra options as below (default in parens)
|
|
704
|
|
|
704
|
|
|
705
|
purge(0): if set to 1, all keys *not* listed in type_conv are purged out
|
|
705
|
purge(0): if set to 1, all keys *not* listed in type_conv are purged out
|
|
706
|
of the dictionary to be returned. If purge is going to be used, the
|
|
706
|
of the dictionary to be returned. If purge is going to be used, the
|
|
707
|
set of keys to be left as strings also has to be explicitly specified
|
|
707
|
set of keys to be left as strings also has to be explicitly specified
|
|
708
|
using the (non-existent) conversion function None.
|
|
708
|
using the (non-existent) conversion function None.
|
|
709
|
|
|
709
|
|
|
710
|
fs(None): field separator. This is the key/value separator to be used
|
|
710
|
fs(None): field separator. This is the key/value separator to be used
|
|
711
|
when parsing the file. The None default means any whitespace [behavior
|
|
711
|
when parsing the file. The None default means any whitespace [behavior
|
|
712
|
of string.split()].
|
|
712
|
of string.split()].
|
|
713
|
|
|
713
|
|
|
714
|
strip(0): if 1, strip string values of leading/trailinig whitespace.
|
|
714
|
strip(0): if 1, strip string values of leading/trailinig whitespace.
|
|
715
|
|
|
715
|
|
|
716
|
warn(1): warning level if requested keys are not found in file.
|
|
716
|
warn(1): warning level if requested keys are not found in file.
|
|
717
|
- 0: silently ignore.
|
|
717
|
- 0: silently ignore.
|
|
718
|
- 1: inform but proceed.
|
|
718
|
- 1: inform but proceed.
|
|
719
|
- 2: raise KeyError exception.
|
|
719
|
- 2: raise KeyError exception.
|
|
720
|
|
|
720
|
|
|
721
|
no_empty(0): if 1, remove keys with whitespace strings as a value.
|
|
721
|
no_empty(0): if 1, remove keys with whitespace strings as a value.
|
|
722
|
|
|
722
|
|
|
723
|
unique([]): list of keys (or space separated string) which can't be
|
|
723
|
unique([]): list of keys (or space separated string) which can't be
|
|
724
|
repeated. If one such key is found in the file, each new instance
|
|
724
|
repeated. If one such key is found in the file, each new instance
|
|
725
|
overwrites the previous one. For keys not listed here, the behavior is
|
|
725
|
overwrites the previous one. For keys not listed here, the behavior is
|
|
726
|
to make a list of all appearances.
|
|
726
|
to make a list of all appearances.
|
|
727
|
|
|
727
|
|
|
728
|
Example:
|
|
728
|
Example:
|
|
729
|
|
|
729
|
|
|
730
|
If the input file test.ini contains (we put it in a string to keep the test
|
|
730
|
If the input file test.ini contains (we put it in a string to keep the test
|
|
731
|
self-contained):
|
|
731
|
self-contained):
|
|
732
|
|
|
732
|
|
|
733
|
>>> test_ini = '''\
|
|
733
|
>>> test_ini = '''\
|
|
734
|
... i 3
|
|
734
|
... i 3
|
|
735
|
... x 4.5
|
|
735
|
... x 4.5
|
|
736
|
... y 5.5
|
|
736
|
... y 5.5
|
|
737
|
... s hi ho'''
|
|
737
|
... s hi ho'''
|
|
738
|
|
|
738
|
|
|
739
|
Then we can use it as follows:
|
|
739
|
Then we can use it as follows:
|
|
740
|
>>> type_conv={int:'i',float:'x',None:'s'}
|
|
740
|
>>> type_conv={int:'i',float:'x',None:'s'}
|
|
741
|
|
|
741
|
|
|
742
|
>>> d = read_dict(test_ini)
|
|
742
|
>>> d = read_dict(test_ini)
|
|
743
|
|
|
743
|
|
|
744
|
>>> sorted(d.items())
|
|
744
|
>>> sorted(d.items())
|
|
745
|
[('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')]
|
|
745
|
[('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')]
|
|
746
|
|
|
746
|
|
|
747
|
>>> d = read_dict(test_ini,type_conv)
|
|
747
|
>>> d = read_dict(test_ini,type_conv)
|
|
748
|
|
|
748
|
|
|
749
|
>>> sorted(d.items())
|
|
749
|
>>> sorted(d.items())
|
|
750
|
[('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')]
|
|
750
|
[('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')]
|
|
751
|
|
|
751
|
|
|
752
|
>>> d = read_dict(test_ini,type_conv,purge=True)
|
|
752
|
>>> d = read_dict(test_ini,type_conv,purge=True)
|
|
753
|
|
|
753
|
|
|
754
|
>>> sorted(d.items())
|
|
754
|
>>> sorted(d.items())
|
|
755
|
[('i', 3), ('s', 'hi ho'), ('x', 4.5)]
|
|
755
|
[('i', 3), ('s', 'hi ho'), ('x', 4.5)]
|
|
756
|
"""
|
|
756
|
"""
|
|
757
|
|
|
757
|
|
|
758
|
# starting config
|
|
758
|
# starting config
|
|
759
|
opt.setdefault('purge',0)
|
|
759
|
opt.setdefault('purge',0)
|
|
760
|
opt.setdefault('fs',None) # field sep defaults to any whitespace
|
|
760
|
opt.setdefault('fs',None) # field sep defaults to any whitespace
|
|
761
|
opt.setdefault('strip',0)
|
|
761
|
opt.setdefault('strip',0)
|
|
762
|
opt.setdefault('warn',1)
|
|
762
|
opt.setdefault('warn',1)
|
|
763
|
opt.setdefault('no_empty',0)
|
|
763
|
opt.setdefault('no_empty',0)
|
|
764
|
opt.setdefault('unique','')
|
|
764
|
opt.setdefault('unique','')
|
|
765
|
if type(opt['unique']) in StringTypes:
|
|
765
|
if type(opt['unique']) in StringTypes:
|
|
766
|
unique_keys = qw(opt['unique'])
|
|
766
|
unique_keys = qw(opt['unique'])
|
|
767
|
elif type(opt['unique']) in (types.TupleType,types.ListType):
|
|
767
|
elif type(opt['unique']) in (types.TupleType,types.ListType):
|
|
768
|
unique_keys = opt['unique']
|
|
768
|
unique_keys = opt['unique']
|
|
769
|
else:
|
|
769
|
else:
|
|
770
|
raise ValueError, 'Unique keys must be given as a string, List or Tuple'
|
|
770
|
raise ValueError, 'Unique keys must be given as a string, List or Tuple'
|
|
771
|
|
|
771
|
|
|
772
|
dict = {}
|
|
772
|
dict = {}
|
|
773
|
|
|
773
|
|
|
774
|
# first read in table of values as strings
|
|
774
|
# first read in table of values as strings
|
|
775
|
if '\n' in filename:
|
|
775
|
if '\n' in filename:
|
|
776
|
lines = filename.splitlines()
|
|
776
|
lines = filename.splitlines()
|
|
777
|
file = None
|
|
777
|
file = None
|
|
778
|
else:
|
|
778
|
else:
|
|
779
|
file = open(filename,'r')
|
|
779
|
file = open(filename,'r')
|
|
780
|
lines = file.readlines()
|
|
780
|
lines = file.readlines()
|
|
781
|
for line in lines:
|
|
781
|
for line in lines:
|
|
782
|
line = line.strip()
|
|
782
|
line = line.strip()
|
|
783
|
if len(line) and line[0]=='#': continue
|
|
783
|
if len(line) and line[0]=='#': continue
|
|
784
|
if len(line)>0:
|
|
784
|
if len(line)>0:
|
|
785
|
lsplit = line.split(opt['fs'],1)
|
|
785
|
lsplit = line.split(opt['fs'],1)
|
|
786
|
try:
|
|
786
|
try:
|
|
787
|
key,val = lsplit
|
|
787
|
key,val = lsplit
|
|
788
|
except ValueError:
|
|
788
|
except ValueError:
|
|
789
|
key,val = lsplit[0],''
|
|
789
|
key,val = lsplit[0],''
|
|
790
|
key = key.strip()
|
|
790
|
key = key.strip()
|
|
791
|
if opt['strip']: val = val.strip()
|
|
791
|
if opt['strip']: val = val.strip()
|
|
792
|
if val == "''" or val == '""': val = ''
|
|
792
|
if val == "''" or val == '""': val = ''
|
|
793
|
if opt['no_empty'] and (val=='' or val.isspace()):
|
|
793
|
if opt['no_empty'] and (val=='' or val.isspace()):
|
|
794
|
continue
|
|
794
|
continue
|
|
795
|
# if a key is found more than once in the file, build a list
|
|
795
|
# if a key is found more than once in the file, build a list
|
|
796
|
# unless it's in the 'unique' list. In that case, last found in file
|
|
796
|
# unless it's in the 'unique' list. In that case, last found in file
|
|
797
|
# takes precedence. User beware.
|
|
797
|
# takes precedence. User beware.
|
|
798
|
try:
|
|
798
|
try:
|
|
799
|
if dict[key] and key in unique_keys:
|
|
799
|
if dict[key] and key in unique_keys:
|
|
800
|
dict[key] = val
|
|
800
|
dict[key] = val
|
|
801
|
elif type(dict[key]) is types.ListType:
|
|
801
|
elif type(dict[key]) is types.ListType:
|
|
802
|
dict[key].append(val)
|
|
802
|
dict[key].append(val)
|
|
803
|
else:
|
|
803
|
else:
|
|
804
|
dict[key] = [dict[key],val]
|
|
804
|
dict[key] = [dict[key],val]
|
|
805
|
except KeyError:
|
|
805
|
except KeyError:
|
|
806
|
dict[key] = val
|
|
806
|
dict[key] = val
|
|
807
|
# purge if requested
|
|
807
|
# purge if requested
|
|
808
|
if opt['purge']:
|
|
808
|
if opt['purge']:
|
|
809
|
accepted_keys = qwflat(type_conv.values())
|
|
809
|
accepted_keys = qwflat(type_conv.values())
|
|
810
|
for key in dict.keys():
|
|
810
|
for key in dict.keys():
|
|
811
|
if key in accepted_keys: continue
|
|
811
|
if key in accepted_keys: continue
|
|
812
|
del(dict[key])
|
|
812
|
del(dict[key])
|
|
813
|
# now convert if requested
|
|
813
|
# now convert if requested
|
|
814
|
if type_conv==None: return dict
|
|
814
|
if type_conv==None: return dict
|
|
815
|
conversions = type_conv.keys()
|
|
815
|
conversions = type_conv.keys()
|
|
816
|
try: conversions.remove(None)
|
|
816
|
try: conversions.remove(None)
|
|
817
|
except: pass
|
|
817
|
except: pass
|
|
818
|
for convert in conversions:
|
|
818
|
for convert in conversions:
|
|
819
|
for val in qw(type_conv[convert]):
|
|
819
|
for val in qw(type_conv[convert]):
|
|
820
|
try:
|
|
820
|
try:
|
|
821
|
dict[val] = convert(dict[val])
|
|
821
|
dict[val] = convert(dict[val])
|
|
822
|
except KeyError,e:
|
|
822
|
except KeyError,e:
|
|
823
|
if opt['warn'] == 0:
|
|
823
|
if opt['warn'] == 0:
|
|
824
|
pass
|
|
824
|
pass
|
|
825
|
elif opt['warn'] == 1:
|
|
825
|
elif opt['warn'] == 1:
|
|
826
|
print >>sys.stderr, 'Warning: key',val,\
|
|
826
|
print >>sys.stderr, 'Warning: key',val,\
|
|
827
|
'not found in file',filename
|
|
827
|
'not found in file',filename
|
|
828
|
elif opt['warn'] == 2:
|
|
828
|
elif opt['warn'] == 2:
|
|
829
|
raise KeyError,e
|
|
829
|
raise KeyError,e
|
|
830
|
else:
|
|
830
|
else:
|
|
831
|
raise ValueError,'Warning level must be 0,1 or 2'
|
|
831
|
raise ValueError,'Warning level must be 0,1 or 2'
|
|
832
|
|
|
832
|
|
|
833
|
return dict
|
|
833
|
return dict
|
|
834
|
|
|
834
|
|
|
835
|
#----------------------------------------------------------------------------
|
|
835
|
#----------------------------------------------------------------------------
|
|
836
|
def flag_calls(func):
|
|
836
|
def flag_calls(func):
|
|
837
|
"""Wrap a function to detect and flag when it gets called.
|
|
837
|
"""Wrap a function to detect and flag when it gets called.
|
|
838
|
|
|
838
|
|
|
839
|
This is a decorator which takes a function and wraps it in a function with
|
|
839
|
This is a decorator which takes a function and wraps it in a function with
|
|
840
|
a 'called' attribute. wrapper.called is initialized to False.
|
|
840
|
a 'called' attribute. wrapper.called is initialized to False.
|
|
841
|
|
|
841
|
|
|
842
|
The wrapper.called attribute is set to False right before each call to the
|
|
842
|
The wrapper.called attribute is set to False right before each call to the
|
|
843
|
wrapped function, so if the call fails it remains False. After the call
|
|
843
|
wrapped function, so if the call fails it remains False. After the call
|
|
844
|
completes, wrapper.called is set to True and the output is returned.
|
|
844
|
completes, wrapper.called is set to True and the output is returned.
|
|
845
|
|
|
845
|
|
|
846
|
Testing for truth in wrapper.called allows you to determine if a call to
|
|
846
|
Testing for truth in wrapper.called allows you to determine if a call to
|
|
847
|
func() was attempted and succeeded."""
|
|
847
|
func() was attempted and succeeded."""
|
|
848
|
|
|
848
|
|
|
849
|
def wrapper(*args,**kw):
|
|
849
|
def wrapper(*args,**kw):
|
|
850
|
wrapper.called = False
|
|
850
|
wrapper.called = False
|
|
851
|
out = func(*args,**kw)
|
|
851
|
out = func(*args,**kw)
|
|
852
|
wrapper.called = True
|
|
852
|
wrapper.called = True
|
|
853
|
return out
|
|
853
|
return out
|
|
854
|
|
|
854
|
|
|
855
|
wrapper.called = False
|
|
855
|
wrapper.called = False
|
|
856
|
wrapper.__doc__ = func.__doc__
|
|
856
|
wrapper.__doc__ = func.__doc__
|
|
857
|
return wrapper
|
|
857
|
return wrapper
|
|
858
|
|
|
858
|
|
|
859
|
#----------------------------------------------------------------------------
|
|
859
|
#----------------------------------------------------------------------------
|
|
860
|
def dhook_wrap(func,*a,**k):
|
|
860
|
def dhook_wrap(func,*a,**k):
|
|
861
|
"""Wrap a function call in a sys.displayhook controller.
|
|
861
|
"""Wrap a function call in a sys.displayhook controller.
|
|
862
|
|
|
862
|
|
|
863
|
Returns a wrapper around func which calls func, with all its arguments and
|
|
863
|
Returns a wrapper around func which calls func, with all its arguments and
|
|
864
|
keywords unmodified, using the default sys.displayhook. Since IPython
|
|
864
|
keywords unmodified, using the default sys.displayhook. Since IPython
|
|
865
|
modifies sys.displayhook, it breaks the behavior of certain systems that
|
|
865
|
modifies sys.displayhook, it breaks the behavior of certain systems that
|
|
866
|
rely on the default behavior, notably doctest.
|
|
866
|
rely on the default behavior, notably doctest.
|
|
867
|
"""
|
|
867
|
"""
|
|
868
|
|
|
868
|
|
|
869
|
def f(*a,**k):
|
|
869
|
def f(*a,**k):
|
|
870
|
|
|
870
|
|
|
871
|
dhook_s = sys.displayhook
|
|
871
|
dhook_s = sys.displayhook
|
|
872
|
sys.displayhook = sys.__displayhook__
|
|
872
|
sys.displayhook = sys.__displayhook__
|
|
873
|
try:
|
|
873
|
try:
|
|
874
|
out = func(*a,**k)
|
|
874
|
out = func(*a,**k)
|
|
875
|
finally:
|
|
875
|
finally:
|
|
876
|
sys.displayhook = dhook_s
|
|
876
|
sys.displayhook = dhook_s
|
|
877
|
|
|
877
|
|
|
878
|
return out
|
|
878
|
return out
|
|
879
|
|
|
879
|
|
|
880
|
f.__doc__ = func.__doc__
|
|
880
|
f.__doc__ = func.__doc__
|
|
881
|
return f
|
|
881
|
return f
|
|
882
|
|
|
882
|
|
|
883
|
#----------------------------------------------------------------------------
|
|
883
|
#----------------------------------------------------------------------------
|
|
884
|
def doctest_reload():
|
|
884
|
def doctest_reload():
|
|
885
|
"""Properly reload doctest to reuse it interactively.
|
|
885
|
"""Properly reload doctest to reuse it interactively.
|
|
886
|
|
|
886
|
|
|
887
|
This routine:
|
|
887
|
This routine:
|
|
888
|
|
|
888
|
|
|
889
|
- reloads doctest
|
|
889
|
- reloads doctest
|
|
890
|
|
|
890
|
|
|
891
|
- resets its global 'master' attribute to None, so that multiple uses of
|
|
891
|
- resets its global 'master' attribute to None, so that multiple uses of
|
|
892
|
the module interactively don't produce cumulative reports.
|
|
892
|
the module interactively don't produce cumulative reports.
|
|
893
|
|
|
893
|
|
|
894
|
- Monkeypatches its core test runner method to protect it from IPython's
|
|
894
|
- Monkeypatches its core test runner method to protect it from IPython's
|
|
895
|
modified displayhook. Doctest expects the default displayhook behavior
|
|
895
|
modified displayhook. Doctest expects the default displayhook behavior
|
|
896
|
deep down, so our modification breaks it completely. For this reason, a
|
|
896
|
deep down, so our modification breaks it completely. For this reason, a
|
|
897
|
hard monkeypatch seems like a reasonable solution rather than asking
|
|
897
|
hard monkeypatch seems like a reasonable solution rather than asking
|
|
898
|
users to manually use a different doctest runner when under IPython."""
|
|
898
|
users to manually use a different doctest runner when under IPython."""
|
|
899
|
|
|
899
|
|
|
900
|
import doctest
|
|
900
|
import doctest
|
|
901
|
reload(doctest)
|
|
901
|
reload(doctest)
|
|
902
|
doctest.master=None
|
|
902
|
doctest.master=None
|
|
903
|
|
|
903
|
|
|
904
|
try:
|
|
904
|
try:
|
|
905
|
doctest.DocTestRunner
|
|
905
|
doctest.DocTestRunner
|
|
906
|
except AttributeError:
|
|
906
|
except AttributeError:
|
|
907
|
# This is only for python 2.3 compatibility, remove once we move to
|
|
907
|
# This is only for python 2.3 compatibility, remove once we move to
|
|
908
|
# 2.4 only.
|
|
908
|
# 2.4 only.
|
|
909
|
pass
|
|
909
|
pass
|
|
910
|
else:
|
|
910
|
else:
|
|
911
|
doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
|
|
911
|
doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
|
|
912
|
|
|
912
|
|
|
913
|
#----------------------------------------------------------------------------
|
|
913
|
#----------------------------------------------------------------------------
|
|
914
|
class HomeDirError(Error):
|
|
914
|
class HomeDirError(Error):
|
|
915
|
pass
|
|
915
|
pass
|
|
916
|
|
|
916
|
|
|
917
|
def get_home_dir():
|
|
917
|
def get_home_dir():
|
|
918
|
"""Return the closest possible equivalent to a 'home' directory.
|
|
918
|
"""Return the closest possible equivalent to a 'home' directory.
|
|
919
|
|
|
919
|
|
|
920
|
We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
|
|
920
|
We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
|
|
921
|
|
|
921
|
|
|
922
|
Currently only Posix and NT are implemented, a HomeDirError exception is
|
|
922
|
Currently only Posix and NT are implemented, a HomeDirError exception is
|
|
923
|
raised for all other OSes. """
|
|
923
|
raised for all other OSes. """
|
|
924
|
|
|
924
|
|
|
925
|
isdir = os.path.isdir
|
|
925
|
isdir = os.path.isdir
|
|
926
|
env = os.environ
|
|
926
|
env = os.environ
|
|
927
|
|
|
927
|
|
|
928
|
# first, check py2exe distribution root directory for _ipython.
|
|
928
|
# first, check py2exe distribution root directory for _ipython.
|
|
929
|
# This overrides all. Normally does not exist.
|
|
929
|
# This overrides all. Normally does not exist.
|
|
930
|
|
|
930
|
|
|
931
|
if '\\library.zip\\' in IPython.__file__.lower():
|
|
931
|
if '\\library.zip\\' in IPython.__file__.lower():
|
|
932
|
root, rest = IPython.__file__.lower().split('library.zip')
|
|
932
|
root, rest = IPython.__file__.lower().split('library.zip')
|
|
933
|
if isdir(root + '_ipython'):
|
|
933
|
if isdir(root + '_ipython'):
|
|
934
|
os.environ["IPYKITROOT"] = root.rstrip('\\')
|
|
934
|
os.environ["IPYKITROOT"] = root.rstrip('\\')
|
|
935
|
return root
|
|
935
|
return root
|
|
936
|
|
|
936
|
|
|
937
|
try:
|
|
937
|
try:
|
|
938
|
homedir = env['HOME']
|
|
938
|
homedir = env['HOME']
|
|
939
|
if not isdir(homedir):
|
|
939
|
if not isdir(homedir):
|
|
940
|
# in case a user stuck some string which does NOT resolve to a
|
|
940
|
# in case a user stuck some string which does NOT resolve to a
|
|
941
|
# valid path, it's as good as if we hadn't foud it
|
|
941
|
# valid path, it's as good as if we hadn't foud it
|
|
942
|
raise KeyError
|
|
942
|
raise KeyError
|
|
943
|
return homedir
|
|
943
|
return homedir
|
|
944
|
except KeyError:
|
|
944
|
except KeyError:
|
|
945
|
if os.name == 'posix':
|
|
945
|
if os.name == 'posix':
|
|
946
|
raise HomeDirError,'undefined $HOME, IPython can not proceed.'
|
|
946
|
raise HomeDirError,'undefined $HOME, IPython can not proceed.'
|
|
947
|
elif os.name == 'nt':
|
|
947
|
elif os.name == 'nt':
|
|
948
|
# For some strange reason, win9x returns 'nt' for os.name.
|
|
948
|
# For some strange reason, win9x returns 'nt' for os.name.
|
|
949
|
try:
|
|
949
|
try:
|
|
950
|
homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
|
|
950
|
homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
|
|
951
|
if not isdir(homedir):
|
|
951
|
if not isdir(homedir):
|
|
952
|
homedir = os.path.join(env['USERPROFILE'])
|
|
952
|
homedir = os.path.join(env['USERPROFILE'])
|
|
953
|
if not isdir(homedir):
|
|
953
|
if not isdir(homedir):
|
|
954
|
raise HomeDirError
|
|
954
|
raise HomeDirError
|
|
955
|
return homedir
|
|
955
|
return homedir
|
|
956
|
except:
|
|
956
|
except:
|
|
957
|
try:
|
|
957
|
try:
|
|
958
|
# Use the registry to get the 'My Documents' folder.
|
|
958
|
# Use the registry to get the 'My Documents' folder.
|
|
959
|
import _winreg as wreg
|
|
959
|
import _winreg as wreg
|
|
960
|
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
|
|
960
|
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
|
|
961
|
"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
|
|
961
|
"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
|
|
962
|
homedir = wreg.QueryValueEx(key,'Personal')[0]
|
|
962
|
homedir = wreg.QueryValueEx(key,'Personal')[0]
|
|
963
|
key.Close()
|
|
963
|
key.Close()
|
|
964
|
if not isdir(homedir):
|
|
964
|
if not isdir(homedir):
|
|
965
|
e = ('Invalid "Personal" folder registry key '
|
|
965
|
e = ('Invalid "Personal" folder registry key '
|
|
966
|
'typically "My Documents".\n'
|
|
966
|
'typically "My Documents".\n'
|
|
967
|
'Value: %s\n'
|
|
967
|
'Value: %s\n'
|
|
968
|
'This is not a valid directory on your system.' %
|
|
968
|
'This is not a valid directory on your system.' %
|
|
969
|
homedir)
|
|
969
|
homedir)
|
|
970
|
raise HomeDirError(e)
|
|
970
|
raise HomeDirError(e)
|
|
971
|
return homedir
|
|
971
|
return homedir
|
|
972
|
except HomeDirError:
|
|
972
|
except HomeDirError:
|
|
973
|
raise
|
|
973
|
raise
|
|
974
|
except:
|
|
974
|
except:
|
|
975
|
return 'C:\\'
|
|
975
|
return 'C:\\'
|
|
976
|
elif os.name == 'dos':
|
|
976
|
elif os.name == 'dos':
|
|
977
|
# Desperate, may do absurd things in classic MacOS. May work under DOS.
|
|
977
|
# Desperate, may do absurd things in classic MacOS. May work under DOS.
|
|
978
|
return 'C:\\'
|
|
978
|
return 'C:\\'
|
|
979
|
else:
|
|
979
|
else:
|
|
980
|
raise HomeDirError,'support for your operating system not implemented.'
|
|
980
|
raise HomeDirError,'support for your operating system not implemented.'
|
|
981
|
|
|
981
|
|
|
982
|
|
|
982
|
|
|
983
|
def get_ipython_dir():
|
|
983
|
def get_ipython_dir():
|
|
984
|
"""Get the IPython directory for this platform and user.
|
|
984
|
"""Get the IPython directory for this platform and user.
|
|
985
|
|
|
985
|
|
|
986
|
This uses the logic in `get_home_dir` to find the home directory
|
|
986
|
This uses the logic in `get_home_dir` to find the home directory
|
|
987
|
and the adds either .ipython or _ipython to the end of the path.
|
|
987
|
and the adds either .ipython or _ipython to the end of the path.
|
|
988
|
"""
|
|
988
|
"""
|
|
989
|
if os.name == 'posix':
|
|
989
|
if os.name == 'posix':
|
|
990
|
ipdir_def = '.ipython'
|
|
990
|
ipdir_def = '.ipython'
|
|
991
|
else:
|
|
991
|
else:
|
|
992
|
ipdir_def = '_ipython'
|
|
992
|
ipdir_def = '_ipython'
|
|
993
|
home_dir = get_home_dir()
|
|
993
|
home_dir = get_home_dir()
|
|
994
|
ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
|
|
994
|
ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
|
|
995
|
os.path.join(home_dir,ipdir_def)))
|
|
995
|
os.path.join(home_dir,ipdir_def)))
|
|
996
|
return ipdir
|
|
996
|
return ipdir
|
|
997
|
|
|
997
|
|
|
|
|
|
998
|
def get_security_dir():
|
|
|
|
|
999
|
"""Get the IPython security directory.
|
|
|
|
|
1000
|
|
|
|
|
|
1001
|
This directory is the default location for all security related files,
|
|
|
|
|
1002
|
including SSL/TLS certificates and FURL files.
|
|
|
|
|
1003
|
|
|
|
|
|
1004
|
If the directory does not exist, it is created with 0700 permissions.
|
|
|
|
|
1005
|
If it exists, permissions are set to 0700.
|
|
|
|
|
1006
|
"""
|
|
|
|
|
1007
|
security_dir = os.path.join(get_ipython_dir(), 'security')
|
|
|
|
|
1008
|
if not os.path.isdir(security_dir):
|
|
|
|
|
1009
|
os.mkdir(security_dir, 0700)
|
|
|
|
|
1010
|
else:
|
|
|
|
|
1011
|
os.chmod(security_dir, 0700)
|
|
|
|
|
1012
|
return security_dir
|
|
|
|
|
1013
|
|
|
998
|
#****************************************************************************
|
|
1014
|
#****************************************************************************
|
|
999
|
# strings and text
|
|
1015
|
# strings and text
|
|
1000
|
|
|
1016
|
|
|
1001
|
class LSString(str):
|
|
1017
|
class LSString(str):
|
|
1002
|
"""String derivative with a special access attributes.
|
|
1018
|
"""String derivative with a special access attributes.
|
|
1003
|
|
|
1019
|
|
|
1004
|
These are normal strings, but with the special attributes:
|
|
1020
|
These are normal strings, but with the special attributes:
|
|
1005
|
|
|
1021
|
|
|
1006
|
.l (or .list) : value as list (split on newlines).
|
|
1022
|
.l (or .list) : value as list (split on newlines).
|
|
1007
|
.n (or .nlstr): original value (the string itself).
|
|
1023
|
.n (or .nlstr): original value (the string itself).
|
|
1008
|
.s (or .spstr): value as whitespace-separated string.
|
|
1024
|
.s (or .spstr): value as whitespace-separated string.
|
|
1009
|
.p (or .paths): list of path objects
|
|
1025
|
.p (or .paths): list of path objects
|
|
1010
|
|
|
1026
|
|
|
1011
|
Any values which require transformations are computed only once and
|
|
1027
|
Any values which require transformations are computed only once and
|
|
1012
|
cached.
|
|
1028
|
cached.
|
|
1013
|
|
|
1029
|
|
|
1014
|
Such strings are very useful to efficiently interact with the shell, which
|
|
1030
|
Such strings are very useful to efficiently interact with the shell, which
|
|
1015
|
typically only understands whitespace-separated options for commands."""
|
|
1031
|
typically only understands whitespace-separated options for commands."""
|
|
1016
|
|
|
1032
|
|
|
1017
|
def get_list(self):
|
|
1033
|
def get_list(self):
|
|
1018
|
try:
|
|
1034
|
try:
|
|
1019
|
return self.__list
|
|
1035
|
return self.__list
|
|
1020
|
except AttributeError:
|
|
1036
|
except AttributeError:
|
|
1021
|
self.__list = self.split('\n')
|
|
1037
|
self.__list = self.split('\n')
|
|
1022
|
return self.__list
|
|
1038
|
return self.__list
|
|
1023
|
|
|
1039
|
|
|
1024
|
l = list = property(get_list)
|
|
1040
|
l = list = property(get_list)
|
|
1025
|
|
|
1041
|
|
|
1026
|
def get_spstr(self):
|
|
1042
|
def get_spstr(self):
|
|
1027
|
try:
|
|
1043
|
try:
|
|
1028
|
return self.__spstr
|
|
1044
|
return self.__spstr
|
|
1029
|
except AttributeError:
|
|
1045
|
except AttributeError:
|
|
1030
|
self.__spstr = self.replace('\n',' ')
|
|
1046
|
self.__spstr = self.replace('\n',' ')
|
|
1031
|
return self.__spstr
|
|
1047
|
return self.__spstr
|
|
1032
|
|
|
1048
|
|
|
1033
|
s = spstr = property(get_spstr)
|
|
1049
|
s = spstr = property(get_spstr)
|
|
1034
|
|
|
1050
|
|
|
1035
|
def get_nlstr(self):
|
|
1051
|
def get_nlstr(self):
|
|
1036
|
return self
|
|
1052
|
return self
|
|
1037
|
|
|
1053
|
|
|
1038
|
n = nlstr = property(get_nlstr)
|
|
1054
|
n = nlstr = property(get_nlstr)
|
|
1039
|
|
|
1055
|
|
|
1040
|
def get_paths(self):
|
|
1056
|
def get_paths(self):
|
|
1041
|
try:
|
|
1057
|
try:
|
|
1042
|
return self.__paths
|
|
1058
|
return self.__paths
|
|
1043
|
except AttributeError:
|
|
1059
|
except AttributeError:
|
|
1044
|
self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
|
|
1060
|
self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
|
|
1045
|
return self.__paths
|
|
1061
|
return self.__paths
|
|
1046
|
|
|
1062
|
|
|
1047
|
p = paths = property(get_paths)
|
|
1063
|
p = paths = property(get_paths)
|
|
1048
|
|
|
1064
|
|
|
1049
|
def print_lsstring(arg):
|
|
1065
|
def print_lsstring(arg):
|
|
1050
|
""" Prettier (non-repr-like) and more informative printer for LSString """
|
|
1066
|
""" Prettier (non-repr-like) and more informative printer for LSString """
|
|
1051
|
print "LSString (.p, .n, .l, .s available). Value:"
|
|
1067
|
print "LSString (.p, .n, .l, .s available). Value:"
|
|
1052
|
print arg
|
|
1068
|
print arg
|
|
1053
|
|
|
1069
|
|
|
1054
|
print_lsstring = result_display.when_type(LSString)(print_lsstring)
|
|
1070
|
print_lsstring = result_display.when_type(LSString)(print_lsstring)
|
|
1055
|
|
|
1071
|
|
|
1056
|
#----------------------------------------------------------------------------
|
|
1072
|
#----------------------------------------------------------------------------
|
|
1057
|
class SList(list):
|
|
1073
|
class SList(list):
|
|
1058
|
"""List derivative with a special access attributes.
|
|
1074
|
"""List derivative with a special access attributes.
|
|
1059
|
|
|
1075
|
|
|
1060
|
These are normal lists, but with the special attributes:
|
|
1076
|
These are normal lists, but with the special attributes:
|
|
1061
|
|
|
1077
|
|
|
1062
|
.l (or .list) : value as list (the list itself).
|
|
1078
|
.l (or .list) : value as list (the list itself).
|
|
1063
|
.n (or .nlstr): value as a string, joined on newlines.
|
|
1079
|
.n (or .nlstr): value as a string, joined on newlines.
|
|
1064
|
.s (or .spstr): value as a string, joined on spaces.
|
|
1080
|
.s (or .spstr): value as a string, joined on spaces.
|
|
1065
|
.p (or .paths): list of path objects
|
|
1081
|
.p (or .paths): list of path objects
|
|
1066
|
|
|
1082
|
|
|
1067
|
Any values which require transformations are computed only once and
|
|
1083
|
Any values which require transformations are computed only once and
|
|
1068
|
cached."""
|
|
1084
|
cached."""
|
|
1069
|
|
|
1085
|
|
|
1070
|
def get_list(self):
|
|
1086
|
def get_list(self):
|
|
1071
|
return self
|
|
1087
|
return self
|
|
1072
|
|
|
1088
|
|
|
1073
|
l = list = property(get_list)
|
|
1089
|
l = list = property(get_list)
|
|
1074
|
|
|
1090
|
|
|
1075
|
def get_spstr(self):
|
|
1091
|
def get_spstr(self):
|
|
1076
|
try:
|
|
1092
|
try:
|
|
1077
|
return self.__spstr
|
|
1093
|
return self.__spstr
|
|
1078
|
except AttributeError:
|
|
1094
|
except AttributeError:
|
|
1079
|
self.__spstr = ' '.join(self)
|
|
1095
|
self.__spstr = ' '.join(self)
|
|
1080
|
return self.__spstr
|
|
1096
|
return self.__spstr
|
|
1081
|
|
|
1097
|
|
|
1082
|
s = spstr = property(get_spstr)
|
|
1098
|
s = spstr = property(get_spstr)
|
|
1083
|
|
|
1099
|
|
|
1084
|
def get_nlstr(self):
|
|
1100
|
def get_nlstr(self):
|
|
1085
|
try:
|
|
1101
|
try:
|
|
1086
|
return self.__nlstr
|
|
1102
|
return self.__nlstr
|
|
1087
|
except AttributeError:
|
|
1103
|
except AttributeError:
|
|
1088
|
self.__nlstr = '\n'.join(self)
|
|
1104
|
self.__nlstr = '\n'.join(self)
|
|
1089
|
return self.__nlstr
|
|
1105
|
return self.__nlstr
|
|
1090
|
|
|
1106
|
|
|
1091
|
n = nlstr = property(get_nlstr)
|
|
1107
|
n = nlstr = property(get_nlstr)
|
|
1092
|
|
|
1108
|
|
|
1093
|
def get_paths(self):
|
|
1109
|
def get_paths(self):
|
|
1094
|
try:
|
|
1110
|
try:
|
|
1095
|
return self.__paths
|
|
1111
|
return self.__paths
|
|
1096
|
except AttributeError:
|
|
1112
|
except AttributeError:
|
|
1097
|
self.__paths = [path(p) for p in self if os.path.exists(p)]
|
|
1113
|
self.__paths = [path(p) for p in self if os.path.exists(p)]
|
|
1098
|
return self.__paths
|
|
1114
|
return self.__paths
|
|
1099
|
|
|
1115
|
|
|
1100
|
p = paths = property(get_paths)
|
|
1116
|
p = paths = property(get_paths)
|
|
1101
|
|
|
1117
|
|
|
1102
|
def grep(self, pattern, prune = False, field = None):
|
|
1118
|
def grep(self, pattern, prune = False, field = None):
|
|
1103
|
""" Return all strings matching 'pattern' (a regex or callable)
|
|
1119
|
""" Return all strings matching 'pattern' (a regex or callable)
|
|
1104
|
|
|
1120
|
|
|
1105
|
This is case-insensitive. If prune is true, return all items
|
|
1121
|
This is case-insensitive. If prune is true, return all items
|
|
1106
|
NOT matching the pattern.
|
|
1122
|
NOT matching the pattern.
|
|
1107
|
|
|
1123
|
|
|
1108
|
If field is specified, the match must occur in the specified
|
|
1124
|
If field is specified, the match must occur in the specified
|
|
1109
|
whitespace-separated field.
|
|
1125
|
whitespace-separated field.
|
|
1110
|
|
|
1126
|
|
|
1111
|
Examples::
|
|
1127
|
Examples::
|
|
1112
|
|
|
1128
|
|
|
1113
|
a.grep( lambda x: x.startswith('C') )
|
|
1129
|
a.grep( lambda x: x.startswith('C') )
|
|
1114
|
a.grep('Cha.*log', prune=1)
|
|
1130
|
a.grep('Cha.*log', prune=1)
|
|
1115
|
a.grep('chm', field=-1)
|
|
1131
|
a.grep('chm', field=-1)
|
|
1116
|
"""
|
|
1132
|
"""
|
|
1117
|
|
|
1133
|
|
|
1118
|
def match_target(s):
|
|
1134
|
def match_target(s):
|
|
1119
|
if field is None:
|
|
1135
|
if field is None:
|
|
1120
|
return s
|
|
1136
|
return s
|
|
1121
|
parts = s.split()
|
|
1137
|
parts = s.split()
|
|
1122
|
try:
|
|
1138
|
try:
|
|
1123
|
tgt = parts[field]
|
|
1139
|
tgt = parts[field]
|
|
1124
|
return tgt
|
|
1140
|
return tgt
|
|
1125
|
except IndexError:
|
|
1141
|
except IndexError:
|
|
1126
|
return ""
|
|
1142
|
return ""
|
|
1127
|
|
|
1143
|
|
|
1128
|
if isinstance(pattern, basestring):
|
|
1144
|
if isinstance(pattern, basestring):
|
|
1129
|
pred = lambda x : re.search(pattern, x, re.IGNORECASE)
|
|
1145
|
pred = lambda x : re.search(pattern, x, re.IGNORECASE)
|
|
1130
|
else:
|
|
1146
|
else:
|
|
1131
|
pred = pattern
|
|
1147
|
pred = pattern
|
|
1132
|
if not prune:
|
|
1148
|
if not prune:
|
|
1133
|
return SList([el for el in self if pred(match_target(el))])
|
|
1149
|
return SList([el for el in self if pred(match_target(el))])
|
|
1134
|
else:
|
|
1150
|
else:
|
|
1135
|
return SList([el for el in self if not pred(match_target(el))])
|
|
1151
|
return SList([el for el in self if not pred(match_target(el))])
|
|
1136
|
def fields(self, *fields):
|
|
1152
|
def fields(self, *fields):
|
|
1137
|
""" Collect whitespace-separated fields from string list
|
|
1153
|
""" Collect whitespace-separated fields from string list
|
|
1138
|
|
|
1154
|
|
|
1139
|
Allows quick awk-like usage of string lists.
|
|
1155
|
Allows quick awk-like usage of string lists.
|
|
1140
|
|
|
1156
|
|
|
1141
|
Example data (in var a, created by 'a = !ls -l')::
|
|
1157
|
Example data (in var a, created by 'a = !ls -l')::
|
|
1142
|
-rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
|
|
1158
|
-rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
|
|
1143
|
drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
|
|
1159
|
drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
|
|
1144
|
|
|
1160
|
|
|
1145
|
a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
|
|
1161
|
a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
|
|
1146
|
a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
|
|
1162
|
a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
|
|
1147
|
(note the joining by space).
|
|
1163
|
(note the joining by space).
|
|
1148
|
a.fields(-1) is ['ChangeLog', 'IPython']
|
|
1164
|
a.fields(-1) is ['ChangeLog', 'IPython']
|
|
1149
|
|
|
1165
|
|
|
1150
|
IndexErrors are ignored.
|
|
1166
|
IndexErrors are ignored.
|
|
1151
|
|
|
1167
|
|
|
1152
|
Without args, fields() just split()'s the strings.
|
|
1168
|
Without args, fields() just split()'s the strings.
|
|
1153
|
"""
|
|
1169
|
"""
|
|
1154
|
if len(fields) == 0:
|
|
1170
|
if len(fields) == 0:
|
|
1155
|
return [el.split() for el in self]
|
|
1171
|
return [el.split() for el in self]
|
|
1156
|
|
|
1172
|
|
|
1157
|
res = SList()
|
|
1173
|
res = SList()
|
|
1158
|
for el in [f.split() for f in self]:
|
|
1174
|
for el in [f.split() for f in self]:
|
|
1159
|
lineparts = []
|
|
1175
|
lineparts = []
|
|
1160
|
|
|
1176
|
|
|
1161
|
for fd in fields:
|
|
1177
|
for fd in fields:
|
|
1162
|
try:
|
|
1178
|
try:
|
|
1163
|
lineparts.append(el[fd])
|
|
1179
|
lineparts.append(el[fd])
|
|
1164
|
except IndexError:
|
|
1180
|
except IndexError:
|
|
1165
|
pass
|
|
1181
|
pass
|
|
1166
|
if lineparts:
|
|
1182
|
if lineparts:
|
|
1167
|
res.append(" ".join(lineparts))
|
|
1183
|
res.append(" ".join(lineparts))
|
|
1168
|
|
|
1184
|
|
|
1169
|
return res
|
|
1185
|
return res
|
|
1170
|
def sort(self,field= None, nums = False):
|
|
1186
|
def sort(self,field= None, nums = False):
|
|
1171
|
""" sort by specified fields (see fields())
|
|
1187
|
""" sort by specified fields (see fields())
|
|
1172
|
|
|
1188
|
|
|
1173
|
Example::
|
|
1189
|
Example::
|
|
1174
|
a.sort(1, nums = True)
|
|
1190
|
a.sort(1, nums = True)
|
|
1175
|
|
|
1191
|
|
|
1176
|
Sorts a by second field, in numerical order (so that 21 > 3)
|
|
1192
|
Sorts a by second field, in numerical order (so that 21 > 3)
|
|
1177
|
|
|
1193
|
|
|
1178
|
"""
|
|
1194
|
"""
|
|
1179
|
|
|
1195
|
|
|
1180
|
#decorate, sort, undecorate
|
|
1196
|
#decorate, sort, undecorate
|
|
1181
|
if field is not None:
|
|
1197
|
if field is not None:
|
|
1182
|
dsu = [[SList([line]).fields(field), line] for line in self]
|
|
1198
|
dsu = [[SList([line]).fields(field), line] for line in self]
|
|
1183
|
else:
|
|
1199
|
else:
|
|
1184
|
dsu = [[line, line] for line in self]
|
|
1200
|
dsu = [[line, line] for line in self]
|
|
1185
|
if nums:
|
|
1201
|
if nums:
|
|
1186
|
for i in range(len(dsu)):
|
|
1202
|
for i in range(len(dsu)):
|
|
1187
|
numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
|
|
1203
|
numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
|
|
1188
|
try:
|
|
1204
|
try:
|
|
1189
|
n = int(numstr)
|
|
1205
|
n = int(numstr)
|
|
1190
|
except ValueError:
|
|
1206
|
except ValueError:
|
|
1191
|
n = 0;
|
|
1207
|
n = 0;
|
|
1192
|
dsu[i][0] = n
|
|
1208
|
dsu[i][0] = n
|
|
1193
|
|
|
1209
|
|
|
1194
|
|
|
1210
|
|
|
1195
|
dsu.sort()
|
|
1211
|
dsu.sort()
|
|
1196
|
return SList([t[1] for t in dsu])
|
|
1212
|
return SList([t[1] for t in dsu])
|
|
1197
|
|
|
1213
|
|
|
1198
|
def print_slist(arg):
|
|
1214
|
def print_slist(arg):
|
|
1199
|
""" Prettier (non-repr-like) and more informative printer for SList """
|
|
1215
|
""" Prettier (non-repr-like) and more informative printer for SList """
|
|
1200
|
print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
|
|
1216
|
print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
|
|
1201
|
if hasattr(arg, 'hideonce') and arg.hideonce:
|
|
1217
|
if hasattr(arg, 'hideonce') and arg.hideonce:
|
|
1202
|
arg.hideonce = False
|
|
1218
|
arg.hideonce = False
|
|
1203
|
return
|
|
1219
|
return
|
|
1204
|
|
|
1220
|
|
|
1205
|
nlprint(arg)
|
|
1221
|
nlprint(arg)
|
|
1206
|
|
|
1222
|
|
|
1207
|
print_slist = result_display.when_type(SList)(print_slist)
|
|
1223
|
print_slist = result_display.when_type(SList)(print_slist)
|
|
1208
|
|
|
1224
|
|
|
1209
|
|
|
1225
|
|
|
1210
|
|
|
1226
|
|
|
1211
|
#----------------------------------------------------------------------------
|
|
1227
|
#----------------------------------------------------------------------------
|
|
1212
|
def esc_quotes(strng):
|
|
1228
|
def esc_quotes(strng):
|
|
1213
|
"""Return the input string with single and double quotes escaped out"""
|
|
1229
|
"""Return the input string with single and double quotes escaped out"""
|
|
1214
|
|
|
1230
|
|
|
1215
|
return strng.replace('"','\\"').replace("'","\\'")
|
|
1231
|
return strng.replace('"','\\"').replace("'","\\'")
|
|
1216
|
|
|
1232
|
|
|
1217
|
#----------------------------------------------------------------------------
|
|
1233
|
#----------------------------------------------------------------------------
|
|
1218
|
def make_quoted_expr(s):
|
|
1234
|
def make_quoted_expr(s):
|
|
1219
|
"""Return string s in appropriate quotes, using raw string if possible.
|
|
1235
|
"""Return string s in appropriate quotes, using raw string if possible.
|
|
1220
|
|
|
1236
|
|
|
1221
|
Effectively this turns string: cd \ao\ao\
|
|
1237
|
Effectively this turns string: cd \ao\ao\
|
|
1222
|
to: r"cd \ao\ao\_"[:-1]
|
|
1238
|
to: r"cd \ao\ao\_"[:-1]
|
|
1223
|
|
|
1239
|
|
|
1224
|
Note the use of raw string and padding at the end to allow trailing backslash.
|
|
1240
|
Note the use of raw string and padding at the end to allow trailing backslash.
|
|
1225
|
|
|
1241
|
|
|
1226
|
"""
|
|
1242
|
"""
|
|
1227
|
|
|
1243
|
|
|
1228
|
tail = ''
|
|
1244
|
tail = ''
|
|
1229
|
tailpadding = ''
|
|
1245
|
tailpadding = ''
|
|
1230
|
raw = ''
|
|
1246
|
raw = ''
|
|
1231
|
if "\\" in s:
|
|
1247
|
if "\\" in s:
|
|
1232
|
raw = 'r'
|
|
1248
|
raw = 'r'
|
|
1233
|
if s.endswith('\\'):
|
|
1249
|
if s.endswith('\\'):
|
|
1234
|
tail = '[:-1]'
|
|
1250
|
tail = '[:-1]'
|
|
1235
|
tailpadding = '_'
|
|
1251
|
tailpadding = '_'
|
|
1236
|
if '"' not in s:
|
|
1252
|
if '"' not in s:
|
|
1237
|
quote = '"'
|
|
1253
|
quote = '"'
|
|
1238
|
elif "'" not in s:
|
|
1254
|
elif "'" not in s:
|
|
1239
|
quote = "'"
|
|
1255
|
quote = "'"
|
|
1240
|
elif '"""' not in s and not s.endswith('"'):
|
|
1256
|
elif '"""' not in s and not s.endswith('"'):
|
|
1241
|
quote = '"""'
|
|
1257
|
quote = '"""'
|
|
1242
|
elif "'''" not in s and not s.endswith("'"):
|
|
1258
|
elif "'''" not in s and not s.endswith("'"):
|
|
1243
|
quote = "'''"
|
|
1259
|
quote = "'''"
|
|
1244
|
else:
|
|
1260
|
else:
|
|
1245
|
# give up, backslash-escaped string will do
|
|
1261
|
# give up, backslash-escaped string will do
|
|
1246
|
return '"%s"' % esc_quotes(s)
|
|
1262
|
return '"%s"' % esc_quotes(s)
|
|
1247
|
res = raw + quote + s + tailpadding + quote + tail
|
|
1263
|
res = raw + quote + s + tailpadding + quote + tail
|
|
1248
|
return res
|
|
1264
|
return res
|
|
1249
|
|
|
1265
|
|
|
1250
|
|
|
1266
|
|
|
1251
|
#----------------------------------------------------------------------------
|
|
1267
|
#----------------------------------------------------------------------------
|
|
1252
|
def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
|
|
1268
|
def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
|
|
1253
|
"""Take multiple lines of input.
|
|
1269
|
"""Take multiple lines of input.
|
|
1254
|
|
|
1270
|
|
|
1255
|
A list with each line of input as a separate element is returned when a
|
|
1271
|
A list with each line of input as a separate element is returned when a
|
|
1256
|
termination string is entered (defaults to a single '.'). Input can also
|
|
1272
|
termination string is entered (defaults to a single '.'). Input can also
|
|
1257
|
terminate via EOF (^D in Unix, ^Z-RET in Windows).
|
|
1273
|
terminate via EOF (^D in Unix, ^Z-RET in Windows).
|
|
1258
|
|
|
1274
|
|
|
1259
|
Lines of input which end in \\ are joined into single entries (and a
|
|
1275
|
Lines of input which end in \\ are joined into single entries (and a
|
|
1260
|
secondary continuation prompt is issued as long as the user terminates
|
|
1276
|
secondary continuation prompt is issued as long as the user terminates
|
|
1261
|
lines with \\). This allows entering very long strings which are still
|
|
1277
|
lines with \\). This allows entering very long strings which are still
|
|
1262
|
meant to be treated as single entities.
|
|
1278
|
meant to be treated as single entities.
|
|
1263
|
"""
|
|
1279
|
"""
|
|
1264
|
|
|
1280
|
|
|
1265
|
try:
|
|
1281
|
try:
|
|
1266
|
if header:
|
|
1282
|
if header:
|
|
1267
|
header += '\n'
|
|
1283
|
header += '\n'
|
|
1268
|
lines = [raw_input(header + ps1)]
|
|
1284
|
lines = [raw_input(header + ps1)]
|
|
1269
|
except EOFError:
|
|
1285
|
except EOFError:
|
|
1270
|
return []
|
|
1286
|
return []
|
|
1271
|
terminate = [terminate_str]
|
|
1287
|
terminate = [terminate_str]
|
|
1272
|
try:
|
|
1288
|
try:
|
|
1273
|
while lines[-1:] != terminate:
|
|
1289
|
while lines[-1:] != terminate:
|
|
1274
|
new_line = raw_input(ps1)
|
|
1290
|
new_line = raw_input(ps1)
|
|
1275
|
while new_line.endswith('\\'):
|
|
1291
|
while new_line.endswith('\\'):
|
|
1276
|
new_line = new_line[:-1] + raw_input(ps2)
|
|
1292
|
new_line = new_line[:-1] + raw_input(ps2)
|
|
1277
|
lines.append(new_line)
|
|
1293
|
lines.append(new_line)
|
|
1278
|
|
|
1294
|
|
|
1279
|
return lines[:-1] # don't return the termination command
|
|
1295
|
return lines[:-1] # don't return the termination command
|
|
1280
|
except EOFError:
|
|
1296
|
except EOFError:
|
|
1281
|
print
|
|
1297
|
print
|
|
1282
|
return lines
|
|
1298
|
return lines
|
|
1283
|
|
|
1299
|
|
|
1284
|
#----------------------------------------------------------------------------
|
|
1300
|
#----------------------------------------------------------------------------
|
|
1285
|
def raw_input_ext(prompt='', ps2='... '):
|
|
1301
|
def raw_input_ext(prompt='', ps2='... '):
|
|
1286
|
"""Similar to raw_input(), but accepts extended lines if input ends with \\."""
|
|
1302
|
"""Similar to raw_input(), but accepts extended lines if input ends with \\."""
|
|
1287
|
|
|
1303
|
|
|
1288
|
line = raw_input(prompt)
|
|
1304
|
line = raw_input(prompt)
|
|
1289
|
while line.endswith('\\'):
|
|
1305
|
while line.endswith('\\'):
|
|
1290
|
line = line[:-1] + raw_input(ps2)
|
|
1306
|
line = line[:-1] + raw_input(ps2)
|
|
1291
|
return line
|
|
1307
|
return line
|
|
1292
|
|
|
1308
|
|
|
1293
|
#----------------------------------------------------------------------------
|
|
1309
|
#----------------------------------------------------------------------------
|
|
1294
|
def ask_yes_no(prompt,default=None):
|
|
1310
|
def ask_yes_no(prompt,default=None):
|
|
1295
|
"""Asks a question and returns a boolean (y/n) answer.
|
|
1311
|
"""Asks a question and returns a boolean (y/n) answer.
|
|
1296
|
|
|
1312
|
|
|
1297
|
If default is given (one of 'y','n'), it is used if the user input is
|
|
1313
|
If default is given (one of 'y','n'), it is used if the user input is
|
|
1298
|
empty. Otherwise the question is repeated until an answer is given.
|
|
1314
|
empty. Otherwise the question is repeated until an answer is given.
|
|
1299
|
|
|
1315
|
|
|
1300
|
An EOF is treated as the default answer. If there is no default, an
|
|
1316
|
An EOF is treated as the default answer. If there is no default, an
|
|
1301
|
exception is raised to prevent infinite loops.
|
|
1317
|
exception is raised to prevent infinite loops.
|
|
1302
|
|
|
1318
|
|
|
1303
|
Valid answers are: y/yes/n/no (match is not case sensitive)."""
|
|
1319
|
Valid answers are: y/yes/n/no (match is not case sensitive)."""
|
|
1304
|
|
|
1320
|
|
|
1305
|
answers = {'y':True,'n':False,'yes':True,'no':False}
|
|
1321
|
answers = {'y':True,'n':False,'yes':True,'no':False}
|
|
1306
|
ans = None
|
|
1322
|
ans = None
|
|
1307
|
while ans not in answers.keys():
|
|
1323
|
while ans not in answers.keys():
|
|
1308
|
try:
|
|
1324
|
try:
|
|
1309
|
ans = raw_input(prompt+' ').lower()
|
|
1325
|
ans = raw_input(prompt+' ').lower()
|
|
1310
|
if not ans: # response was an empty string
|
|
1326
|
if not ans: # response was an empty string
|
|
1311
|
ans = default
|
|
1327
|
ans = default
|
|
1312
|
except KeyboardInterrupt:
|
|
1328
|
except KeyboardInterrupt:
|
|
1313
|
pass
|
|
1329
|
pass
|
|
1314
|
except EOFError:
|
|
1330
|
except EOFError:
|
|
1315
|
if default in answers.keys():
|
|
1331
|
if default in answers.keys():
|
|
1316
|
ans = default
|
|
1332
|
ans = default
|
|
1317
|
print
|
|
1333
|
print
|
|
1318
|
else:
|
|
1334
|
else:
|
|
1319
|
raise
|
|
1335
|
raise
|
|
1320
|
|
|
1336
|
|
|
1321
|
return answers[ans]
|
|
1337
|
return answers[ans]
|
|
1322
|
|
|
1338
|
|
|
1323
|
#----------------------------------------------------------------------------
|
|
1339
|
#----------------------------------------------------------------------------
|
|
1324
|
def marquee(txt='',width=78,mark='*'):
|
|
1340
|
def marquee(txt='',width=78,mark='*'):
|
|
1325
|
"""Return the input string centered in a 'marquee'."""
|
|
1341
|
"""Return the input string centered in a 'marquee'."""
|
|
1326
|
if not txt:
|
|
1342
|
if not txt:
|
|
1327
|
return (mark*width)[:width]
|
|
1343
|
return (mark*width)[:width]
|
|
1328
|
nmark = (width-len(txt)-2)/len(mark)/2
|
|
1344
|
nmark = (width-len(txt)-2)/len(mark)/2
|
|
1329
|
if nmark < 0: nmark =0
|
|
1345
|
if nmark < 0: nmark =0
|
|
1330
|
marks = mark*nmark
|
|
1346
|
marks = mark*nmark
|
|
1331
|
return '%s %s %s' % (marks,txt,marks)
|
|
1347
|
return '%s %s %s' % (marks,txt,marks)
|
|
1332
|
|
|
1348
|
|
|
1333
|
#----------------------------------------------------------------------------
|
|
1349
|
#----------------------------------------------------------------------------
|
|
1334
|
class EvalDict:
|
|
1350
|
class EvalDict:
|
|
1335
|
"""
|
|
1351
|
"""
|
|
1336
|
Emulate a dict which evaluates its contents in the caller's frame.
|
|
1352
|
Emulate a dict which evaluates its contents in the caller's frame.
|
|
1337
|
|
|
1353
|
|
|
1338
|
Usage:
|
|
1354
|
Usage:
|
|
1339
|
>>> number = 19
|
|
1355
|
>>> number = 19
|
|
1340
|
|
|
1356
|
|
|
1341
|
>>> text = "python"
|
|
1357
|
>>> text = "python"
|
|
1342
|
|
|
1358
|
|
|
1343
|
>>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
|
|
1359
|
>>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
|
|
1344
|
Python 2.1 rules!
|
|
1360
|
Python 2.1 rules!
|
|
1345
|
"""
|
|
1361
|
"""
|
|
1346
|
|
|
1362
|
|
|
1347
|
# This version is due to sismex01@hebmex.com on c.l.py, and is basically a
|
|
1363
|
# This version is due to sismex01@hebmex.com on c.l.py, and is basically a
|
|
1348
|
# modified (shorter) version of:
|
|
1364
|
# modified (shorter) version of:
|
|
1349
|
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
|
|
1365
|
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
|
|
1350
|
# Skip Montanaro (skip@pobox.com).
|
|
1366
|
# Skip Montanaro (skip@pobox.com).
|
|
1351
|
|
|
1367
|
|
|
1352
|
def __getitem__(self, name):
|
|
1368
|
def __getitem__(self, name):
|
|
1353
|
frame = sys._getframe(1)
|
|
1369
|
frame = sys._getframe(1)
|
|
1354
|
return eval(name, frame.f_globals, frame.f_locals)
|
|
1370
|
return eval(name, frame.f_globals, frame.f_locals)
|
|
1355
|
|
|
1371
|
|
|
1356
|
EvalString = EvalDict # for backwards compatibility
|
|
1372
|
EvalString = EvalDict # for backwards compatibility
|
|
1357
|
#----------------------------------------------------------------------------
|
|
1373
|
#----------------------------------------------------------------------------
|
|
1358
|
def qw(words,flat=0,sep=None,maxsplit=-1):
|
|
1374
|
def qw(words,flat=0,sep=None,maxsplit=-1):
|
|
1359
|
"""Similar to Perl's qw() operator, but with some more options.
|
|
1375
|
"""Similar to Perl's qw() operator, but with some more options.
|
|
1360
|
|
|
1376
|
|
|
1361
|
qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
|
|
1377
|
qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
|
|
1362
|
|
|
1378
|
|
|
1363
|
words can also be a list itself, and with flat=1, the output will be
|
|
1379
|
words can also be a list itself, and with flat=1, the output will be
|
|
1364
|
recursively flattened.
|
|
1380
|
recursively flattened.
|
|
1365
|
|
|
1381
|
|
|
1366
|
Examples:
|
|
1382
|
Examples:
|
|
1367
|
|
|
1383
|
|
|
1368
|
>>> qw('1 2')
|
|
1384
|
>>> qw('1 2')
|
|
1369
|
['1', '2']
|
|
1385
|
['1', '2']
|
|
1370
|
|
|
1386
|
|
|
1371
|
>>> qw(['a b','1 2',['m n','p q']])
|
|
1387
|
>>> qw(['a b','1 2',['m n','p q']])
|
|
1372
|
[['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
|
|
1388
|
[['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
|
|
1373
|
|
|
1389
|
|
|
1374
|
>>> qw(['a b','1 2',['m n','p q']],flat=1)
|
|
1390
|
>>> qw(['a b','1 2',['m n','p q']],flat=1)
|
|
1375
|
['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
|
|
1391
|
['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
|
|
1376
|
"""
|
|
1392
|
"""
|
|
1377
|
|
|
1393
|
|
|
1378
|
if type(words) in StringTypes:
|
|
1394
|
if type(words) in StringTypes:
|
|
1379
|
return [word.strip() for word in words.split(sep,maxsplit)
|
|
1395
|
return [word.strip() for word in words.split(sep,maxsplit)
|
|
1380
|
if word and not word.isspace() ]
|
|
1396
|
if word and not word.isspace() ]
|
|
1381
|
if flat:
|
|
1397
|
if flat:
|
|
1382
|
return flatten(map(qw,words,[1]*len(words)))
|
|
1398
|
return flatten(map(qw,words,[1]*len(words)))
|
|
1383
|
return map(qw,words)
|
|
1399
|
return map(qw,words)
|
|
1384
|
|
|
1400
|
|
|
1385
|
#----------------------------------------------------------------------------
|
|
1401
|
#----------------------------------------------------------------------------
|
|
1386
|
def qwflat(words,sep=None,maxsplit=-1):
|
|
1402
|
def qwflat(words,sep=None,maxsplit=-1):
|
|
1387
|
"""Calls qw(words) in flat mode. It's just a convenient shorthand."""
|
|
1403
|
"""Calls qw(words) in flat mode. It's just a convenient shorthand."""
|
|
1388
|
return qw(words,1,sep,maxsplit)
|
|
1404
|
return qw(words,1,sep,maxsplit)
|
|
1389
|
|
|
1405
|
|
|
1390
|
#----------------------------------------------------------------------------
|
|
1406
|
#----------------------------------------------------------------------------
|
|
1391
|
def qw_lol(indata):
|
|
1407
|
def qw_lol(indata):
|
|
1392
|
"""qw_lol('a b') -> [['a','b']],
|
|
1408
|
"""qw_lol('a b') -> [['a','b']],
|
|
1393
|
otherwise it's just a call to qw().
|
|
1409
|
otherwise it's just a call to qw().
|
|
1394
|
|
|
1410
|
|
|
1395
|
We need this to make sure the modules_some keys *always* end up as a
|
|
1411
|
We need this to make sure the modules_some keys *always* end up as a
|
|
1396
|
list of lists."""
|
|
1412
|
list of lists."""
|
|
1397
|
|
|
1413
|
|
|
1398
|
if type(indata) in StringTypes:
|
|
1414
|
if type(indata) in StringTypes:
|
|
1399
|
return [qw(indata)]
|
|
1415
|
return [qw(indata)]
|
|
1400
|
else:
|
|
1416
|
else:
|
|
1401
|
return qw(indata)
|
|
1417
|
return qw(indata)
|
|
1402
|
|
|
1418
|
|
|
1403
|
#-----------------------------------------------------------------------------
|
|
1419
|
#-----------------------------------------------------------------------------
|
|
1404
|
def list_strings(arg):
|
|
1420
|
def list_strings(arg):
|
|
1405
|
"""Always return a list of strings, given a string or list of strings
|
|
1421
|
"""Always return a list of strings, given a string or list of strings
|
|
1406
|
as input."""
|
|
1422
|
as input."""
|
|
1407
|
|
|
1423
|
|
|
1408
|
if type(arg) in StringTypes: return [arg]
|
|
1424
|
if type(arg) in StringTypes: return [arg]
|
|
1409
|
else: return arg
|
|
1425
|
else: return arg
|
|
1410
|
|
|
1426
|
|
|
1411
|
#----------------------------------------------------------------------------
|
|
1427
|
#----------------------------------------------------------------------------
|
|
1412
|
def grep(pat,list,case=1):
|
|
1428
|
def grep(pat,list,case=1):
|
|
1413
|
"""Simple minded grep-like function.
|
|
1429
|
"""Simple minded grep-like function.
|
|
1414
|
grep(pat,list) returns occurrences of pat in list, None on failure.
|
|
1430
|
grep(pat,list) returns occurrences of pat in list, None on failure.
|
|
1415
|
|
|
1431
|
|
|
1416
|
It only does simple string matching, with no support for regexps. Use the
|
|
1432
|
It only does simple string matching, with no support for regexps. Use the
|
|
1417
|
option case=0 for case-insensitive matching."""
|
|
1433
|
option case=0 for case-insensitive matching."""
|
|
1418
|
|
|
1434
|
|
|
1419
|
# This is pretty crude. At least it should implement copying only references
|
|
1435
|
# This is pretty crude. At least it should implement copying only references
|
|
1420
|
# to the original data in case it's big. Now it copies the data for output.
|
|
1436
|
# to the original data in case it's big. Now it copies the data for output.
|
|
1421
|
out=[]
|
|
1437
|
out=[]
|
|
1422
|
if case:
|
|
1438
|
if case:
|
|
1423
|
for term in list:
|
|
1439
|
for term in list:
|
|
1424
|
if term.find(pat)>-1: out.append(term)
|
|
1440
|
if term.find(pat)>-1: out.append(term)
|
|
1425
|
else:
|
|
1441
|
else:
|
|
1426
|
lpat=pat.lower()
|
|
1442
|
lpat=pat.lower()
|
|
1427
|
for term in list:
|
|
1443
|
for term in list:
|
|
1428
|
if term.lower().find(lpat)>-1: out.append(term)
|
|
1444
|
if term.lower().find(lpat)>-1: out.append(term)
|
|
1429
|
|
|
1445
|
|
|
1430
|
if len(out): return out
|
|
1446
|
if len(out): return out
|
|
1431
|
else: return None
|
|
1447
|
else: return None
|
|
1432
|
|
|
1448
|
|
|
1433
|
#----------------------------------------------------------------------------
|
|
1449
|
#----------------------------------------------------------------------------
|
|
1434
|
def dgrep(pat,*opts):
|
|
1450
|
def dgrep(pat,*opts):
|
|
1435
|
"""Return grep() on dir()+dir(__builtins__).
|
|
1451
|
"""Return grep() on dir()+dir(__builtins__).
|
|
1436
|
|
|
1452
|
|
|
1437
|
A very common use of grep() when working interactively."""
|
|
1453
|
A very common use of grep() when working interactively."""
|
|
1438
|
|
|
1454
|
|
|
1439
|
return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
|
|
1455
|
return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
|
|
1440
|
|
|
1456
|
|
|
1441
|
#----------------------------------------------------------------------------
|
|
1457
|
#----------------------------------------------------------------------------
|
|
1442
|
def idgrep(pat):
|
|
1458
|
def idgrep(pat):
|
|
1443
|
"""Case-insensitive dgrep()"""
|
|
1459
|
"""Case-insensitive dgrep()"""
|
|
1444
|
|
|
1460
|
|
|
1445
|
return dgrep(pat,0)
|
|
1461
|
return dgrep(pat,0)
|
|
1446
|
|
|
1462
|
|
|
1447
|
#----------------------------------------------------------------------------
|
|
1463
|
#----------------------------------------------------------------------------
|
|
1448
|
def igrep(pat,list):
|
|
1464
|
def igrep(pat,list):
|
|
1449
|
"""Synonym for case-insensitive grep."""
|
|
1465
|
"""Synonym for case-insensitive grep."""
|
|
1450
|
|
|
1466
|
|
|
1451
|
return grep(pat,list,case=0)
|
|
1467
|
return grep(pat,list,case=0)
|
|
1452
|
|
|
1468
|
|
|
1453
|
#----------------------------------------------------------------------------
|
|
1469
|
#----------------------------------------------------------------------------
|
|
1454
|
def indent(str,nspaces=4,ntabs=0):
|
|
1470
|
def indent(str,nspaces=4,ntabs=0):
|
|
1455
|
"""Indent a string a given number of spaces or tabstops.
|
|
1471
|
"""Indent a string a given number of spaces or tabstops.
|
|
1456
|
|
|
1472
|
|
|
1457
|
indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
|
|
1473
|
indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
|
|
1458
|
"""
|
|
1474
|
"""
|
|
1459
|
if str is None:
|
|
1475
|
if str is None:
|
|
1460
|
return
|
|
1476
|
return
|
|
1461
|
ind = '\t'*ntabs+' '*nspaces
|
|
1477
|
ind = '\t'*ntabs+' '*nspaces
|
|
1462
|
outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
|
|
1478
|
outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
|
|
1463
|
if outstr.endswith(os.linesep+ind):
|
|
1479
|
if outstr.endswith(os.linesep+ind):
|
|
1464
|
return outstr[:-len(ind)]
|
|
1480
|
return outstr[:-len(ind)]
|
|
1465
|
else:
|
|
1481
|
else:
|
|
1466
|
return outstr
|
|
1482
|
return outstr
|
|
1467
|
|
|
1483
|
|
|
1468
|
#-----------------------------------------------------------------------------
|
|
1484
|
#-----------------------------------------------------------------------------
|
|
1469
|
def native_line_ends(filename,backup=1):
|
|
1485
|
def native_line_ends(filename,backup=1):
|
|
1470
|
"""Convert (in-place) a file to line-ends native to the current OS.
|
|
1486
|
"""Convert (in-place) a file to line-ends native to the current OS.
|
|
1471
|
|
|
1487
|
|
|
1472
|
If the optional backup argument is given as false, no backup of the
|
|
1488
|
If the optional backup argument is given as false, no backup of the
|
|
1473
|
original file is left. """
|
|
1489
|
original file is left. """
|
|
1474
|
|
|
1490
|
|
|
1475
|
backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
|
|
1491
|
backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
|
|
1476
|
|
|
1492
|
|
|
1477
|
bak_filename = filename + backup_suffixes[os.name]
|
|
1493
|
bak_filename = filename + backup_suffixes[os.name]
|
|
1478
|
|
|
1494
|
|
|
1479
|
original = open(filename).read()
|
|
1495
|
original = open(filename).read()
|
|
1480
|
shutil.copy2(filename,bak_filename)
|
|
1496
|
shutil.copy2(filename,bak_filename)
|
|
1481
|
try:
|
|
1497
|
try:
|
|
1482
|
new = open(filename,'wb')
|
|
1498
|
new = open(filename,'wb')
|
|
1483
|
new.write(os.linesep.join(original.splitlines()))
|
|
1499
|
new.write(os.linesep.join(original.splitlines()))
|
|
1484
|
new.write(os.linesep) # ALWAYS put an eol at the end of the file
|
|
1500
|
new.write(os.linesep) # ALWAYS put an eol at the end of the file
|
|
1485
|
new.close()
|
|
1501
|
new.close()
|
|
1486
|
except:
|
|
1502
|
except:
|
|
1487
|
os.rename(bak_filename,filename)
|
|
1503
|
os.rename(bak_filename,filename)
|
|
1488
|
if not backup:
|
|
1504
|
if not backup:
|
|
1489
|
try:
|
|
1505
|
try:
|
|
1490
|
os.remove(bak_filename)
|
|
1506
|
os.remove(bak_filename)
|
|
1491
|
except:
|
|
1507
|
except:
|
|
1492
|
pass
|
|
1508
|
pass
|
|
1493
|
|
|
1509
|
|
|
1494
|
#----------------------------------------------------------------------------
|
|
1510
|
#----------------------------------------------------------------------------
|
|
1495
|
def get_pager_cmd(pager_cmd = None):
|
|
1511
|
def get_pager_cmd(pager_cmd = None):
|
|
1496
|
"""Return a pager command.
|
|
1512
|
"""Return a pager command.
|
|
1497
|
|
|
1513
|
|
|
1498
|
Makes some attempts at finding an OS-correct one."""
|
|
1514
|
Makes some attempts at finding an OS-correct one."""
|
|
1499
|
|
|
1515
|
|
|
1500
|
if os.name == 'posix':
|
|
1516
|
if os.name == 'posix':
|
|
1501
|
default_pager_cmd = 'less -r' # -r for color control sequences
|
|
1517
|
default_pager_cmd = 'less -r' # -r for color control sequences
|
|
1502
|
elif os.name in ['nt','dos']:
|
|
1518
|
elif os.name in ['nt','dos']:
|
|
1503
|
default_pager_cmd = 'type'
|
|
1519
|
default_pager_cmd = 'type'
|
|
1504
|
|
|
1520
|
|
|
1505
|
if pager_cmd is None:
|
|
1521
|
if pager_cmd is None:
|
|
1506
|
try:
|
|
1522
|
try:
|
|
1507
|
pager_cmd = os.environ['PAGER']
|
|
1523
|
pager_cmd = os.environ['PAGER']
|
|
1508
|
except:
|
|
1524
|
except:
|
|
1509
|
pager_cmd = default_pager_cmd
|
|
1525
|
pager_cmd = default_pager_cmd
|
|
1510
|
return pager_cmd
|
|
1526
|
return pager_cmd
|
|
1511
|
|
|
1527
|
|
|
1512
|
#-----------------------------------------------------------------------------
|
|
1528
|
#-----------------------------------------------------------------------------
|
|
1513
|
def get_pager_start(pager,start):
|
|
1529
|
def get_pager_start(pager,start):
|
|
1514
|
"""Return the string for paging files with an offset.
|
|
1530
|
"""Return the string for paging files with an offset.
|
|
1515
|
|
|
1531
|
|
|
1516
|
This is the '+N' argument which less and more (under Unix) accept.
|
|
1532
|
This is the '+N' argument which less and more (under Unix) accept.
|
|
1517
|
"""
|
|
1533
|
"""
|
|
1518
|
|
|
1534
|
|
|
1519
|
if pager in ['less','more']:
|
|
1535
|
if pager in ['less','more']:
|
|
1520
|
if start:
|
|
1536
|
if start:
|
|
1521
|
start_string = '+' + str(start)
|
|
1537
|
start_string = '+' + str(start)
|
|
1522
|
else:
|
|
1538
|
else:
|
|
1523
|
start_string = ''
|
|
1539
|
start_string = ''
|
|
1524
|
else:
|
|
1540
|
else:
|
|
1525
|
start_string = ''
|
|
1541
|
start_string = ''
|
|
1526
|
return start_string
|
|
1542
|
return start_string
|
|
1527
|
|
|
1543
|
|
|
1528
|
#----------------------------------------------------------------------------
|
|
1544
|
#----------------------------------------------------------------------------
|
|
1529
|
# (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
|
|
1545
|
# (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
|
|
1530
|
if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
|
|
1546
|
if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
|
|
1531
|
import msvcrt
|
|
1547
|
import msvcrt
|
|
1532
|
def page_more():
|
|
1548
|
def page_more():
|
|
1533
|
""" Smart pausing between pages
|
|
1549
|
""" Smart pausing between pages
|
|
1534
|
|
|
1550
|
|
|
1535
|
@return: True if need print more lines, False if quit
|
|
1551
|
@return: True if need print more lines, False if quit
|
|
1536
|
"""
|
|
1552
|
"""
|
|
1537
|
Term.cout.write('---Return to continue, q to quit--- ')
|
|
1553
|
Term.cout.write('---Return to continue, q to quit--- ')
|
|
1538
|
ans = msvcrt.getch()
|
|
1554
|
ans = msvcrt.getch()
|
|
1539
|
if ans in ("q", "Q"):
|
|
1555
|
if ans in ("q", "Q"):
|
|
1540
|
result = False
|
|
1556
|
result = False
|
|
1541
|
else:
|
|
1557
|
else:
|
|
1542
|
result = True
|
|
1558
|
result = True
|
|
1543
|
Term.cout.write("\b"*37 + " "*37 + "\b"*37)
|
|
1559
|
Term.cout.write("\b"*37 + " "*37 + "\b"*37)
|
|
1544
|
return result
|
|
1560
|
return result
|
|
1545
|
else:
|
|
1561
|
else:
|
|
1546
|
def page_more():
|
|
1562
|
def page_more():
|
|
1547
|
ans = raw_input('---Return to continue, q to quit--- ')
|
|
1563
|
ans = raw_input('---Return to continue, q to quit--- ')
|
|
1548
|
if ans.lower().startswith('q'):
|
|
1564
|
if ans.lower().startswith('q'):
|
|
1549
|
return False
|
|
1565
|
return False
|
|
1550
|
else:
|
|
1566
|
else:
|
|
1551
|
return True
|
|
1567
|
return True
|
|
1552
|
|
|
1568
|
|
|
1553
|
esc_re = re.compile(r"(\x1b[^m]+m)")
|
|
1569
|
esc_re = re.compile(r"(\x1b[^m]+m)")
|
|
1554
|
|
|
1570
|
|
|
1555
|
def page_dumb(strng,start=0,screen_lines=25):
|
|
1571
|
def page_dumb(strng,start=0,screen_lines=25):
|
|
1556
|
"""Very dumb 'pager' in Python, for when nothing else works.
|
|
1572
|
"""Very dumb 'pager' in Python, for when nothing else works.
|
|
1557
|
|
|
1573
|
|
|
1558
|
Only moves forward, same interface as page(), except for pager_cmd and
|
|
1574
|
Only moves forward, same interface as page(), except for pager_cmd and
|
|
1559
|
mode."""
|
|
1575
|
mode."""
|
|
1560
|
|
|
1576
|
|
|
1561
|
out_ln = strng.splitlines()[start:]
|
|
1577
|
out_ln = strng.splitlines()[start:]
|
|
1562
|
screens = chop(out_ln,screen_lines-1)
|
|
1578
|
screens = chop(out_ln,screen_lines-1)
|
|
1563
|
if len(screens) == 1:
|
|
1579
|
if len(screens) == 1:
|
|
1564
|
print >>Term.cout, os.linesep.join(screens[0])
|
|
1580
|
print >>Term.cout, os.linesep.join(screens[0])
|
|
1565
|
else:
|
|
1581
|
else:
|
|
1566
|
last_escape = ""
|
|
1582
|
last_escape = ""
|
|
1567
|
for scr in screens[0:-1]:
|
|
1583
|
for scr in screens[0:-1]:
|
|
1568
|
hunk = os.linesep.join(scr)
|
|
1584
|
hunk = os.linesep.join(scr)
|
|
1569
|
print >>Term.cout, last_escape + hunk
|
|
1585
|
print >>Term.cout, last_escape + hunk
|
|
1570
|
if not page_more():
|
|
1586
|
if not page_more():
|
|
1571
|
return
|
|
1587
|
return
|
|
1572
|
esc_list = esc_re.findall(hunk)
|
|
1588
|
esc_list = esc_re.findall(hunk)
|
|
1573
|
if len(esc_list) > 0:
|
|
1589
|
if len(esc_list) > 0:
|
|
1574
|
last_escape = esc_list[-1]
|
|
1590
|
last_escape = esc_list[-1]
|
|
1575
|
print >>Term.cout, last_escape + os.linesep.join(screens[-1])
|
|
1591
|
print >>Term.cout, last_escape + os.linesep.join(screens[-1])
|
|
1576
|
|
|
1592
|
|
|
1577
|
#----------------------------------------------------------------------------
|
|
1593
|
#----------------------------------------------------------------------------
|
|
1578
|
def page(strng,start=0,screen_lines=0,pager_cmd = None):
|
|
1594
|
def page(strng,start=0,screen_lines=0,pager_cmd = None):
|
|
1579
|
"""Print a string, piping through a pager after a certain length.
|
|
1595
|
"""Print a string, piping through a pager after a certain length.
|
|
1580
|
|
|
1596
|
|
|
1581
|
The screen_lines parameter specifies the number of *usable* lines of your
|
|
1597
|
The screen_lines parameter specifies the number of *usable* lines of your
|
|
1582
|
terminal screen (total lines minus lines you need to reserve to show other
|
|
1598
|
terminal screen (total lines minus lines you need to reserve to show other
|
|
1583
|
information).
|
|
1599
|
information).
|
|
1584
|
|
|
1600
|
|
|
1585
|
If you set screen_lines to a number <=0, page() will try to auto-determine
|
|
1601
|
If you set screen_lines to a number <=0, page() will try to auto-determine
|
|
1586
|
your screen size and will only use up to (screen_size+screen_lines) for
|
|
1602
|
your screen size and will only use up to (screen_size+screen_lines) for
|
|
1587
|
printing, paging after that. That is, if you want auto-detection but need
|
|
1603
|
printing, paging after that. That is, if you want auto-detection but need
|
|
1588
|
to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
|
|
1604
|
to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
|
|
1589
|
auto-detection without any lines reserved simply use screen_lines = 0.
|
|
1605
|
auto-detection without any lines reserved simply use screen_lines = 0.
|
|
1590
|
|
|
1606
|
|
|
1591
|
If a string won't fit in the allowed lines, it is sent through the
|
|
1607
|
If a string won't fit in the allowed lines, it is sent through the
|
|
1592
|
specified pager command. If none given, look for PAGER in the environment,
|
|
1608
|
specified pager command. If none given, look for PAGER in the environment,
|
|
1593
|
and ultimately default to less.
|
|
1609
|
and ultimately default to less.
|
|
1594
|
|
|
1610
|
|
|
1595
|
If no system pager works, the string is sent through a 'dumb pager'
|
|
1611
|
If no system pager works, the string is sent through a 'dumb pager'
|
|
1596
|
written in python, very simplistic.
|
|
1612
|
written in python, very simplistic.
|
|
1597
|
"""
|
|
1613
|
"""
|
|
1598
|
|
|
1614
|
|
|
1599
|
# Some routines may auto-compute start offsets incorrectly and pass a
|
|
1615
|
# Some routines may auto-compute start offsets incorrectly and pass a
|
|
1600
|
# negative value. Offset to 0 for robustness.
|
|
1616
|
# negative value. Offset to 0 for robustness.
|
|
1601
|
start = max(0,start)
|
|
1617
|
start = max(0,start)
|
|
1602
|
|
|
1618
|
|
|
1603
|
# first, try the hook
|
|
1619
|
# first, try the hook
|
|
1604
|
ip = IPython.ipapi.get()
|
|
1620
|
ip = IPython.ipapi.get()
|
|
1605
|
if ip:
|
|
1621
|
if ip:
|
|
1606
|
try:
|
|
1622
|
try:
|
|
1607
|
ip.IP.hooks.show_in_pager(strng)
|
|
1623
|
ip.IP.hooks.show_in_pager(strng)
|
|
1608
|
return
|
|
1624
|
return
|
|
1609
|
except IPython.ipapi.TryNext:
|
|
1625
|
except IPython.ipapi.TryNext:
|
|
1610
|
pass
|
|
1626
|
pass
|
|
1611
|
|
|
1627
|
|
|
1612
|
# Ugly kludge, but calling curses.initscr() flat out crashes in emacs
|
|
1628
|
# Ugly kludge, but calling curses.initscr() flat out crashes in emacs
|
|
1613
|
TERM = os.environ.get('TERM','dumb')
|
|
1629
|
TERM = os.environ.get('TERM','dumb')
|
|
1614
|
if TERM in ['dumb','emacs'] and os.name != 'nt':
|
|
1630
|
if TERM in ['dumb','emacs'] and os.name != 'nt':
|
|
1615
|
print strng
|
|
1631
|
print strng
|
|
1616
|
return
|
|
1632
|
return
|
|
1617
|
# chop off the topmost part of the string we don't want to see
|
|
1633
|
# chop off the topmost part of the string we don't want to see
|
|
1618
|
str_lines = strng.split(os.linesep)[start:]
|
|
1634
|
str_lines = strng.split(os.linesep)[start:]
|
|
1619
|
str_toprint = os.linesep.join(str_lines)
|
|
1635
|
str_toprint = os.linesep.join(str_lines)
|
|
1620
|
num_newlines = len(str_lines)
|
|
1636
|
num_newlines = len(str_lines)
|
|
1621
|
len_str = len(str_toprint)
|
|
1637
|
len_str = len(str_toprint)
|
|
1622
|
|
|
1638
|
|
|
1623
|
# Dumb heuristics to guesstimate number of on-screen lines the string
|
|
1639
|
# Dumb heuristics to guesstimate number of on-screen lines the string
|
|
1624
|
# takes. Very basic, but good enough for docstrings in reasonable
|
|
1640
|
# takes. Very basic, but good enough for docstrings in reasonable
|
|
1625
|
# terminals. If someone later feels like refining it, it's not hard.
|
|
1641
|
# terminals. If someone later feels like refining it, it's not hard.
|
|
1626
|
numlines = max(num_newlines,int(len_str/80)+1)
|
|
1642
|
numlines = max(num_newlines,int(len_str/80)+1)
|
|
1627
|
|
|
1643
|
|
|
1628
|
if os.name == "nt":
|
|
1644
|
if os.name == "nt":
|
|
1629
|
screen_lines_def = get_console_size(defaulty=25)[1]
|
|
1645
|
screen_lines_def = get_console_size(defaulty=25)[1]
|
|
1630
|
else:
|
|
1646
|
else:
|
|
1631
|
screen_lines_def = 25 # default value if we can't auto-determine
|
|
1647
|
screen_lines_def = 25 # default value if we can't auto-determine
|
|
1632
|
|
|
1648
|
|
|
1633
|
# auto-determine screen size
|
|
1649
|
# auto-determine screen size
|
|
1634
|
if screen_lines <= 0:
|
|
1650
|
if screen_lines <= 0:
|
|
1635
|
if TERM=='xterm':
|
|
1651
|
if TERM=='xterm':
|
|
1636
|
use_curses = USE_CURSES
|
|
1652
|
use_curses = USE_CURSES
|
|
1637
|
else:
|
|
1653
|
else:
|
|
1638
|
# curses causes problems on many terminals other than xterm.
|
|
1654
|
# curses causes problems on many terminals other than xterm.
|
|
1639
|
use_curses = False
|
|
1655
|
use_curses = False
|
|
1640
|
if use_curses:
|
|
1656
|
if use_curses:
|
|
1641
|
# There is a bug in curses, where *sometimes* it fails to properly
|
|
1657
|
# There is a bug in curses, where *sometimes* it fails to properly
|
|
1642
|
# initialize, and then after the endwin() call is made, the
|
|
1658
|
# initialize, and then after the endwin() call is made, the
|
|
1643
|
# terminal is left in an unusable state. Rather than trying to
|
|
1659
|
# terminal is left in an unusable state. Rather than trying to
|
|
1644
|
# check everytime for this (by requesting and comparing termios
|
|
1660
|
# check everytime for this (by requesting and comparing termios
|
|
1645
|
# flags each time), we just save the initial terminal state and
|
|
1661
|
# flags each time), we just save the initial terminal state and
|
|
1646
|
# unconditionally reset it every time. It's cheaper than making
|
|
1662
|
# unconditionally reset it every time. It's cheaper than making
|
|
1647
|
# the checks.
|
|
1663
|
# the checks.
|
|
1648
|
term_flags = termios.tcgetattr(sys.stdout)
|
|
1664
|
term_flags = termios.tcgetattr(sys.stdout)
|
|
1649
|
scr = curses.initscr()
|
|
1665
|
scr = curses.initscr()
|
|
1650
|
screen_lines_real,screen_cols = scr.getmaxyx()
|
|
1666
|
screen_lines_real,screen_cols = scr.getmaxyx()
|
|
1651
|
curses.endwin()
|
|
1667
|
curses.endwin()
|
|
1652
|
# Restore terminal state in case endwin() didn't.
|
|
1668
|
# Restore terminal state in case endwin() didn't.
|
|
1653
|
termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
|
|
1669
|
termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
|
|
1654
|
# Now we have what we needed: the screen size in rows/columns
|
|
1670
|
# Now we have what we needed: the screen size in rows/columns
|
|
1655
|
screen_lines += screen_lines_real
|
|
1671
|
screen_lines += screen_lines_real
|
|
1656
|
#print '***Screen size:',screen_lines_real,'lines x',\
|
|
1672
|
#print '***Screen size:',screen_lines_real,'lines x',\
|
|
1657
|
#screen_cols,'columns.' # dbg
|
|
1673
|
#screen_cols,'columns.' # dbg
|
|
1658
|
else:
|
|
1674
|
else:
|
|
1659
|
screen_lines += screen_lines_def
|
|
1675
|
screen_lines += screen_lines_def
|
|
1660
|
|
|
1676
|
|
|
1661
|
#print 'numlines',numlines,'screenlines',screen_lines # dbg
|
|
1677
|
#print 'numlines',numlines,'screenlines',screen_lines # dbg
|
|
1662
|
if numlines <= screen_lines :
|
|
1678
|
if numlines <= screen_lines :
|
|
1663
|
#print '*** normal print' # dbg
|
|
1679
|
#print '*** normal print' # dbg
|
|
1664
|
print >>Term.cout, str_toprint
|
|
1680
|
print >>Term.cout, str_toprint
|
|
1665
|
else:
|
|
1681
|
else:
|
|
1666
|
# Try to open pager and default to internal one if that fails.
|
|
1682
|
# Try to open pager and default to internal one if that fails.
|
|
1667
|
# All failure modes are tagged as 'retval=1', to match the return
|
|
1683
|
# All failure modes are tagged as 'retval=1', to match the return
|
|
1668
|
# value of a failed system command. If any intermediate attempt
|
|
1684
|
# value of a failed system command. If any intermediate attempt
|
|
1669
|
# sets retval to 1, at the end we resort to our own page_dumb() pager.
|
|
1685
|
# sets retval to 1, at the end we resort to our own page_dumb() pager.
|
|
1670
|
pager_cmd = get_pager_cmd(pager_cmd)
|
|
1686
|
pager_cmd = get_pager_cmd(pager_cmd)
|
|
1671
|
pager_cmd += ' ' + get_pager_start(pager_cmd,start)
|
|
1687
|
pager_cmd += ' ' + get_pager_start(pager_cmd,start)
|
|
1672
|
if os.name == 'nt':
|
|
1688
|
if os.name == 'nt':
|
|
1673
|
if pager_cmd.startswith('type'):
|
|
1689
|
if pager_cmd.startswith('type'):
|
|
1674
|
# The default WinXP 'type' command is failing on complex strings.
|
|
1690
|
# The default WinXP 'type' command is failing on complex strings.
|
|
1675
|
retval = 1
|
|
1691
|
retval = 1
|
|
1676
|
else:
|
|
1692
|
else:
|
|
1677
|
tmpname = tempfile.mktemp('.txt')
|
|
1693
|
tmpname = tempfile.mktemp('.txt')
|
|
1678
|
tmpfile = file(tmpname,'wt')
|
|
1694
|
tmpfile = file(tmpname,'wt')
|
|
1679
|
tmpfile.write(strng)
|
|
1695
|
tmpfile.write(strng)
|
|
1680
|
tmpfile.close()
|
|
1696
|
tmpfile.close()
|
|
1681
|
cmd = "%s < %s" % (pager_cmd,tmpname)
|
|
1697
|
cmd = "%s < %s" % (pager_cmd,tmpname)
|
|
1682
|
if os.system(cmd):
|
|
1698
|
if os.system(cmd):
|
|
1683
|
retval = 1
|
|
1699
|
retval = 1
|
|
1684
|
else:
|
|
1700
|
else:
|
|
1685
|
retval = None
|
|
1701
|
retval = None
|
|
1686
|
os.remove(tmpname)
|
|
1702
|
os.remove(tmpname)
|
|
1687
|
else:
|
|
1703
|
else:
|
|
1688
|
try:
|
|
1704
|
try:
|
|
1689
|
retval = None
|
|
1705
|
retval = None
|
|
1690
|
# if I use popen4, things hang. No idea why.
|
|
1706
|
# if I use popen4, things hang. No idea why.
|
|
1691
|
#pager,shell_out = os.popen4(pager_cmd)
|
|
1707
|
#pager,shell_out = os.popen4(pager_cmd)
|
|
1692
|
pager = os.popen(pager_cmd,'w')
|
|
1708
|
pager = os.popen(pager_cmd,'w')
|
|
1693
|
pager.write(strng)
|
|
1709
|
pager.write(strng)
|
|
1694
|
pager.close()
|
|
1710
|
pager.close()
|
|
1695
|
retval = pager.close() # success returns None
|
|
1711
|
retval = pager.close() # success returns None
|
|
1696
|
except IOError,msg: # broken pipe when user quits
|
|
1712
|
except IOError,msg: # broken pipe when user quits
|
|
1697
|
if msg.args == (32,'Broken pipe'):
|
|
1713
|
if msg.args == (32,'Broken pipe'):
|
|
1698
|
retval = None
|
|
1714
|
retval = None
|
|
1699
|
else:
|
|
1715
|
else:
|
|
1700
|
retval = 1
|
|
1716
|
retval = 1
|
|
1701
|
except OSError:
|
|
1717
|
except OSError:
|
|
1702
|
# Other strange problems, sometimes seen in Win2k/cygwin
|
|
1718
|
# Other strange problems, sometimes seen in Win2k/cygwin
|
|
1703
|
retval = 1
|
|
1719
|
retval = 1
|
|
1704
|
if retval is not None:
|
|
1720
|
if retval is not None:
|
|
1705
|
page_dumb(strng,screen_lines=screen_lines)
|
|
1721
|
page_dumb(strng,screen_lines=screen_lines)
|
|
1706
|
|
|
1722
|
|
|
1707
|
#----------------------------------------------------------------------------
|
|
1723
|
#----------------------------------------------------------------------------
|
|
1708
|
def page_file(fname,start = 0, pager_cmd = None):
|
|
1724
|
def page_file(fname,start = 0, pager_cmd = None):
|
|
1709
|
"""Page a file, using an optional pager command and starting line.
|
|
1725
|
"""Page a file, using an optional pager command and starting line.
|
|
1710
|
"""
|
|
1726
|
"""
|
|
1711
|
|
|
1727
|
|
|
1712
|
pager_cmd = get_pager_cmd(pager_cmd)
|
|
1728
|
pager_cmd = get_pager_cmd(pager_cmd)
|
|
1713
|
pager_cmd += ' ' + get_pager_start(pager_cmd,start)
|
|
1729
|
pager_cmd += ' ' + get_pager_start(pager_cmd,start)
|
|
1714
|
|
|
1730
|
|
|
1715
|
try:
|
|
1731
|
try:
|
|
1716
|
if os.environ['TERM'] in ['emacs','dumb']:
|
|
1732
|
if os.environ['TERM'] in ['emacs','dumb']:
|
|
1717
|
raise EnvironmentError
|
|
1733
|
raise EnvironmentError
|
|
1718
|
xsys(pager_cmd + ' ' + fname)
|
|
1734
|
xsys(pager_cmd + ' ' + fname)
|
|
1719
|
except:
|
|
1735
|
except:
|
|
1720
|
try:
|
|
1736
|
try:
|
|
1721
|
if start > 0:
|
|
1737
|
if start > 0:
|
|
1722
|
start -= 1
|
|
1738
|
start -= 1
|
|
1723
|
page(open(fname).read(),start)
|
|
1739
|
page(open(fname).read(),start)
|
|
1724
|
except:
|
|
1740
|
except:
|
|
1725
|
print 'Unable to show file',`fname`
|
|
1741
|
print 'Unable to show file',`fname`
|
|
1726
|
|
|
1742
|
|
|
1727
|
|
|
1743
|
|
|
1728
|
#----------------------------------------------------------------------------
|
|
1744
|
#----------------------------------------------------------------------------
|
|
1729
|
def snip_print(str,width = 75,print_full = 0,header = ''):
|
|
1745
|
def snip_print(str,width = 75,print_full = 0,header = ''):
|
|
1730
|
"""Print a string snipping the midsection to fit in width.
|
|
1746
|
"""Print a string snipping the midsection to fit in width.
|
|
1731
|
|
|
1747
|
|
|
1732
|
print_full: mode control:
|
|
1748
|
print_full: mode control:
|
|
1733
|
- 0: only snip long strings
|
|
1749
|
- 0: only snip long strings
|
|
1734
|
- 1: send to page() directly.
|
|
1750
|
- 1: send to page() directly.
|
|
1735
|
- 2: snip long strings and ask for full length viewing with page()
|
|
1751
|
- 2: snip long strings and ask for full length viewing with page()
|
|
1736
|
Return 1 if snipping was necessary, 0 otherwise."""
|
|
1752
|
Return 1 if snipping was necessary, 0 otherwise."""
|
|
1737
|
|
|
1753
|
|
|
1738
|
if print_full == 1:
|
|
1754
|
if print_full == 1:
|
|
1739
|
page(header+str)
|
|
1755
|
page(header+str)
|
|
1740
|
return 0
|
|
1756
|
return 0
|
|
1741
|
|
|
1757
|
|
|
1742
|
print header,
|
|
1758
|
print header,
|
|
1743
|
if len(str) < width:
|
|
1759
|
if len(str) < width:
|
|
1744
|
print str
|
|
1760
|
print str
|
|
1745
|
snip = 0
|
|
1761
|
snip = 0
|
|
1746
|
else:
|
|
1762
|
else:
|
|
1747
|
whalf = int((width -5)/2)
|
|
1763
|
whalf = int((width -5)/2)
|
|
1748
|
print str[:whalf] + ' <...> ' + str[-whalf:]
|
|
1764
|
print str[:whalf] + ' <...> ' + str[-whalf:]
|
|
1749
|
snip = 1
|
|
1765
|
snip = 1
|
|
1750
|
if snip and print_full == 2:
|
|
1766
|
if snip and print_full == 2:
|
|
1751
|
if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
|
|
1767
|
if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
|
|
1752
|
page(str)
|
|
1768
|
page(str)
|
|
1753
|
return snip
|
|
1769
|
return snip
|
|
1754
|
|
|
1770
|
|
|
1755
|
#****************************************************************************
|
|
1771
|
#****************************************************************************
|
|
1756
|
# lists, dicts and structures
|
|
1772
|
# lists, dicts and structures
|
|
1757
|
|
|
1773
|
|
|
1758
|
def belong(candidates,checklist):
|
|
1774
|
def belong(candidates,checklist):
|
|
1759
|
"""Check whether a list of items appear in a given list of options.
|
|
1775
|
"""Check whether a list of items appear in a given list of options.
|
|
1760
|
|
|
1776
|
|
|
1761
|
Returns a list of 1 and 0, one for each candidate given."""
|
|
1777
|
Returns a list of 1 and 0, one for each candidate given."""
|
|
1762
|
|
|
1778
|
|
|
1763
|
return [x in checklist for x in candidates]
|
|
1779
|
return [x in checklist for x in candidates]
|
|
1764
|
|
|
1780
|
|
|
1765
|
#----------------------------------------------------------------------------
|
|
1781
|
#----------------------------------------------------------------------------
|
|
1766
|
def uniq_stable(elems):
|
|
1782
|
def uniq_stable(elems):
|
|
1767
|
"""uniq_stable(elems) -> list
|
|
1783
|
"""uniq_stable(elems) -> list
|
|
1768
|
|
|
1784
|
|
|
1769
|
Return from an iterable, a list of all the unique elements in the input,
|
|
1785
|
Return from an iterable, a list of all the unique elements in the input,
|
|
1770
|
but maintaining the order in which they first appear.
|
|
1786
|
but maintaining the order in which they first appear.
|
|
1771
|
|
|
1787
|
|
|
1772
|
A naive solution to this problem which just makes a dictionary with the
|
|
1788
|
A naive solution to this problem which just makes a dictionary with the
|
|
1773
|
elements as keys fails to respect the stability condition, since
|
|
1789
|
elements as keys fails to respect the stability condition, since
|
|
1774
|
dictionaries are unsorted by nature.
|
|
1790
|
dictionaries are unsorted by nature.
|
|
1775
|
|
|
1791
|
|
|
1776
|
Note: All elements in the input must be valid dictionary keys for this
|
|
1792
|
Note: All elements in the input must be valid dictionary keys for this
|
|
1777
|
routine to work, as it internally uses a dictionary for efficiency
|
|
1793
|
routine to work, as it internally uses a dictionary for efficiency
|
|
1778
|
reasons."""
|
|
1794
|
reasons."""
|
|
1779
|
|
|
1795
|
|
|
1780
|
unique = []
|
|
1796
|
unique = []
|
|
1781
|
unique_dict = {}
|
|
1797
|
unique_dict = {}
|
|
1782
|
for nn in elems:
|
|
1798
|
for nn in elems:
|
|
1783
|
if nn not in unique_dict:
|
|
1799
|
if nn not in unique_dict:
|
|
1784
|
unique.append(nn)
|
|
1800
|
unique.append(nn)
|
|
1785
|
unique_dict[nn] = None
|
|
1801
|
unique_dict[nn] = None
|
|
1786
|
return unique
|
|
1802
|
return unique
|
|
1787
|
|
|
1803
|
|
|
1788
|
#----------------------------------------------------------------------------
|
|
1804
|
#----------------------------------------------------------------------------
|
|
1789
|
class NLprinter:
|
|
1805
|
class NLprinter:
|
|
1790
|
"""Print an arbitrarily nested list, indicating index numbers.
|
|
1806
|
"""Print an arbitrarily nested list, indicating index numbers.
|
|
1791
|
|
|
1807
|
|
|
1792
|
An instance of this class called nlprint is available and callable as a
|
|
1808
|
An instance of this class called nlprint is available and callable as a
|
|
1793
|
function.
|
|
1809
|
function.
|
|
1794
|
|
|
1810
|
|
|
1795
|
nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
|
|
1811
|
nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
|
|
1796
|
and using 'sep' to separate the index from the value. """
|
|
1812
|
and using 'sep' to separate the index from the value. """
|
|
1797
|
|
|
1813
|
|
|
1798
|
def __init__(self):
|
|
1814
|
def __init__(self):
|
|
1799
|
self.depth = 0
|
|
1815
|
self.depth = 0
|
|
1800
|
|
|
1816
|
|
|
1801
|
def __call__(self,lst,pos='',**kw):
|
|
1817
|
def __call__(self,lst,pos='',**kw):
|
|
1802
|
"""Prints the nested list numbering levels."""
|
|
1818
|
"""Prints the nested list numbering levels."""
|
|
1803
|
kw.setdefault('indent',' ')
|
|
1819
|
kw.setdefault('indent',' ')
|
|
1804
|
kw.setdefault('sep',': ')
|
|
1820
|
kw.setdefault('sep',': ')
|
|
1805
|
kw.setdefault('start',0)
|
|
1821
|
kw.setdefault('start',0)
|
|
1806
|
kw.setdefault('stop',len(lst))
|
|
1822
|
kw.setdefault('stop',len(lst))
|
|
1807
|
# we need to remove start and stop from kw so they don't propagate
|
|
1823
|
# we need to remove start and stop from kw so they don't propagate
|
|
1808
|
# into a recursive call for a nested list.
|
|
1824
|
# into a recursive call for a nested list.
|
|
1809
|
start = kw['start']; del kw['start']
|
|
1825
|
start = kw['start']; del kw['start']
|
|
1810
|
stop = kw['stop']; del kw['stop']
|
|
1826
|
stop = kw['stop']; del kw['stop']
|
|
1811
|
if self.depth == 0 and 'header' in kw.keys():
|
|
1827
|
if self.depth == 0 and 'header' in kw.keys():
|
|
1812
|
print kw['header']
|
|
1828
|
print kw['header']
|
|
1813
|
|
|
1829
|
|
|
1814
|
for idx in range(start,stop):
|
|
1830
|
for idx in range(start,stop):
|
|
1815
|
elem = lst[idx]
|
|
1831
|
elem = lst[idx]
|
|
1816
|
if type(elem)==type([]):
|
|
1832
|
if type(elem)==type([]):
|
|
1817
|
self.depth += 1
|
|
1833
|
self.depth += 1
|
|
1818
|
self.__call__(elem,itpl('$pos$idx,'),**kw)
|
|
1834
|
self.__call__(elem,itpl('$pos$idx,'),**kw)
|
|
1819
|
self.depth -= 1
|
|
1835
|
self.depth -= 1
|
|
1820
|
else:
|
|
1836
|
else:
|
|
1821
|
printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
|
|
1837
|
printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
|
|
1822
|
|
|
1838
|
|
|
1823
|
nlprint = NLprinter()
|
|
1839
|
nlprint = NLprinter()
|
|
1824
|
#----------------------------------------------------------------------------
|
|
1840
|
#----------------------------------------------------------------------------
|
|
1825
|
def all_belong(candidates,checklist):
|
|
1841
|
def all_belong(candidates,checklist):
|
|
1826
|
"""Check whether a list of items ALL appear in a given list of options.
|
|
1842
|
"""Check whether a list of items ALL appear in a given list of options.
|
|
1827
|
|
|
1843
|
|
|
1828
|
Returns a single 1 or 0 value."""
|
|
1844
|
Returns a single 1 or 0 value."""
|
|
1829
|
|
|
1845
|
|
|
1830
|
return 1-(0 in [x in checklist for x in candidates])
|
|
1846
|
return 1-(0 in [x in checklist for x in candidates])
|
|
1831
|
|
|
1847
|
|
|
1832
|
#----------------------------------------------------------------------------
|
|
1848
|
#----------------------------------------------------------------------------
|
|
1833
|
def sort_compare(lst1,lst2,inplace = 1):
|
|
1849
|
def sort_compare(lst1,lst2,inplace = 1):
|
|
1834
|
"""Sort and compare two lists.
|
|
1850
|
"""Sort and compare two lists.
|
|
1835
|
|
|
1851
|
|
|
1836
|
By default it does it in place, thus modifying the lists. Use inplace = 0
|
|
1852
|
By default it does it in place, thus modifying the lists. Use inplace = 0
|
|
1837
|
to avoid that (at the cost of temporary copy creation)."""
|
|
1853
|
to avoid that (at the cost of temporary copy creation)."""
|
|
1838
|
if not inplace:
|
|
1854
|
if not inplace:
|
|
1839
|
lst1 = lst1[:]
|
|
1855
|
lst1 = lst1[:]
|
|
1840
|
lst2 = lst2[:]
|
|
1856
|
lst2 = lst2[:]
|
|
1841
|
lst1.sort(); lst2.sort()
|
|
1857
|
lst1.sort(); lst2.sort()
|
|
1842
|
return lst1 == lst2
|
|
1858
|
return lst1 == lst2
|
|
1843
|
|
|
1859
|
|
|
1844
|
#----------------------------------------------------------------------------
|
|
1860
|
#----------------------------------------------------------------------------
|
|
1845
|
def list2dict(lst):
|
|
1861
|
def list2dict(lst):
|
|
1846
|
"""Takes a list of (key,value) pairs and turns it into a dict."""
|
|
1862
|
"""Takes a list of (key,value) pairs and turns it into a dict."""
|
|
1847
|
|
|
1863
|
|
|
1848
|
dic = {}
|
|
1864
|
dic = {}
|
|
1849
|
for k,v in lst: dic[k] = v
|
|
1865
|
for k,v in lst: dic[k] = v
|
|
1850
|
return dic
|
|
1866
|
return dic
|
|
1851
|
|
|
1867
|
|
|
1852
|
#----------------------------------------------------------------------------
|
|
1868
|
#----------------------------------------------------------------------------
|
|
1853
|
def list2dict2(lst,default=''):
|
|
1869
|
def list2dict2(lst,default=''):
|
|
1854
|
"""Takes a list and turns it into a dict.
|
|
1870
|
"""Takes a list and turns it into a dict.
|
|
1855
|
Much slower than list2dict, but more versatile. This version can take
|
|
1871
|
Much slower than list2dict, but more versatile. This version can take
|
|
1856
|
lists with sublists of arbitrary length (including sclars)."""
|
|
1872
|
lists with sublists of arbitrary length (including sclars)."""
|
|
1857
|
|
|
1873
|
|
|
1858
|
dic = {}
|
|
1874
|
dic = {}
|
|
1859
|
for elem in lst:
|
|
1875
|
for elem in lst:
|
|
1860
|
if type(elem) in (types.ListType,types.TupleType):
|
|
1876
|
if type(elem) in (types.ListType,types.TupleType):
|
|
1861
|
size = len(elem)
|
|
1877
|
size = len(elem)
|
|
1862
|
if size == 0:
|
|
1878
|
if size == 0:
|
|
1863
|
pass
|
|
1879
|
pass
|
|
1864
|
elif size == 1:
|
|
1880
|
elif size == 1:
|
|
1865
|
dic[elem] = default
|
|
1881
|
dic[elem] = default
|
|
1866
|
else:
|
|
1882
|
else:
|
|
1867
|
k,v = elem[0], elem[1:]
|
|
1883
|
k,v = elem[0], elem[1:]
|
|
1868
|
if len(v) == 1: v = v[0]
|
|
1884
|
if len(v) == 1: v = v[0]
|
|
1869
|
dic[k] = v
|
|
1885
|
dic[k] = v
|
|
1870
|
else:
|
|
1886
|
else:
|
|
1871
|
dic[elem] = default
|
|
1887
|
dic[elem] = default
|
|
1872
|
return dic
|
|
1888
|
return dic
|
|
1873
|
|
|
1889
|
|
|
1874
|
#----------------------------------------------------------------------------
|
|
1890
|
#----------------------------------------------------------------------------
|
|
1875
|
def flatten(seq):
|
|
1891
|
def flatten(seq):
|
|
1876
|
"""Flatten a list of lists (NOT recursive, only works for 2d lists)."""
|
|
1892
|
"""Flatten a list of lists (NOT recursive, only works for 2d lists)."""
|
|
1877
|
|
|
1893
|
|
|
1878
|
return [x for subseq in seq for x in subseq]
|
|
1894
|
return [x for subseq in seq for x in subseq]
|
|
1879
|
|
|
1895
|
|
|
1880
|
#----------------------------------------------------------------------------
|
|
1896
|
#----------------------------------------------------------------------------
|
|
1881
|
def get_slice(seq,start=0,stop=None,step=1):
|
|
1897
|
def get_slice(seq,start=0,stop=None,step=1):
|
|
1882
|
"""Get a slice of a sequence with variable step. Specify start,stop,step."""
|
|
1898
|
"""Get a slice of a sequence with variable step. Specify start,stop,step."""
|
|
1883
|
if stop == None:
|
|
1899
|
if stop == None:
|
|
1884
|
stop = len(seq)
|
|
1900
|
stop = len(seq)
|
|
1885
|
item = lambda i: seq[i]
|
|
1901
|
item = lambda i: seq[i]
|
|
1886
|
return map(item,xrange(start,stop,step))
|
|
1902
|
return map(item,xrange(start,stop,step))
|
|
1887
|
|
|
1903
|
|
|
1888
|
#----------------------------------------------------------------------------
|
|
1904
|
#----------------------------------------------------------------------------
|
|
1889
|
def chop(seq,size):
|
|
1905
|
def chop(seq,size):
|
|
1890
|
"""Chop a sequence into chunks of the given size."""
|
|
1906
|
"""Chop a sequence into chunks of the given size."""
|
|
1891
|
chunk = lambda i: seq[i:i+size]
|
|
1907
|
chunk = lambda i: seq[i:i+size]
|
|
1892
|
return map(chunk,xrange(0,len(seq),size))
|
|
1908
|
return map(chunk,xrange(0,len(seq),size))
|
|
1893
|
|
|
1909
|
|
|
1894
|
#----------------------------------------------------------------------------
|
|
1910
|
#----------------------------------------------------------------------------
|
|
1895
|
# with is a keyword as of python 2.5, so this function is renamed to withobj
|
|
1911
|
# with is a keyword as of python 2.5, so this function is renamed to withobj
|
|
1896
|
# from its old 'with' name.
|
|
1912
|
# from its old 'with' name.
|
|
1897
|
def with_obj(object, **args):
|
|
1913
|
def with_obj(object, **args):
|
|
1898
|
"""Set multiple attributes for an object, similar to Pascal's with.
|
|
1914
|
"""Set multiple attributes for an object, similar to Pascal's with.
|
|
1899
|
|
|
1915
|
|
|
1900
|
Example:
|
|
1916
|
Example:
|
|
1901
|
with_obj(jim,
|
|
1917
|
with_obj(jim,
|
|
1902
|
born = 1960,
|
|
1918
|
born = 1960,
|
|
1903
|
haircolour = 'Brown',
|
|
1919
|
haircolour = 'Brown',
|
|
1904
|
eyecolour = 'Green')
|
|
1920
|
eyecolour = 'Green')
|
|
1905
|
|
|
1921
|
|
|
1906
|
Credit: Greg Ewing, in
|
|
1922
|
Credit: Greg Ewing, in
|
|
1907
|
http://mail.python.org/pipermail/python-list/2001-May/040703.html.
|
|
1923
|
http://mail.python.org/pipermail/python-list/2001-May/040703.html.
|
|
1908
|
|
|
1924
|
|
|
1909
|
NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
|
|
1925
|
NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
|
|
1910
|
has become a keyword for Python 2.5, so we had to rename it."""
|
|
1926
|
has become a keyword for Python 2.5, so we had to rename it."""
|
|
1911
|
|
|
1927
|
|
|
1912
|
object.__dict__.update(args)
|
|
1928
|
object.__dict__.update(args)
|
|
1913
|
|
|
1929
|
|
|
1914
|
#----------------------------------------------------------------------------
|
|
1930
|
#----------------------------------------------------------------------------
|
|
1915
|
def setattr_list(obj,alist,nspace = None):
|
|
1931
|
def setattr_list(obj,alist,nspace = None):
|
|
1916
|
"""Set a list of attributes for an object taken from a namespace.
|
|
1932
|
"""Set a list of attributes for an object taken from a namespace.
|
|
1917
|
|
|
1933
|
|
|
1918
|
setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
|
|
1934
|
setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
|
|
1919
|
alist with their values taken from nspace, which must be a dict (something
|
|
1935
|
alist with their values taken from nspace, which must be a dict (something
|
|
1920
|
like locals() will often do) If nspace isn't given, locals() of the
|
|
1936
|
like locals() will often do) If nspace isn't given, locals() of the
|
|
1921
|
*caller* is used, so in most cases you can omit it.
|
|
1937
|
*caller* is used, so in most cases you can omit it.
|
|
1922
|
|
|
1938
|
|
|
1923
|
Note that alist can be given as a string, which will be automatically
|
|
1939
|
Note that alist can be given as a string, which will be automatically
|
|
1924
|
split into a list on whitespace. If given as a list, it must be a list of
|
|
1940
|
split into a list on whitespace. If given as a list, it must be a list of
|
|
1925
|
*strings* (the variable names themselves), not of variables."""
|
|
1941
|
*strings* (the variable names themselves), not of variables."""
|
|
1926
|
|
|
1942
|
|
|
1927
|
# this grabs the local variables from the *previous* call frame -- that is
|
|
1943
|
# this grabs the local variables from the *previous* call frame -- that is
|
|
1928
|
# the locals from the function that called setattr_list().
|
|
1944
|
# the locals from the function that called setattr_list().
|
|
1929
|
# - snipped from weave.inline()
|
|
1945
|
# - snipped from weave.inline()
|
|
1930
|
if nspace is None:
|
|
1946
|
if nspace is None:
|
|
1931
|
call_frame = sys._getframe().f_back
|
|
1947
|
call_frame = sys._getframe().f_back
|
|
1932
|
nspace = call_frame.f_locals
|
|
1948
|
nspace = call_frame.f_locals
|
|
1933
|
|
|
1949
|
|
|
1934
|
if type(alist) in StringTypes:
|
|
1950
|
if type(alist) in StringTypes:
|
|
1935
|
alist = alist.split()
|
|
1951
|
alist = alist.split()
|
|
1936
|
for attr in alist:
|
|
1952
|
for attr in alist:
|
|
1937
|
val = eval(attr,nspace)
|
|
1953
|
val = eval(attr,nspace)
|
|
1938
|
setattr(obj,attr,val)
|
|
1954
|
setattr(obj,attr,val)
|
|
1939
|
|
|
1955
|
|
|
1940
|
#----------------------------------------------------------------------------
|
|
1956
|
#----------------------------------------------------------------------------
|
|
1941
|
def getattr_list(obj,alist,*args):
|
|
1957
|
def getattr_list(obj,alist,*args):
|
|
1942
|
"""getattr_list(obj,alist[, default]) -> attribute list.
|
|
1958
|
"""getattr_list(obj,alist[, default]) -> attribute list.
|
|
1943
|
|
|
1959
|
|
|
1944
|
Get a list of named attributes for an object. When a default argument is
|
|
1960
|
Get a list of named attributes for an object. When a default argument is
|
|
1945
|
given, it is returned when the attribute doesn't exist; without it, an
|
|
1961
|
given, it is returned when the attribute doesn't exist; without it, an
|
|
1946
|
exception is raised in that case.
|
|
1962
|
exception is raised in that case.
|
|
1947
|
|
|
1963
|
|
|
1948
|
Note that alist can be given as a string, which will be automatically
|
|
1964
|
Note that alist can be given as a string, which will be automatically
|
|
1949
|
split into a list on whitespace. If given as a list, it must be a list of
|
|
1965
|
split into a list on whitespace. If given as a list, it must be a list of
|
|
1950
|
*strings* (the variable names themselves), not of variables."""
|
|
1966
|
*strings* (the variable names themselves), not of variables."""
|
|
1951
|
|
|
1967
|
|
|
1952
|
if type(alist) in StringTypes:
|
|
1968
|
if type(alist) in StringTypes:
|
|
1953
|
alist = alist.split()
|
|
1969
|
alist = alist.split()
|
|
1954
|
if args:
|
|
1970
|
if args:
|
|
1955
|
if len(args)==1:
|
|
1971
|
if len(args)==1:
|
|
1956
|
default = args[0]
|
|
1972
|
default = args[0]
|
|
1957
|
return map(lambda attr: getattr(obj,attr,default),alist)
|
|
1973
|
return map(lambda attr: getattr(obj,attr,default),alist)
|
|
1958
|
else:
|
|
1974
|
else:
|
|
1959
|
raise ValueError,'getattr_list() takes only one optional argument'
|
|
1975
|
raise ValueError,'getattr_list() takes only one optional argument'
|
|
1960
|
else:
|
|
1976
|
else:
|
|
1961
|
return map(lambda attr: getattr(obj,attr),alist)
|
|
1977
|
return map(lambda attr: getattr(obj,attr),alist)
|
|
1962
|
|
|
1978
|
|
|
1963
|
#----------------------------------------------------------------------------
|
|
1979
|
#----------------------------------------------------------------------------
|
|
1964
|
def map_method(method,object_list,*argseq,**kw):
|
|
1980
|
def map_method(method,object_list,*argseq,**kw):
|
|
1965
|
"""map_method(method,object_list,*args,**kw) -> list
|
|
1981
|
"""map_method(method,object_list,*args,**kw) -> list
|
|
1966
|
|
|
1982
|
|
|
1967
|
Return a list of the results of applying the methods to the items of the
|
|
1983
|
Return a list of the results of applying the methods to the items of the
|
|
1968
|
argument sequence(s). If more than one sequence is given, the method is
|
|
1984
|
argument sequence(s). If more than one sequence is given, the method is
|
|
1969
|
called with an argument list consisting of the corresponding item of each
|
|
1985
|
called with an argument list consisting of the corresponding item of each
|
|
1970
|
sequence. All sequences must be of the same length.
|
|
1986
|
sequence. All sequences must be of the same length.
|
|
1971
|
|
|
1987
|
|
|
1972
|
Keyword arguments are passed verbatim to all objects called.
|
|
1988
|
Keyword arguments are passed verbatim to all objects called.
|
|
1973
|
|
|
1989
|
|
|
1974
|
This is Python code, so it's not nearly as fast as the builtin map()."""
|
|
1990
|
This is Python code, so it's not nearly as fast as the builtin map()."""
|
|
1975
|
|
|
1991
|
|
|
1976
|
out_list = []
|
|
1992
|
out_list = []
|
|
1977
|
idx = 0
|
|
1993
|
idx = 0
|
|
1978
|
for object in object_list:
|
|
1994
|
for object in object_list:
|
|
1979
|
try:
|
|
1995
|
try:
|
|
1980
|
handler = getattr(object, method)
|
|
1996
|
handler = getattr(object, method)
|
|
1981
|
except AttributeError:
|
|
1997
|
except AttributeError:
|
|
1982
|
out_list.append(None)
|
|
1998
|
out_list.append(None)
|
|
1983
|
else:
|
|
1999
|
else:
|
|
1984
|
if argseq:
|
|
2000
|
if argseq:
|
|
1985
|
args = map(lambda lst:lst[idx],argseq)
|
|
2001
|
args = map(lambda lst:lst[idx],argseq)
|
|
1986
|
#print 'ob',object,'hand',handler,'ar',args # dbg
|
|
2002
|
#print 'ob',object,'hand',handler,'ar',args # dbg
|
|
1987
|
out_list.append(handler(args,**kw))
|
|
2003
|
out_list.append(handler(args,**kw))
|
|
1988
|
else:
|
|
2004
|
else:
|
|
1989
|
out_list.append(handler(**kw))
|
|
2005
|
out_list.append(handler(**kw))
|
|
1990
|
idx += 1
|
|
2006
|
idx += 1
|
|
1991
|
return out_list
|
|
2007
|
return out_list
|
|
1992
|
|
|
2008
|
|
|
1993
|
#----------------------------------------------------------------------------
|
|
2009
|
#----------------------------------------------------------------------------
|
|
1994
|
def get_class_members(cls):
|
|
2010
|
def get_class_members(cls):
|
|
1995
|
ret = dir(cls)
|
|
2011
|
ret = dir(cls)
|
|
1996
|
if hasattr(cls,'__bases__'):
|
|
2012
|
if hasattr(cls,'__bases__'):
|
|
1997
|
for base in cls.__bases__:
|
|
2013
|
for base in cls.__bases__:
|
|
1998
|
ret.extend(get_class_members(base))
|
|
2014
|
ret.extend(get_class_members(base))
|
|
1999
|
return ret
|
|
2015
|
return ret
|
|
2000
|
|
|
2016
|
|
|
2001
|
#----------------------------------------------------------------------------
|
|
2017
|
#----------------------------------------------------------------------------
|
|
2002
|
def dir2(obj):
|
|
2018
|
def dir2(obj):
|
|
2003
|
"""dir2(obj) -> list of strings
|
|
2019
|
"""dir2(obj) -> list of strings
|
|
2004
|
|
|
2020
|
|
|
2005
|
Extended version of the Python builtin dir(), which does a few extra
|
|
2021
|
Extended version of the Python builtin dir(), which does a few extra
|
|
2006
|
checks, and supports common objects with unusual internals that confuse
|
|
2022
|
checks, and supports common objects with unusual internals that confuse
|
|
2007
|
dir(), such as Traits and PyCrust.
|
|
2023
|
dir(), such as Traits and PyCrust.
|
|
2008
|
|
|
2024
|
|
|
2009
|
This version is guaranteed to return only a list of true strings, whereas
|
|
2025
|
This version is guaranteed to return only a list of true strings, whereas
|
|
2010
|
dir() returns anything that objects inject into themselves, even if they
|
|
2026
|
dir() returns anything that objects inject into themselves, even if they
|
|
2011
|
are later not really valid for attribute access (many extension libraries
|
|
2027
|
are later not really valid for attribute access (many extension libraries
|
|
2012
|
have such bugs).
|
|
2028
|
have such bugs).
|
|
2013
|
"""
|
|
2029
|
"""
|
|
2014
|
|
|
2030
|
|
|
2015
|
# Start building the attribute list via dir(), and then complete it
|
|
2031
|
# Start building the attribute list via dir(), and then complete it
|
|
2016
|
# with a few extra special-purpose calls.
|
|
2032
|
# with a few extra special-purpose calls.
|
|
2017
|
words = dir(obj)
|
|
2033
|
words = dir(obj)
|
|
2018
|
|
|
2034
|
|
|
2019
|
if hasattr(obj,'__class__'):
|
|
2035
|
if hasattr(obj,'__class__'):
|
|
2020
|
words.append('__class__')
|
|
2036
|
words.append('__class__')
|
|
2021
|
words.extend(get_class_members(obj.__class__))
|
|
2037
|
words.extend(get_class_members(obj.__class__))
|
|
2022
|
#if '__base__' in words: 1/0
|
|
2038
|
#if '__base__' in words: 1/0
|
|
2023
|
|
|
2039
|
|
|
2024
|
# Some libraries (such as traits) may introduce duplicates, we want to
|
|
2040
|
# Some libraries (such as traits) may introduce duplicates, we want to
|
|
2025
|
# track and clean this up if it happens
|
|
2041
|
# track and clean this up if it happens
|
|
2026
|
may_have_dupes = False
|
|
2042
|
may_have_dupes = False
|
|
2027
|
|
|
2043
|
|
|
2028
|
# this is the 'dir' function for objects with Enthought's traits
|
|
2044
|
# this is the 'dir' function for objects with Enthought's traits
|
|
2029
|
if hasattr(obj, 'trait_names'):
|
|
2045
|
if hasattr(obj, 'trait_names'):
|
|
2030
|
try:
|
|
2046
|
try:
|
|
2031
|
words.extend(obj.trait_names())
|
|
2047
|
words.extend(obj.trait_names())
|
|
2032
|
may_have_dupes = True
|
|
2048
|
may_have_dupes = True
|
|
2033
|
except TypeError:
|
|
2049
|
except TypeError:
|
|
2034
|
# This will happen if `obj` is a class and not an instance.
|
|
2050
|
# This will happen if `obj` is a class and not an instance.
|
|
2035
|
pass
|
|
2051
|
pass
|
|
2036
|
|
|
2052
|
|
|
2037
|
# Support for PyCrust-style _getAttributeNames magic method.
|
|
2053
|
# Support for PyCrust-style _getAttributeNames magic method.
|
|
2038
|
if hasattr(obj, '_getAttributeNames'):
|
|
2054
|
if hasattr(obj, '_getAttributeNames'):
|
|
2039
|
try:
|
|
2055
|
try:
|
|
2040
|
words.extend(obj._getAttributeNames())
|
|
2056
|
words.extend(obj._getAttributeNames())
|
|
2041
|
may_have_dupes = True
|
|
2057
|
may_have_dupes = True
|
|
2042
|
except TypeError:
|
|
2058
|
except TypeError:
|
|
2043
|
# `obj` is a class and not an instance. Ignore
|
|
2059
|
# `obj` is a class and not an instance. Ignore
|
|
2044
|
# this error.
|
|
2060
|
# this error.
|
|
2045
|
pass
|
|
2061
|
pass
|
|
2046
|
|
|
2062
|
|
|
2047
|
if may_have_dupes:
|
|
2063
|
if may_have_dupes:
|
|
2048
|
# eliminate possible duplicates, as some traits may also
|
|
2064
|
# eliminate possible duplicates, as some traits may also
|
|
2049
|
# appear as normal attributes in the dir() call.
|
|
2065
|
# appear as normal attributes in the dir() call.
|
|
2050
|
words = list(set(words))
|
|
2066
|
words = list(set(words))
|
|
2051
|
words.sort()
|
|
2067
|
words.sort()
|
|
2052
|
|
|
2068
|
|
|
2053
|
# filter out non-string attributes which may be stuffed by dir() calls
|
|
2069
|
# filter out non-string attributes which may be stuffed by dir() calls
|
|
2054
|
# and poor coding in third-party modules
|
|
2070
|
# and poor coding in third-party modules
|
|
2055
|
return [w for w in words if isinstance(w, basestring)]
|
|
2071
|
return [w for w in words if isinstance(w, basestring)]
|
|
2056
|
|
|
2072
|
|
|
2057
|
#----------------------------------------------------------------------------
|
|
2073
|
#----------------------------------------------------------------------------
|
|
2058
|
def import_fail_info(mod_name,fns=None):
|
|
2074
|
def import_fail_info(mod_name,fns=None):
|
|
2059
|
"""Inform load failure for a module."""
|
|
2075
|
"""Inform load failure for a module."""
|
|
2060
|
|
|
2076
|
|
|
2061
|
if fns == None:
|
|
2077
|
if fns == None:
|
|
2062
|
warn("Loading of %s failed.\n" % (mod_name,))
|
|
2078
|
warn("Loading of %s failed.\n" % (mod_name,))
|
|
2063
|
else:
|
|
2079
|
else:
|
|
2064
|
warn("Loading of %s from %s failed.\n" % (fns,mod_name))
|
|
2080
|
warn("Loading of %s from %s failed.\n" % (fns,mod_name))
|
|
2065
|
|
|
2081
|
|
|
2066
|
#----------------------------------------------------------------------------
|
|
2082
|
#----------------------------------------------------------------------------
|
|
2067
|
# Proposed popitem() extension, written as a method
|
|
2083
|
# Proposed popitem() extension, written as a method
|
|
2068
|
|
|
2084
|
|
|
2069
|
|
|
2085
|
|
|
2070
|
class NotGiven: pass
|
|
2086
|
class NotGiven: pass
|
|
2071
|
|
|
2087
|
|
|
2072
|
def popkey(dct,key,default=NotGiven):
|
|
2088
|
def popkey(dct,key,default=NotGiven):
|
|
2073
|
"""Return dct[key] and delete dct[key].
|
|
2089
|
"""Return dct[key] and delete dct[key].
|
|
2074
|
|
|
2090
|
|
|
2075
|
If default is given, return it if dct[key] doesn't exist, otherwise raise
|
|
2091
|
If default is given, return it if dct[key] doesn't exist, otherwise raise
|
|
2076
|
KeyError. """
|
|
2092
|
KeyError. """
|
|
2077
|
|
|
2093
|
|
|
2078
|
try:
|
|
2094
|
try:
|
|
2079
|
val = dct[key]
|
|
2095
|
val = dct[key]
|
|
2080
|
except KeyError:
|
|
2096
|
except KeyError:
|
|
2081
|
if default is NotGiven:
|
|
2097
|
if default is NotGiven:
|
|
2082
|
raise
|
|
2098
|
raise
|
|
2083
|
else:
|
|
2099
|
else:
|
|
2084
|
return default
|
|
2100
|
return default
|
|
2085
|
else:
|
|
2101
|
else:
|
|
2086
|
del dct[key]
|
|
2102
|
del dct[key]
|
|
2087
|
return val
|
|
2103
|
return val
|
|
2088
|
|
|
2104
|
|
|
2089
|
def wrap_deprecated(func, suggest = '<nothing>'):
|
|
2105
|
def wrap_deprecated(func, suggest = '<nothing>'):
|
|
2090
|
def newFunc(*args, **kwargs):
|
|
2106
|
def newFunc(*args, **kwargs):
|
|
2091
|
warnings.warn("Call to deprecated function %s, use %s instead" %
|
|
2107
|
warnings.warn("Call to deprecated function %s, use %s instead" %
|
|
2092
|
( func.__name__, suggest),
|
|
2108
|
( func.__name__, suggest),
|
|
2093
|
category=DeprecationWarning,
|
|
2109
|
category=DeprecationWarning,
|
|
2094
|
stacklevel = 2)
|
|
2110
|
stacklevel = 2)
|
|
2095
|
return func(*args, **kwargs)
|
|
2111
|
return func(*args, **kwargs)
|
|
2096
|
return newFunc
|
|
2112
|
return newFunc
|
|
2097
|
|
|
2113
|
|
|
2098
|
|
|
2114
|
|
|
2099
|
def _num_cpus_unix():
|
|
2115
|
def _num_cpus_unix():
|
|
2100
|
"""Return the number of active CPUs on a Unix system."""
|
|
2116
|
"""Return the number of active CPUs on a Unix system."""
|
|
2101
|
return os.sysconf("SC_NPROCESSORS_ONLN")
|
|
2117
|
return os.sysconf("SC_NPROCESSORS_ONLN")
|
|
2102
|
|
|
2118
|
|
|
2103
|
|
|
2119
|
|
|
2104
|
def _num_cpus_darwin():
|
|
2120
|
def _num_cpus_darwin():
|
|
2105
|
"""Return the number of active CPUs on a Darwin system."""
|
|
2121
|
"""Return the number of active CPUs on a Darwin system."""
|
|
2106
|
p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
|
|
2122
|
p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
|
|
2107
|
return p.stdout.read()
|
|
2123
|
return p.stdout.read()
|
|
2108
|
|
|
2124
|
|
|
2109
|
|
|
2125
|
|
|
2110
|
def _num_cpus_windows():
|
|
2126
|
def _num_cpus_windows():
|
|
2111
|
"""Return the number of active CPUs on a Windows system."""
|
|
2127
|
"""Return the number of active CPUs on a Windows system."""
|
|
2112
|
return os.environ.get("NUMBER_OF_PROCESSORS")
|
|
2128
|
return os.environ.get("NUMBER_OF_PROCESSORS")
|
|
2113
|
|
|
2129
|
|
|
2114
|
|
|
2130
|
|
|
2115
|
def num_cpus():
|
|
2131
|
def num_cpus():
|
|
2116
|
"""Return the effective number of CPUs in the system as an integer.
|
|
2132
|
"""Return the effective number of CPUs in the system as an integer.
|
|
2117
|
|
|
2133
|
|
|
2118
|
This cross-platform function makes an attempt at finding the total number of
|
|
2134
|
This cross-platform function makes an attempt at finding the total number of
|
|
2119
|
available CPUs in the system, as returned by various underlying system and
|
|
2135
|
available CPUs in the system, as returned by various underlying system and
|
|
2120
|
python calls.
|
|
2136
|
python calls.
|
|
2121
|
|
|
2137
|
|
|
2122
|
If it can't find a sensible answer, it returns 1 (though an error *may* make
|
|
2138
|
If it can't find a sensible answer, it returns 1 (though an error *may* make
|
|
2123
|
it return a large positive number that's actually incorrect).
|
|
2139
|
it return a large positive number that's actually incorrect).
|
|
2124
|
"""
|
|
2140
|
"""
|
|
2125
|
|
|
2141
|
|
|
2126
|
# Many thanks to the Parallel Python project (http://www.parallelpython.com)
|
|
2142
|
# Many thanks to the Parallel Python project (http://www.parallelpython.com)
|
|
2127
|
# for the names of the keys we needed to look up for this function. This
|
|
2143
|
# for the names of the keys we needed to look up for this function. This
|
|
2128
|
# code was inspired by their equivalent function.
|
|
2144
|
# code was inspired by their equivalent function.
|
|
2129
|
|
|
2145
|
|
|
2130
|
ncpufuncs = {'Linux':_num_cpus_unix,
|
|
2146
|
ncpufuncs = {'Linux':_num_cpus_unix,
|
|
2131
|
'Darwin':_num_cpus_darwin,
|
|
2147
|
'Darwin':_num_cpus_darwin,
|
|
2132
|
'Windows':_num_cpus_windows,
|
|
2148
|
'Windows':_num_cpus_windows,
|
|
2133
|
# On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
|
|
2149
|
# On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
|
|
2134
|
# See http://bugs.python.org/issue1082 for details.
|
|
2150
|
# See http://bugs.python.org/issue1082 for details.
|
|
2135
|
'Microsoft':_num_cpus_windows,
|
|
2151
|
'Microsoft':_num_cpus_windows,
|
|
2136
|
}
|
|
2152
|
}
|
|
2137
|
|
|
2153
|
|
|
2138
|
ncpufunc = ncpufuncs.get(platform.system(),
|
|
2154
|
ncpufunc = ncpufuncs.get(platform.system(),
|
|
2139
|
# default to unix version (Solaris, AIX, etc)
|
|
2155
|
# default to unix version (Solaris, AIX, etc)
|
|
2140
|
_num_cpus_unix)
|
|
2156
|
_num_cpus_unix)
|
|
2141
|
|
|
2157
|
|
|
2142
|
try:
|
|
2158
|
try:
|
|
2143
|
ncpus = max(1,int(ncpufunc()))
|
|
2159
|
ncpus = max(1,int(ncpufunc()))
|
|
2144
|
except:
|
|
2160
|
except:
|
|
2145
|
ncpus = 1
|
|
2161
|
ncpus = 1
|
|
2146
|
return ncpus
|
|
2162
|
return ncpus
|
|
2147
|
|
|
2163
|
|
|
2148
|
#*************************** end of file <genutils.py> **********************
|
|
2164
|
#*************************** end of file <genutils.py> **********************
|