27 """ |
27 """ |
28 breaks = {} # indexed by (filename, lineno) tuple: Breakpoint |
28 breaks = {} # indexed by (filename, lineno) tuple: Breakpoint |
29 breakInFile = {} # indexed by filename: [lineno] |
29 breakInFile = {} # indexed by filename: [lineno] |
30 breakInFrameCache = {} |
30 breakInFrameCache = {} |
31 |
31 |
32 def __init__(self, filename, lineno, temporary=0, cond=None): |
32 def __init__(self, filename, lineno, temporary=False, cond=None): |
33 """ |
33 """ |
34 Constructor |
34 Constructor |
35 |
35 |
36 @param filename the filename where a breakpoint is set |
36 @param filename file name where a breakpoint is set |
37 @type str |
37 @type str |
38 @param lineno the line number of the breakpoint |
38 @param lineno line number of the breakpoint |
39 @type int |
39 @type int |
40 @keyparam temporary flag to indicate a temporary breakpoint |
40 @keyparam temporary flag to indicate a temporary breakpoint |
41 @type int |
41 @type bool |
42 @keyparam cond Python expression which dynamically enables this bp |
42 @keyparam cond Python expression which dynamically enables this bp |
43 @type str |
43 @type str |
44 """ |
44 """ |
45 filename = os.path.abspath(filename) |
45 filename = os.path.abspath(filename) |
46 self.file = filename |
46 self.file = filename |
47 self.line = lineno |
47 self.line = lineno |
48 self.temporary = temporary |
48 self.temporary = temporary |
49 self.cond = cond |
49 self.cond = cond |
50 self.enabled = 1 |
50 self.enabled = True |
51 self.ignore = 0 |
51 self.ignore = 0 |
52 self.hits = 0 |
52 self.hits = 0 |
53 self.breaks[filename, lineno] = self |
53 self.breaks[filename, lineno] = self |
54 lines = self.breakInFile.setdefault(filename, []) |
54 lines = self.breakInFile.setdefault(filename, []) |
55 if lineno not in lines: |
55 if lineno not in lines: |
70 |
70 |
71 def enable(self): |
71 def enable(self): |
72 """ |
72 """ |
73 Public method to enable this breakpoint. |
73 Public method to enable this breakpoint. |
74 """ |
74 """ |
75 self.enabled = 1 |
75 self.enabled = True |
76 |
76 |
77 def disable(self): |
77 def disable(self): |
78 """ |
78 """ |
79 Public method to disable this breakpoint. |
79 Public method to disable this breakpoint. |
80 """ |
80 """ |
81 self.enabled = 0 |
81 self.enabled = False |
82 |
82 |
83 @staticmethod |
83 @staticmethod |
84 def clear_break(filename, lineno): |
84 def clear_break(filename, lineno): |
85 """ |
85 """ |
86 Public method reimplemented from bdb.py to clear a breakpoint. |
86 Public method reimplemented from bdb.py to clear a breakpoint. |
87 |
87 |
88 @param filename the filename of the bp to retrieve |
88 @param filename file name of the bp to retrieve |
89 @type str |
89 @type str |
90 @param lineno the linenumber of the bp to retrieve |
90 @param lineno line number of the bp to retrieve |
91 @type int |
91 @type int |
92 """ |
92 """ |
93 bp = Breakpoint.breaks.get((filename, lineno)) |
93 bp = Breakpoint.breaks.get((filename, lineno)) |
94 if bp: |
94 if bp: |
95 bp.deleteMe() |
95 bp.deleteMe() |
110 Public method to get the breakpoint of a particular line. |
110 Public method to get the breakpoint of a particular line. |
111 |
111 |
112 Because eric6 supports only one breakpoint per line, this |
112 Because eric6 supports only one breakpoint per line, this |
113 method will return only one breakpoint. |
113 method will return only one breakpoint. |
114 |
114 |
115 @param filename the filename of the bp to retrieve |
115 @param filename file name of the bp to retrieve |
116 @type str |
116 @type str |
117 @param lineno the linenumber of the bp to retrieve |
117 @param lineno line number of the bp to retrieve |
118 @type int |
118 @type int |
119 @return Breakpoint or None, if there is no bp |
119 @return Breakpoint or None, if there is no bp |
120 @rtype Breakpoint object or None |
120 @rtype Breakpoint object or None |
121 """ |
121 """ |
122 return Breakpoint.breaks.get((filename, lineno)) |
122 return Breakpoint.breaks.get((filename, lineno)) |
129 |
129 |
130 Called only if we know there is a bpt at this |
130 Called only if we know there is a bpt at this |
131 location. Returns breakpoint that was triggered and a flag |
131 location. Returns breakpoint that was triggered and a flag |
132 that indicates if it is ok to delete a temporary bp. |
132 that indicates if it is ok to delete a temporary bp. |
133 |
133 |
134 @param filename the filename of the bp to retrieve |
134 @param filename file name of the bp to retrieve |
135 @type str |
135 @type str |
136 @param lineno the linenumber of the bp to retrieve |
136 @param lineno line number of the bp to retrieve |
137 @type int |
137 @type int |
138 @param frame the current execution frame |
138 @param frame the current execution frame |
139 @type frame object |
139 @type frame object |
140 @return tuple of Breakpoint and a flag to indicate, that a |
140 @return tuple of Breakpoint and a flag to indicate, that a |
141 temporary breakpoint may be deleted |
141 temporary breakpoint may be deleted |
142 @rtype tuple of Breakpoint, bool |
142 @rtype tuple of Breakpoint, bool |
143 """ |
143 """ |
144 b = Breakpoint.breaks[filename, lineno] |
144 b = Breakpoint.breaks[filename, lineno] |
145 if b.enabled == 0: |
145 if not b.enabled: |
146 return (None, 0) |
146 return (None, False) |
147 |
147 |
148 # Count every hit when bp is enabled |
148 # Count every hit when bp is enabled |
149 b.hits += 1 |
149 b.hits += 1 |
150 if not b.cond: |
150 if not b.cond: |
151 # If unconditional, and ignoring, |
151 # If unconditional, and ignoring, |
152 # go on to next, else break |
152 # go on to next, else break |
153 if b.ignore > 0: |
153 if b.ignore > 0: |
154 b.ignore -= 1 |
154 b.ignore -= 1 |
155 return (None, 0) |
155 return (None, False) |
156 else: |
156 else: |
157 # breakpoint and marker that's ok |
157 # breakpoint and marker that's ok |
158 # to delete if temporary |
158 # to delete if temporary |
159 return (b, 1) |
159 return (b, True) |
160 else: |
160 else: |
161 # Conditional bp. |
161 # Conditional bp. |
162 # Ignore count applies only to those bpt hits where the |
162 # Ignore count applies only to those bpt hits where the |
163 # condition evaluates to true. |
163 # condition evaluates to true. |
164 try: |
164 try: |
166 if val: |
166 if val: |
167 if b.ignore > 0: |
167 if b.ignore > 0: |
168 b.ignore -= 1 |
168 b.ignore -= 1 |
169 # continue |
169 # continue |
170 else: |
170 else: |
171 return (b, 1) |
171 return (b, True) |
172 # else: |
172 # else: |
173 # continue |
173 # continue |
174 except Exception: |
174 except Exception: |
175 # if eval fails, most conservative |
175 # if eval fails, most conservative |
176 # thing is to stop on breakpoint |
176 # thing is to stop on breakpoint |
177 # regardless of ignore count. |
177 # regardless of ignore count. |
178 # Don't delete temporary, |
178 # Don't delete temporary, |
179 # as another hint to user. |
179 # as another hint to user. |
180 return (b, 0) |
180 return (b, False) |
181 return (None, 0) |
181 return (None, False) |
182 |
182 |
183 |
183 |
184 class Watch: |
184 class Watch: |
185 """ |
185 """ |
186 Watch class. |
186 Watch class. |
188 Implements temporary watches, ignore counts, disabling and |
188 Implements temporary watches, ignore counts, disabling and |
189 (re)-enabling, and conditionals. |
189 (re)-enabling, and conditionals. |
190 """ |
190 """ |
191 watches = [] |
191 watches = [] |
192 |
192 |
193 def __init__(self, cond, compiledCond, flag, temporary=0): |
193 def __init__(self, cond, compiledCond, flag, temporary=False): |
194 """ |
194 """ |
195 Constructor |
195 Constructor |
196 |
196 |
197 @param cond condition as string with flag |
197 @param cond condition as string with flag |
198 @type str |
198 @type str |
199 @param compiledCond precompiled condition |
199 @param compiledCond precompiled condition |
200 @type code object |
200 @type code object |
201 @param flag indicates type of watch (created or changed) |
201 @param flag indicates type of watch (created or changed) |
202 @type str |
202 @type str |
203 @keyparam temporary flag for temporary watches |
203 @keyparam temporary flag for temporary watches |
204 @type int |
204 @type bool |
205 """ |
205 """ |
206 # Should not occur |
206 # Should not occur |
207 if not cond: |
207 if not cond: |
208 return |
208 return |
209 |
209 |
210 self.cond = cond |
210 self.cond = cond |
211 self.compiledCond = compiledCond |
211 self.compiledCond = compiledCond |
212 self.temporary = temporary |
212 self.temporary = temporary |
213 |
213 |
214 self.enabled = 1 |
214 self.enabled = True |
215 self.ignore = 0 |
215 self.ignore = 0 |
216 |
216 |
217 self.created = False |
217 self.created = False |
218 self.changed = False |
218 self.changed = False |
219 if flag == '??created??': |
219 if flag == '??created??': |
289 @return tuple of watch expression and a flag to indicate, that a |
289 @return tuple of watch expression and a flag to indicate, that a |
290 temporary watch expression may be deleted |
290 temporary watch expression may be deleted |
291 @rtype tuple of Watch, int |
291 @rtype tuple of Watch, int |
292 """ |
292 """ |
293 for b in Watch.watches: |
293 for b in Watch.watches: |
294 if b.enabled == 0: |
294 if not b.enabled: |
295 continue |
295 continue |
296 try: |
296 try: |
297 val = eval(b.compiledCond, frame.f_globals, frame.f_locals) |
297 val = eval(b.compiledCond, frame.f_globals, frame.f_locals) |
298 if b.created: |
298 if b.created: |
299 if frame in b.values: |
299 if frame in b.values: |
300 continue |
300 continue |
301 else: |
301 else: |
302 b.values[frame] = [1, val, b.ignore] |
302 b.values[frame] = [1, val, b.ignore] |
303 return (b, 1) |
303 return (b, True) |
304 |
304 |
305 elif b.changed: |
305 elif b.changed: |
306 try: |
306 try: |
307 if b.values[frame][1] != val: |
307 if b.values[frame][1] != val: |
308 b.values[frame][1] = val |
308 b.values[frame][1] = val |