1+ from __future__ import absolute_import
12import cgi
23import gc
34import os
45localDir = os .path .join (os .getcwd (), os .path .dirname (__file__ ))
5- from StringIO import StringIO
6+ from io import BytesIO
67import sys
78import threading
89import time
1314
1415import cherrypy
1516
16- import reftree
17+ from . import reftree
1718
1819
20+ from six import iteritems
21+
1922def get_repr (obj , limit = 250 ):
2023 return cgi .escape (reftree .get_repr (obj , limit ))
2124
@@ -44,62 +47,62 @@ def template(name, **params):
4447
4548
4649class Root :
47-
50+
4851 period = 5
4952 maxhistory = 300
50-
53+
5154 def __init__ (self ):
5255 self .history = {}
5356 self .samples = 0
5457 if cherrypy .__version__ >= '3.1' :
5558 cherrypy .engine .subscribe ('exit' , self .stop )
5659 self .runthread = threading .Thread (target = self .start )
5760 self .runthread .start ()
58-
61+
5962 def start (self ):
6063 self .running = True
6164 while self .running :
6265 self .tick ()
6366 time .sleep (self .period )
64-
67+
6568 def tick (self ):
6669 gc .collect ()
67-
70+
6871 typecounts = {}
6972 for obj in gc .get_objects ():
7073 objtype = type (obj )
7174 if objtype in typecounts :
7275 typecounts [objtype ] += 1
7376 else :
7477 typecounts [objtype ] = 1
75-
76- for objtype , count in typecounts . iteritems ():
78+
79+ for objtype , count in iteritems (typecounts ):
7780 typename = objtype .__module__ + "." + objtype .__name__
7881 if typename not in self .history :
7982 self .history [typename ] = [0 ] * self .samples
8083 self .history [typename ].append (count )
81-
84+
8285 samples = self .samples + 1
83-
86+
8487 # Add dummy entries for any types which no longer exist
85- for typename , hist in self .history . iteritems ( ):
88+ for typename , hist in iteritems ( self .history ):
8689 diff = samples - len (hist )
8790 if diff > 0 :
8891 hist .extend ([0 ] * diff )
89-
92+
9093 # Truncate history to self.maxhistory
9194 if samples > self .maxhistory :
92- for typename , hist in self .history . iteritems ( ):
95+ for typename , hist in iteritems ( self .history ):
9396 hist .pop (0 )
9497 else :
9598 self .samples = samples
96-
99+
97100 def stop (self ):
98101 self .running = False
99-
102+
100103 def index (self , floor = 0 ):
101104 rows = []
102- typenames = self .history .keys ()
105+ typenames = list ( self .history .keys () )
103106 typenames .sort ()
104107 for typename in typenames :
105108 hist = self .history [typename ]
@@ -117,7 +120,7 @@ def index(self, floor=0):
117120 rows .append (row )
118121 return template ("graphs.html" , output = "\n " .join (rows ))
119122 index .exposed = True
120-
123+
121124 def chart (self , typename ):
122125 """Return a sparkline chart of the given type."""
123126 data = self .history [typename ]
@@ -128,28 +131,28 @@ def chart(self, typename):
128131 draw .line ([(i , int (height - (v * scale ))) for i , v in enumerate (data )],
129132 fill = "#009900" )
130133 del draw
131-
132- f = StringIO ()
134+
135+ f = BytesIO ()
133136 im .save (f , "PNG" )
134137 result = f .getvalue ()
135-
138+
136139 cherrypy .response .headers ["Content-Type" ] = "image/png"
137140 return result
138141 chart .exposed = True
139-
142+
140143 def trace (self , typename , objid = None ):
141144 gc .collect ()
142-
145+
143146 if objid is None :
144147 rows = self .trace_all (typename )
145148 else :
146149 rows = self .trace_one (typename , objid )
147-
150+
148151 return template ("trace.html" , output = "\n " .join (rows ),
149152 typename = cgi .escape (typename ),
150153 objid = str (objid or '' ))
151154 trace .exposed = True
152-
155+
153156 def trace_all (self , typename ):
154157 rows = []
155158 for obj in gc .get_objects ():
@@ -160,7 +163,7 @@ def trace_all(self, typename):
160163 if not rows :
161164 rows = ["<h3>The type you requested was not found.</h3>" ]
162165 return rows
163-
166+
164167 def trace_one (self , typename , objid ):
165168 rows = []
166169 objid = int (objid )
@@ -181,7 +184,7 @@ def trace_one(self, typename, objid):
181184 (k , get_repr (v )))
182185 del v
183186 rows .append ('</div>' )
184-
187+
185188 # Referrers
186189 rows .append ('<div class="refs"><h3>Referrers (Parents)</h3>' )
187190 rows .append ('<p class="desc"><a href="%s">Show the '
@@ -193,7 +196,7 @@ def trace_one(self, typename, objid):
193196 if parentid :
194197 rows .append ("<p class='obj'>%s</p>" % parentrepr )
195198 rows .append ('</div>' )
196-
199+
197200 # Referents
198201 rows .append ('<div class="refs"><h3>Referents (Children)</h3>' )
199202 for child in gc .get_referents (obj ):
@@ -203,10 +206,10 @@ def trace_one(self, typename, objid):
203206 if not rows :
204207 rows = ["<h3>The object you requested was not found.</h3>" ]
205208 return rows
206-
209+
207210 def tree (self , typename , objid ):
208211 gc .collect ()
209-
212+
210213 rows = []
211214 objid = int (objid )
212215 all_objs = gc .get_objects ()
@@ -218,17 +221,17 @@ def tree(self, typename, objid):
218221 "of the correct type.</h3>" ]
219222 else :
220223 rows .append ('<div class="obj">' )
221-
224+
222225 tree = ReferrerTree (obj )
223226 tree .ignore (all_objs )
224227 for depth , parentid , parentrepr in tree .walk (maxresults = 1000 ):
225228 rows .append (parentrepr )
226-
229+
227230 rows .append ('</div>' )
228231 break
229232 if not rows :
230233 rows = ["<h3>The object you requested was not found.</h3>" ]
231-
234+
232235 params = {'output' : "\n " .join (rows ),
233236 'typename' : cgi .escape (typename ),
234237 'objid' : str (objid ),
@@ -254,17 +257,17 @@ def tree(self, typename, objid):
254257
255258
256259class ReferrerTree (reftree .Tree ):
257-
260+
258261 ignore_modules = True
259-
262+
260263 def _gen (self , obj , depth = 0 ):
261264 if self .maxdepth and depth >= self .maxdepth :
262265 yield depth , 0 , "---- Max depth reached ----"
263266 raise StopIteration
264-
267+
265268 if isinstance (obj , ModuleType ) and self .ignore_modules :
266269 raise StopIteration
267-
270+
268271 refs = gc .get_referrers (obj )
269272 refiter = iter (refs )
270273 self .ignore (refs , refiter )
@@ -274,38 +277,38 @@ def _gen(self, obj, depth=0):
274277 if (isinstance (ref , FrameType )
275278 and ref .f_code .co_filename in (thisfile , self .filename )):
276279 continue
277-
280+
278281 # Exclude all functions and classes from this module or reftree.
279282 mod = getattr (ref , "__module__" , "" )
280283 if "dowser" in mod or "reftree" in mod or mod == '__main__' :
281284 continue
282-
285+
283286 # Exclude all parents in our ignore list.
284287 if id (ref ) in self ._ignore :
285288 continue
286-
289+
287290 # Yield the (depth, id, repr) of our object.
288291 yield depth , 0 , '%s<div class="branch">' % (" " * depth )
289292 if id (ref ) in self .seen :
290293 yield depth , id (ref ), "see %s above" % id (ref )
291294 else :
292295 self .seen [id (ref )] = None
293296 yield depth , id (ref ), self .get_repr (ref , obj )
294-
297+
295298 for parent in self ._gen (ref , depth + 1 ):
296299 yield parent
297300 yield depth , 0 , '%s</div>' % (" " * depth )
298-
301+
299302 def get_repr (self , obj , referent = None ):
300303 """Return an HTML tree block describing the given object."""
301304 objtype = type (obj )
302305 typename = objtype .__module__ + "." + objtype .__name__
303306 prettytype = typename .replace ("__builtin__." , "" )
304-
307+
305308 name = getattr (obj , "__name__" , "" )
306309 if name :
307310 prettytype = "%s %r" % (prettytype , name )
308-
311+
309312 key = ""
310313 if referent :
311314 key = self .get_refkey (obj , referent )
@@ -315,14 +318,14 @@ def get_repr(self, obj, referent=None):
315318 % (url ("/trace/%s/%s" % (typename , id (obj ))),
316319 id (obj ), prettytype , key , get_repr (obj , 100 ))
317320 )
318-
321+
319322 def get_refkey (self , obj , referent ):
320323 """Return the dict key or attribute name of obj which refers to referent."""
321324 if isinstance (obj , dict ):
322- for k , v in obj . iteritems ():
325+ for k , v in iteritems (obj ):
323326 if v is referent :
324327 return " (via its %r key)" % k
325-
328+
326329 for k in dir (obj ) + ['__dict__' ]:
327330 if getattr (obj , k , None ) is referent :
328331 return " (via its %r attribute)" % k
0 commit comments