Contact: fumanchu@aminus.org

Log in as guest/misc to create tickets

root/reftree.py

Revision 113 (checked in by fumanchu, 2 years ago)

Dowser: updated to use reftree.

  • Property svn:eol-style set to native
Line 
1
2 import gc
3 import sys
4
5 from types import FrameType
6
7
8 class Tree:
9    
10     def __init__(self, obj):
11         self.obj = obj
12         self.filename = sys._getframe().f_code.co_filename
13         self._ignore = {}
14    
15     def ignore(self, *objects):
16         for obj in objects:
17             self._ignore[id(obj)] = None
18    
19     def ignore_caller(self):
20         f = sys._getframe()     # = this function
21         cur = f.f_back          # = the function that called us (probably 'walk')
22         self.ignore(cur, cur.f_builtins, cur.f_locals, cur.f_globals)
23         caller = f.f_back       # = the 'real' caller
24         self.ignore(caller, caller.f_builtins, caller.f_locals, caller.f_globals)
25    
26     def walk(self, maxresults=100, maxdepth=None):
27         """Walk the object tree, ignoring duplicates and circular refs."""
28         self.seen = {}
29         self.ignore(self, self.__dict__, self.obj, self.seen, self._ignore)
30        
31         # Ignore the calling frame, its builtins, globals and locals
32         self.ignore_caller()
33        
34         self.maxdepth = maxdepth
35         count = 0
36         for result in self._gen(self.obj):
37             yield result
38             count += 1
39             if maxresults and count >= maxresults:
40                 yield 0, 0, "==== Max results reached ===="
41                 raise StopIteration
42    
43     def print_tree(self, maxresults=100, maxdepth=None):
44         """Walk the object tree, pretty-printing each branch."""
45         self.ignore_caller()
46         for depth, refid, rep in self.walk(maxresults, maxdepth):
47             print ("%9d" % refid), (" " * depth * 2), rep
48
49
50 def _repr_container(obj):
51     return "%s of len %s: %r" % (type(obj).__name__, len(obj), obj)
52 repr_dict = _repr_container
53 repr_set = _repr_container
54 repr_list = _repr_container
55 repr_tuple = _repr_container
56
57 def repr_str(obj):
58     return "%s of len %s: %r" % (type(obj).__name__, len(obj), obj)
59 repr_unicode = repr_str
60
61 def repr_frame(obj):
62     return "frame from %s line %s" % (obj.f_code.co_filename, obj.f_lineno)
63
64 def get_repr(obj, limit=250):
65     typename = getattr(type(obj), "__name__", None)
66     handler = globals().get("repr_%s" % typename, repr)
67    
68     try:
69         result = handler(obj)
70     except:
71         result = "unrepresentable object: %r" % sys.exc_info()[1]
72    
73     if len(result) > limit:
74         result = result[:limit] + "..."
75    
76     return result
77
78
79 class ReferentTree(Tree):
80    
81     def _gen(self, obj, depth=0):
82         if self.maxdepth and depth >= self.maxdepth:
83             yield depth, 0, "---- Max depth reached ----"
84             raise StopIteration
85        
86         for ref in gc.get_referents(obj):
87             if id(ref) in self._ignore:
88                 continue
89             elif id(ref) in self.seen:
90                 yield depth, id(ref), "!" + get_repr(ref)
91                 continue
92             else:
93                 self.seen[id(ref)] = None
94                 yield depth, id(ref), get_repr(ref)
95            
96             for child in self._gen(ref, depth + 1):
97                 yield child
98
99
100 class ReferrerTree(Tree):
101    
102     def _gen(self, obj, depth=0):
103         if self.maxdepth and depth >= self.maxdepth:
104             yield depth, 0, "---- Max depth reached ----"
105             raise StopIteration
106        
107         refs = gc.get_referrers(obj)
108         refiter = iter(refs)
109         self.ignore(refs, refiter)
110         for ref in refiter:
111             # Exclude all frames that are from this module.
112             if isinstance(ref, FrameType):
113                 if ref.f_code.co_filename == self.filename:
114                     continue
115            
116             if id(ref) in self._ignore:
117                 continue
118             elif id(ref) in self.seen:
119                 yield depth, id(ref), "!" + get_repr(ref)
120                 continue
121             else:
122                 self.seen[id(ref)] = None
123                 yield depth, id(ref), get_repr(ref)
124            
125             for parent in self._gen(ref, depth + 1):
126                 yield parent
127
128
129
130 class CircularReferents(Tree):
131    
132     def walk(self, maxresults=100, maxdepth=None):
133         """Walk the object tree, showing circular referents."""
134         self.stops = 0
135         self.seen = {}
136         self.ignore(self, self.__dict__, self.seen, self._ignore)
137        
138         # Ignore the calling frame, its builtins, globals and locals
139         self.ignore_caller()
140        
141         self.maxdepth = maxdepth
142         count = 0
143         for result in self._gen(self.obj):
144             yield result
145             count += 1
146             if maxresults and count >= maxresults:
147                 yield 0, 0, "==== Max results reached ===="
148                 raise StopIteration
149    
150     def _gen(self, obj, depth=0, trail=None):
151         if self.maxdepth and depth >= self.maxdepth:
152             self.stops += 1
153             raise StopIteration
154        
155         if trail is None:
156             trail = []
157        
158         for ref in gc.get_referents(obj):
159             if id(ref) in self._ignore:
160                 continue
161             elif id(ref) in self.seen:
162                 continue
163             else:
164                 self.seen[id(ref)] = None
165            
166             refrepr = get_repr(ref)
167             if id(ref) == id(self.obj):
168                 yield trail + [refrepr,]
169            
170             for child in self._gen(ref, depth + 1, trail + [refrepr,]):
171                 yield child
172    
173     def print_tree(self, maxresults=100, maxdepth=None):
174         """Walk the object tree, pretty-printing each branch."""
175         self.ignore_caller()
176         for trail in self.walk(maxresults, maxdepth):
177             print trail
178         if self.stops:
179             print "%s paths stopped because max depth reached" % self.stops
180
181
182 def count_objects():
183     d = {}
184     for obj in gc.get_objects():
185         objtype = type(obj)
186         d[objtype] = d.get(objtype, 0) + 1
187     d = [(v, k) for k, v in d.iteritems()]
188     d.sort()
189     return d
190
Note: See TracBrowser for help on using the browser.