1 from __future__
import with_statement
2 import datetime
, thread
, threading
, struct
, os
, sys
6 with
open("fcgi.log","a") as f
:
11 log("%s %s %s: %s" % (str(datetime
.datetime
.now()), pad(thread
.get_ident(),5), self
.__class
__.__name
__, msg
))
13 def ellipsis(text
,maxlen
,endsize
=7):
14 """ ellipsis is a helper function
15 It grabs a little off both ends and puts an ellipsis in the middle.
17 >>> ellipsis("1234567890_2_4_6_8_01_3_5_7_9_", 20)
19 >>> ellipsis("1234567890", 8, 2)
21 >>> len(ellipsis("1234567890", 8, 2))
25 if type(text
) not in (str,unicode):
27 assert type(text
) in (str, unicode)
28 if len(text
) <= maxlen
:
31 return text
[0:maxlen
-3]+"..."
32 return text
[0:maxlen
-(endsize
+3)]+"..."+text
[-endsize
:]
34 def pad(s
,min,char
=' '):
37 return s
+ (char
* (min - len(s
)))
39 def ms_elapsed(since
):
40 d
= (datetime
.datetime
.now() - since
)
41 return (d
.seconds
*1000.0) + (d
.microseconds
/ 1000.0)
43 class NiceThread(threading
.Thread
):
45 threading
.Thread
.__init
__(self
)
48 def please_stop(self
):
55 pass # override this in a subclass
57 pass # override this in a subclass
59 class FastCGIPairs(Loggable
):
60 """ FastCGI uses a unique pair encoding:
61 <1-byte length><1-byte length><name><value>
63 def __init__(self
, s
):
65 self
._i
= -1 # this is the counter if this object is used as an iterator
68 # dont forget to follow logic from the spec: Lengths of 127 bytes and less can be encoded in one byte, while longer lengths are always encoded in four bytes
69 name_len
= struct
.unpack("!B",s
[0])[0]
70 if name_len
>> 7 == 1:
71 name_len
= struct
.unpack("!L",s
[0:4])[0]
77 value_len
= struct
.unpack("!B",s
[0])[0]
78 if value_len
>> 7 == 1: # if the 4-byte marker is set
79 value_len
= struct
.unpack("!L", s
[0:4])[0] # then get its long value
80 value_len
&= 0x7FFFFF # clear the marker bit
86 value
= s
[0:value_len
]
88 self
.pairs
.append( (name
,value
) )
90 self
.pairs
.append(pair
)
104 ret
+= struct
.pack("!"+pa
+pb
, a
, b
)
112 if self
._i
>= len(self
.pairs
):
114 raise StopIteration()
115 return self
.pairs
[self
._i
]
118 """ Returns a generator that iterates depth-first through 'gen', a potentially nested generator.
120 All the generators throughout the flatten() process are allowed to yield lists, tuples, simple values, or other generators.
122 Simples values flatten() to str() of themselves.
124 The other value types (list,tuple,generator) will recurse and flatten their contents.
127 ... for c in ('f','o','o'):
131 ... for c in ('b','a','r'):
135 ... yield [foo(),bar()]
137 >>> list(flatten(gen))
138 ['f', 'o', 'o', 'b', 'a', 'r']
145 ... yield [foo(), bad()]
147 >>> list(flatten(gen()))
148 Traceback (most recent call last):
150 GeneratorException: Caused by:
151 <type 'exceptions.ZeroDivisionError'> integer division or modulo by zero
153 ('generator', ['gen', '<doctest __main__.flatten[5]>', 1]):
155 ('generator', ['bad', '<doctest __main__.flatten[4]>', 1]):
160 stack
= '(not-yet-defined)'
161 if type(gen
) in (str, unicode):
163 elif type(gen
).__name
__ == 'function':
164 stack
= ('function',gen
.__name
__)
165 for i
in flatten(gen()):
167 elif type(gen
) in (list,tuple):
168 for i
in range(len(gen
)):
170 for j
in flatten(gen
[i
]):
172 elif type(gen
).__name
__ == 'generator':
173 stack
= ('generator', [gen
.gi_frame
.f_code
.co_name
, gen
.gi_frame
.f_code
.co_filename
.split(os
.path
.sep
)[-1], gen
.gi_frame
.f_lineno
])
181 (a
,b
,c
) = sys
.exc_info()
182 raise GeneratorException(b
, c
, stack
)
184 class GeneratorException(Exception):
185 def __init__(self
, error
, tb
=None, stack
=[]):
187 if hasattr(t
, "__name__") and t
.__name
__ == 'GeneratorException':
188 self
.error
= error
.error
189 self
.stack
= stack
+ (error
.stack
,)
206 def unroll_stack(stack
,n
=0):
209 + str(stack
[:2])+":\n" \
210 + (unroll_stack(stack
[2],n
+1) if len(stack
) > 2 else '')
211 return "Caused by:\n%s %s\nStack:\n%s\nTB:%s\n" \
212 % (str(type(self
.error
)),
214 unroll_stack(self
.stack
),
217 if __name__
== '__main__':