blob: df07ddddbbe2b0b6897a76ee42cb9de70c65e471 [file] [log] [blame]
Fred Drakef0193242001-10-12 20:56:29 +00001import _hotshot
2import os.path
3import parser
4import symbol
5import sys
6
7from _hotshot import \
8 WHAT_ENTER, \
9 WHAT_EXIT, \
10 WHAT_LINENO, \
11 WHAT_DEFINE_FILE, \
Fred Draked5d5a042001-10-15 22:05:32 +000012 WHAT_DEFINE_FUNC, \
Fred Drakef0193242001-10-12 20:56:29 +000013 WHAT_ADD_INFO
14
15
16__all__ = ["LogReader", "ENTER", "EXIT", "LINE"]
17
18
19ENTER = WHAT_ENTER
20EXIT = WHAT_EXIT
21LINE = WHAT_LINENO
22
23
24try:
25 StopIteration
26except NameError:
27 StopIteration = IndexError
28
29
30class LogReader:
31 def __init__(self, logfn):
32 # fileno -> filename
33 self._filemap = {}
34 # (fileno, lineno) -> filename, funcname
35 self._funcmap = {}
36
37 self._info = {}
Fred Draked62f1512001-10-13 02:55:40 +000038 self._reader = _hotshot.logreader(logfn)
39 self._nextitem = self._reader.next
Fred Drakef0193242001-10-12 20:56:29 +000040 self._stack = []
41
42 # Iteration support:
43 # This adds an optional (& ignored) parameter to next() so that the
44 # same bound method can be used as the __getitem__() method -- this
45 # avoids using an additional method call which kills the performance.
46
47 def next(self, index=0):
Fred Draked5d5a042001-10-15 22:05:32 +000048 while 1:
Fred Drakef0193242001-10-12 20:56:29 +000049 try:
Fred Draked5d5a042001-10-15 22:05:32 +000050 what, tdelta, fileno, lineno = self._nextitem()
51 except TypeError:
52 # logreader().next() returns None at the end
53 self._reader.close()
54 raise StopIteration()
55 if what == WHAT_DEFINE_FILE:
56 self._filemap[fileno] = tdelta
57 continue
58 if what == WHAT_DEFINE_FUNC:
59 filename = self._filemap[fileno]
60 self._funcmap[(fileno, lineno)] = (filename, tdelta)
61 continue
62 if what == WHAT_ADD_INFO:
63 key = tdelta.lower()
64 try:
65 L = self._info[key]
66 except KeyError:
67 L = []
68 self._info[key] = L
69 L.append(lineno)
70 if key == "current-directory":
71 self.cwd = lineno
72 continue
73 if what == WHAT_ENTER:
74 t = self._decode_location(fileno, lineno)
75 filename, funcname = t
76 self._stack.append((filename, funcname, lineno))
77 elif what == WHAT_EXIT:
78 filename, funcname, lineno = self._stack.pop()
79 else:
80 filename, funcname, firstlineno = self._stack[-1]
81 return what, (filename, lineno, funcname), tdelta
Fred Drakef0193242001-10-12 20:56:29 +000082
83 if sys.version < "2.2":
84 # Don't add this for newer Python versions; we only want iteration
85 # support, not general sequence support.
86 __getitem__ = next
87 else:
88 def __iter__(self):
89 return self
90
91 #
92 # helpers
93 #
94
95 def _decode_location(self, fileno, lineno):
96 try:
97 return self._funcmap[(fileno, lineno)]
98 except KeyError:
Fred Draked5d5a042001-10-15 22:05:32 +000099 #
100 # This should only be needed when the log file does not
101 # contain all the DEFINE_FUNC records needed to allow the
102 # function name to be retrieved from the log file.
103 #
Fred Drakef0193242001-10-12 20:56:29 +0000104 if self._loadfile(fileno):
105 filename = funcname = None
106 try:
107 filename, funcname = self._funcmap[(fileno, lineno)]
108 except KeyError:
109 filename = self._filemap.get(fileno)
110 funcname = None
111 self._funcmap[(fileno, lineno)] = (filename, funcname)
112 return filename, funcname
113
114 def _loadfile(self, fileno):
115 try:
116 filename = self._filemap[fileno]
117 except KeyError:
118 print "Could not identify fileId", fileno
119 return 1
120 if filename is None:
121 return 1
122 absname = os.path.normcase(os.path.join(self.cwd, filename))
123
124 try:
125 fp = open(absname)
126 except IOError:
127 return
128 st = parser.suite(fp.read())
129 fp.close()
130
131 # Scan the tree looking for def and lambda nodes, filling in
132 # self._funcmap with all the available information.
133 funcdef = symbol.funcdef
134 lambdef = symbol.lambdef
135
136 stack = [st.totuple(1)]
137
138 while stack:
139 tree = stack.pop()
140 try:
141 sym = tree[0]
142 except (IndexError, TypeError):
143 continue
144 if sym == funcdef:
145 self._funcmap[(fileno, tree[2][2])] = filename, tree[2][1]
146 elif sym == lambdef:
147 self._funcmap[(fileno, tree[1][2])] = filename, "<lambda>"
148 stack.extend(list(tree[1:]))