Skip to content

Commit 97e1253

Browse files
Merge pull request #129 from CadQuery/debug-fix
Debug fix
2 parents ed55278 + 0cb73b8 commit 97e1253

File tree

3 files changed

+122
-42
lines changed

3 files changed

+122
-42
lines changed

cq_editor/widgets/debugger.py

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,32 @@ def _exec(self, code, locals_dict, globals_dict):
185185
if self.preferences['Change working dir to script dir'] and p:
186186
stack.enter_context(p)
187187
exec(code, locals_dict, globals_dict)
188+
189+
def _inject_locals(self,module):
190+
191+
cq_objects = {}
192+
193+
def _show_object(obj,name=None, options={}):
194+
195+
if name:
196+
cq_objects.update({name : SimpleNamespace(shape=obj,options=options)})
197+
else:
198+
cq_objects.update({str(id(obj)) : SimpleNamespace(shape=obj,options=options)})
199+
200+
def _debug(obj,name=None):
201+
202+
_show_object(obj,name,options=dict(color='red',alpha=0.2))
203+
204+
module.__dict__['show_object'] = _show_object
205+
module.__dict__['debug'] = _debug
206+
module.__dict__['log'] = lambda x: info(str(x))
207+
module.__dict__['cq'] = cq
208+
209+
return cq_objects, set(module.__dict__)-{'cq'}
210+
211+
def _cleanup_locals(self,module,injected_names):
212+
213+
for name in injected_names: module.__dict__.pop(name)
188214

189215
@pyqtSlot(bool)
190216
def render(self):
@@ -193,37 +219,25 @@ def render(self):
193219
reload_cq()
194220

195221
cq_script = self.get_current_script()
196-
cq_code,t = self.compile_code(cq_script)
222+
cq_code,module = self.compile_code(cq_script)
197223

198224
if cq_code is None: return
199-
200-
cq_objects = {}
201-
202-
def _show_object(obj,name=None, options={}):
203-
204-
if name:
205-
cq_objects.update({name : SimpleNamespace(shape=obj,options=options)})
206-
else:
207-
cq_objects.update({str(id(obj)) : SimpleNamespace(shape=obj,options=options)})
208-
209-
t.__dict__['show_object'] = _show_object
210-
t.__dict__['debug'] = lambda x: info(str(x))
211-
t.__dict__['cq'] = cq
225+
226+
cq_objects,injected_names = self._inject_locals(module)
212227

213228
try:
214-
self._exec(cq_code, t.__dict__, t.__dict__)
229+
self._exec(cq_code, module.__dict__, module.__dict__)
215230

216231
#remove the special methods
217-
t.__dict__.pop('show_object')
218-
t.__dict__.pop('debug')
232+
self._cleanup_locals(module,injected_names)
219233

220-
#collect all CQ objects if no explicti show_object was called
234+
#collect all CQ objects if no explicit show_object was called
221235
if len(cq_objects) == 0:
222-
cq_objects = find_cq_objects(t.__dict__)
236+
cq_objects = find_cq_objects(module.__dict__)
223237
self.sigRendered.emit(cq_objects)
224238
self.sigTraceback.emit(None,
225239
cq_script)
226-
self.sigLocals.emit(t.__dict__)
240+
self.sigLocals.emit(module.__dict__)
227241
except Exception:
228242
self.sigTraceback.emit(sys.exc_info(),
229243
cq_script)
@@ -241,6 +255,8 @@ def debug(self,value):
241255
self.sigDebugging.emit(False)
242256
self._actions['Run'][1].setChecked(False)
243257
return
258+
259+
cq_objects,injected_names = self._inject_locals(module)
244260

245261
self.breakpoints = [ el[0] for el in self.get_breakpoints()]
246262

@@ -257,6 +273,13 @@ def debug(self,value):
257273
sys.settrace(None)
258274
self.sigDebugging.emit(False)
259275
self._actions['Run'][1].setChecked(False)
276+
277+
if len(cq_objects) == 0:
278+
cq_objects = find_cq_objects(module.__dict__)
279+
self.sigRendered.emit(cq_objects)
280+
281+
self._cleanup_locals(module,injected_names)
282+
self.sigLocals.emit(module.__dict__)
260283
else:
261284
sys.settrace(None)
262285
self.inner_event_loop.exit(0)

cq_editor/widgets/object_tree.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,20 @@ def addLines(self):
223223

224224
self.sigObjectsAdded.emit(ais_list)
225225

226+
def _current_properties(self):
227+
228+
current_params = {}
229+
for i in range(self.CQ.childCount()):
230+
child = self.CQ.child(i)
231+
current_params[child.properties['Name']] = child.properties
232+
233+
return current_params
234+
235+
def _restore_properties(self,obj,properties):
236+
237+
for p in properties[obj.properties['Name']]:
238+
obj.properties[p.name()] = p.value()
239+
226240
@pyqtSlot(dict,bool)
227241
@pyqtSlot(dict)
228242
def addObjects(self,objects,clean=False,root=None):
@@ -234,10 +248,7 @@ def addObjects(self,objects,clean=False,root=None):
234248
preserve_props = self.preferences['Preserve properties on reload']
235249

236250
if preserve_props:
237-
old_params = {}
238-
for i in range(self.CQ.childCount()):
239-
child = self.CQ.child(i)
240-
old_params[child.properties['Name']] = child.properties
251+
current_props = self._current_properties()
241252

242253
if clean or self.preferences['Clear all before each run']:
243254
self.removeObjects()
@@ -256,9 +267,8 @@ def addObjects(self,objects,clean=False,root=None):
256267
ais=ais,
257268
sig=self.sigObjectPropertiesChanged)
258269

259-
if preserve_props and name in old_params:
260-
for p in old_params[name]:
261-
child.properties[p.name()] = p.value()
270+
if preserve_props and name in current_props:
271+
self._restore_properties(child,current_props)
262272

263273
if child.properties['Visible']:
264274
ais_list.append(ais)

tests/test_app.py

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
result = result.box(3, 3, 0.5)
4343
result = result.edges("|Z").fillet(0.125)
4444
45-
debug('test')
45+
log('test')
4646
show_object(result,name='test')
4747
'''
4848

@@ -55,6 +55,15 @@
5555
show_object(result.val())
5656
'''
5757

58+
code_debug_Workplane = \
59+
'''import cadquery as cq
60+
result = cq.Workplane("XY" )
61+
result = result.box(3, 3, 0.5)
62+
result = result.edges("|Z").fillet(0.125)
63+
64+
debug(result)
65+
'''
66+
5867
code_multi = \
5968
'''import cadquery as cq
6069
result1 = cq.Workplane("XY" ).box(3, 3, 0.5)
@@ -85,6 +94,13 @@ def get_bottom_left(widget):
8594

8695
return pos
8796

97+
def get_rgba(ais):
98+
99+
alpha = ais.Transparency()
100+
color = get_occ_color(ais)
101+
102+
return color.redF(),color.redF(),color.redF(),alpha
103+
88104
@pytest.fixture
89105
def main(qtbot,mocker):
90106

@@ -335,24 +351,24 @@ def patch_debugger(debugger,event_loop_mock):
335351
assert(number_visible_items(viewer) == 3)
336352

337353
#test step through
338-
ev = event_loop([lambda: (assert_func(variables.model().rowCount() == 0),
354+
ev = event_loop([lambda: (assert_func(variables.model().rowCount() == 4),
339355
assert_func(number_visible_items(viewer) == 3),
340356
step.triggered.emit()),
341-
lambda: (assert_func(variables.model().rowCount() == 1),
357+
lambda: (assert_func(variables.model().rowCount() == 4),
342358
assert_func(number_visible_items(viewer) == 3),
343359
step.triggered.emit()),
344-
lambda: (assert_func(variables.model().rowCount() == 2),
360+
lambda: (assert_func(variables.model().rowCount() == 5),
345361
assert_func(number_visible_items(viewer) == 3),
346362
step.triggered.emit()),
347-
lambda: (assert_func(variables.model().rowCount() == 2),
363+
lambda: (assert_func(variables.model().rowCount() == 5),
348364
assert_func(number_visible_items(viewer) == 4),
349365
cont.triggered.emit())])
350366

351367
patch_debugger(debugger,ev)
352368

353369
debug.triggered.emit(True)
354370
assert(variables.model().rowCount() == 2)
355-
assert(number_visible_items(viewer) == 3)
371+
assert(number_visible_items(viewer) == 4)
356372

357373
#test exit debug
358374
ev = event_loop([lambda: (step.triggered.emit(),),
@@ -369,7 +385,7 @@ def patch_debugger(debugger,event_loop_mock):
369385

370386
#test breakpoint
371387
ev = event_loop([lambda: (cont.triggered.emit(),),
372-
lambda: (assert_func(variables.model().rowCount() == 2),
388+
lambda: (assert_func(variables.model().rowCount() == 5),
373389
assert_func(number_visible_items(viewer) == 4),
374390
cont.triggered.emit(),)])
375391

@@ -380,7 +396,45 @@ def patch_debugger(debugger,event_loop_mock):
380396
debug.triggered.emit(True)
381397

382398
assert(variables.model().rowCount() == 2)
383-
assert(number_visible_items(viewer) == 3)
399+
assert(number_visible_items(viewer) == 4)
400+
401+
#test breakpoint without using singals
402+
ev = event_loop([lambda: (cont.triggered.emit(),),
403+
lambda: (assert_func(variables.model().rowCount() == 5),
404+
assert_func(number_visible_items(viewer) == 4),
405+
cont.triggered.emit(),)])
406+
407+
patch_debugger(debugger,ev)
408+
409+
editor.set_breakpoints([(4,None)])
410+
411+
debugger.debug(True)
412+
413+
assert(variables.model().rowCount() == 2)
414+
assert(number_visible_items(viewer) == 4)
415+
416+
#test debug() without using singals
417+
ev = event_loop([lambda: (cont.triggered.emit(),),
418+
lambda: (assert_func(variables.model().rowCount() == 5),
419+
assert_func(number_visible_items(viewer) == 4),
420+
cont.triggered.emit(),)])
421+
422+
patch_debugger(debugger,ev)
423+
424+
editor.set_text(code_debug_Workplane)
425+
editor.set_breakpoints([(4,None)])
426+
427+
debugger.debug(True)
428+
429+
CQ = obj_tree.CQ
430+
431+
# object 1 (defualt color)
432+
r,g,b,a = get_rgba(CQ.child(0).ais)
433+
assert( a == pytest.approx(0.2) )
434+
assert( r == 1.0 )
435+
436+
assert(variables.model().rowCount() == 2)
437+
assert(number_visible_items(viewer) == 4)
384438

385439
# restore the tracing function
386440
sys.settrace(trace_function)
@@ -884,13 +938,6 @@ def test_render_colors(main_clean):
884938

885939
editor.set_text(code_color)
886940
debugger._actions['Run'][0].triggered.emit()
887-
888-
def get_rgba(ais):
889-
890-
alpha = ais.Transparency()
891-
color = get_occ_color(ais)
892-
893-
return color.redF(),color.redF(),color.redF(),alpha
894941

895942
CQ = obj_tree.CQ
896943

0 commit comments

Comments
 (0)