0
|
1 """Collected utility functions, many are taken from Drew's utils.py in
|
|
2 Cuisine CVS and Hiss's Utility.py."""
|
|
3
|
|
4 from __future__ import generators
|
|
5 import sys
|
|
6
|
|
7 __author__ = "David McClosky <dmcc@bigasterisk.com>, " + \
|
|
8 "Drew Perttula <drewp@bigasterisk.com>"
|
|
9 __cvsid__ = "$Id: TLUtility.py,v 1.1 2003/05/25 08:25:35 dmcc Exp $"
|
|
10 __version__ = "$Revision: 1.1 $"[11:-2]
|
|
11
|
|
12 def make_attributes_from_args(*argnames):
|
|
13 """
|
|
14 This function simulates the effect of running
|
|
15 self.foo=foo
|
|
16 for each of the given argument names ('foo' in the example just
|
|
17 now). Now you can write:
|
|
18 def __init__(self,foo,bar,baz):
|
|
19 copy_to_attributes('foo','bar','baz')
|
|
20 ...
|
|
21 instead of:
|
|
22 def __init__(self,foo,bar,baz):
|
|
23 self.foo=foo
|
|
24 self.bar=bar
|
|
25 self.baz=baz
|
|
26 ...
|
|
27 """
|
|
28
|
|
29 callerlocals=sys._getframe(1).f_locals
|
|
30 callerself=callerlocals['self']
|
|
31 for a in argnames:
|
|
32 try:
|
|
33 setattr(callerself,a,callerlocals[a])
|
|
34 except KeyError:
|
|
35 raise KeyError, "Function has no argument '%s'" % a
|
|
36
|
|
37 def enumerate(*collections):
|
|
38 """Generates an indexed series: (0,coll[0]), (1,coll[1]) ...
|
|
39
|
|
40 this is a multi-list version of the code from the PEP:
|
|
41 enumerate(a,b) gives (0,a[0],b[0]), (1,a[1],b[1]) ...
|
|
42 """
|
|
43 i = 0
|
|
44 iters = [iter(collection) for collection in collections]
|
|
45 while 1:
|
|
46 yield [i,] + [iterator.next() for iterator in iters]
|
|
47 i += 1
|
|
48
|
|
49 def dumpobj(o):
|
|
50 """Prints all the object's non-callable attributes"""
|
|
51 print repr(o)
|
|
52 for a in [x for x in dir(o) if not callable(getattr(o, x))]:
|
|
53 try:
|
|
54 print " %20s: %s " % (a, getattr(o, a))
|
|
55 except:
|
|
56 pass
|
|
57 print ""
|
|
58
|
|
59 def dict_filter_update(d, **newitems):
|
|
60 """Adds a set of new keys and values to dictionary 'd' if the values are
|
|
61 true:
|
|
62
|
|
63 >>> some_dict = {}
|
|
64 >>> dict_filter_update(some_dict, a=None, b=0, c=1, e={}, s='hello')
|
|
65 >>> some_dict
|
|
66 {'c': 1, 's': 'hello'}
|
|
67 """
|
|
68 for k, v in newitems.items():
|
|
69 if v: d[k] = v
|
|
70
|
|
71 def try_get_logger(channel):
|
|
72 """Tries to get a logger with the channel 'channel'. Will return a
|
|
73 silent DummyClass if logging is not available."""
|
|
74 try:
|
|
75 import logging
|
|
76 log = logging.getLogger(channel)
|
|
77 except ImportError:
|
|
78 log = DummyClass()
|
|
79 return log
|
|
80
|
|
81 class DummyClass:
|
|
82 """A class that can be instantiated but never used. It is intended to
|
|
83 be replaced when information is available.
|
|
84
|
|
85 Usage:
|
|
86 >>> d = DummyClass(1, 2, x="xyzzy")
|
|
87 >>> d.someattr
|
|
88 Traceback (most recent call last):
|
|
89 File "<stdin>", line 1, in ?
|
|
90 File "Utility.py", line 33, in __getattr__
|
|
91 raise AttributeError, "Attempted usage of a DummyClass: %s" % key
|
|
92 AttributeError: Attempted usage of a DummyClass: someattr
|
|
93 >>> d.somefunction()
|
|
94 Traceback (most recent call last):
|
|
95 File "<stdin>", line 1, in ?
|
|
96 File "Utility.py", line 33, in __getattr__
|
|
97 raise AttributeError, "Attempted usage of a DummyClass: %s" % key
|
|
98 AttributeError: Attempted usage of a DummyClass: somefunction"""
|
|
99 def __init__(self, use_warnings=1, raise_exceptions=0, **kw):
|
|
100 """Constructs a DummyClass"""
|
|
101 make_attributes_from_args('use_warnings', 'raise_exceptions')
|
|
102 def __getattr__(self, key):
|
|
103 """Raises an exception to warn the user that a Dummy is not being
|
|
104 replaced in time."""
|
|
105 if key == "__del__":
|
|
106 return
|
|
107 msg = "Attempted usage of '%s' on a DummyClass" % key
|
|
108 if self.use_warnings:
|
|
109 import warnings
|
|
110 warnings.warn(msg)
|
|
111 if self.raise_exceptions:
|
|
112 raise AttributeError, msg
|
|
113 return lambda *args, **kw: self.bogus_function()
|
|
114 def bogus_function(self):
|
|
115 pass
|
|
116
|
|
117 class ClassyDict(dict):
|
|
118 """A dict that accepts attribute-style access as well (for keys
|
|
119 that are legal names, obviously). I used to call this Struct, but
|
|
120 chose the more colorful name to avoid confusion with the struct
|
|
121 module."""
|
|
122 def __getattr__(self, a):
|
|
123 return self[a]
|
|
124 def __setattr__(self, a, v):
|
|
125 self[a] = v
|
|
126 def __delattr__(self, a):
|
|
127 del self[a]
|
|
128
|
|
129 def trace(func):
|
|
130 """Good old fashioned Lisp-style tracing. Example usage:
|
|
131
|
|
132 >>> def f(a, b, c=3):
|
|
133 >>> print a, b, c
|
|
134 >>> return a + b
|
|
135 >>>
|
|
136 >>>
|
|
137 >>> f = trace(f)
|
|
138 >>> f(1, 2)
|
|
139 |>> f called args: [1, 2]
|
|
140 1 2 3
|
|
141 <<| f returned 3
|
|
142 3
|
|
143
|
|
144 TODO: print out default keywords (maybe)
|
|
145 indent for recursive call like the lisp version (possible use of
|
|
146 generators?)"""
|
|
147 name = func.func_name
|
|
148 def tracer(*args, **kw):
|
|
149 s = '|>> %s called' % name
|
|
150 if args:
|
|
151 s += ' args: %r' % list(args)
|
|
152 if kw:
|
|
153 s += ' kw: %r' % kw
|
|
154 print s
|
|
155 ret = func(*args, **kw)
|
|
156 print '<<| %s returned %s' % (name, ret)
|
|
157 return ret
|
|
158 return tracer
|
|
159
|
|
160 # these functions taken from old light8 code
|
|
161 def dict_max(*dicts):
|
|
162 """
|
|
163 ({'a' : 5, 'b' : 9}, {'a' : 10, 'b' : 4})
|
|
164 returns ==> {'a' : 10, 'b' : 9}
|
|
165 """
|
|
166 newdict = {}
|
|
167 for d in dicts:
|
|
168 for k,v in d.items():
|
|
169 newdict[k] = max(v, newdict.get(k, 0))
|
|
170 return newdict
|
|
171
|
|
172 def dict_scale(d,scl):
|
|
173 """scales all values in dict and returns a new dict"""
|
|
174 return dict([(k,v*scl) for k,v in d.items()])
|
|
175
|
|
176 def dict_subset(d, dkeys, default=0):
|
|
177 """Subset of dictionary d: only the keys in dkeys. If you plan on omitting
|
|
178 keys, make sure you like the default."""
|
|
179 newd = {} # dirty variables!
|
|
180 for k in dkeys:
|
|
181 newd[k] = d.get(k, default)
|
|
182 return newd
|
|
183
|
|
184 # functions specific to Timeline
|
|
185 # TBD
|
|
186 def last_less_than(array, x):
|
|
187 """array must be sorted"""
|
|
188 best = None
|
|
189 for elt in array:
|
|
190 if elt <= x:
|
|
191 best = elt
|
|
192 elif best is not None:
|
|
193 return best
|
|
194 return best
|
|
195
|
|
196 # TBD
|
|
197 def first_greater_than(array, x):
|
|
198 """array must be sorted"""
|
|
199 array_rev = array[:]
|
|
200 array_rev.reverse()
|
|
201 best = None
|
|
202 for elt in array_rev:
|
|
203 if elt >= x:
|
|
204 best = elt
|
|
205 elif best is not None:
|
|
206 return best
|
|
207 return best
|
|
208
|
|
209
|