From 841b792c73a0f86f91db73252de7b46e956db80b Mon Sep 17 00:00:00 2001 From: Heewa Barfchin Date: Mon, 17 May 2021 18:13:16 -0400 Subject: [PATCH] Path: check for empty before using - fixes #4645 In a few locations, python objects are used without checking if they exist and are non-null, which throws missing attribute exceptions. The fix is to simply check first. --- src/Mod/Path/PathScripts/PathJob.py | 80 ++++++++++++++++------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py index 655528b72d..7fa8a6857b 100644 --- a/src/Mod/Path/PathScripts/PathJob.py +++ b/src/Mod/Path/PathScripts/PathJob.py @@ -171,7 +171,7 @@ class ObjectJob: obj.Stock.ViewObject.Visibility = False def setupSetupSheet(self, obj): - if not hasattr(obj, 'SetupSheet'): + if not getattr(obj, 'SetupSheet', None): obj.addProperty('App::PropertyLink', 'SetupSheet', 'Base', QtCore.QT_TRANSLATE_NOOP('PathJob', 'SetupSheet holding the settings for this job')) obj.SetupSheet = PathSetupSheet.Create() if obj.SetupSheet.ViewObject: @@ -223,53 +223,58 @@ class ObjectJob: PathLog.track(obj.Label, arg2) doc = obj.Document - # the first to tear down are the ops, they depend on other resources - PathLog.debug('taking down ops: %s' % [o.Name for o in self.allOperations()]) - while obj.Operations.Group: - op = obj.Operations.Group[0] - if not op.ViewObject or not hasattr(op.ViewObject.Proxy, 'onDelete') or op.ViewObject.Proxy.onDelete(op.ViewObject, ()): - PathUtil.clearExpressionEngine(op) - doc.removeObject(op.Name) - obj.Operations.Group = [] - doc.removeObject(obj.Operations.Name) - obj.Operations = None + if getattr(obj, 'Operations', None): + # the first to tear down are the ops, they depend on other resources + PathLog.debug('taking down ops: %s' % [o.Name for o in self.allOperations()]) + while obj.Operations.Group: + op = obj.Operations.Group[0] + if not op.ViewObject or not hasattr(op.ViewObject.Proxy, 'onDelete') or op.ViewObject.Proxy.onDelete(op.ViewObject, ()): + PathUtil.clearExpressionEngine(op) + doc.removeObject(op.Name) + obj.Operations.Group = [] + doc.removeObject(obj.Operations.Name) + obj.Operations = None # stock could depend on Model, so delete it first - if obj.Stock: + if getattr(obj, 'Stock', None): PathLog.debug('taking down stock') PathUtil.clearExpressionEngine(obj.Stock) doc.removeObject(obj.Stock.Name) obj.Stock = None # base doesn't depend on anything inside job - for base in obj.Model.Group: - PathLog.debug("taking down base %s" % base.Label) - self.removeBase(obj, base, False) - obj.Model.Group = [] - doc.removeObject(obj.Model.Name) - obj.Model = None + if getattr(obj, 'Model', None): + for base in obj.Model.Group: + PathLog.debug("taking down base %s" % base.Label) + self.removeBase(obj, base, False) + obj.Model.Group = [] + doc.removeObject(obj.Model.Name) + obj.Model = None # Tool controllers might refer to either legacy tool or toolbit - PathLog.debug('taking down tool controller') - for tc in obj.Tools.Group: - if hasattr(tc.Tool, "Proxy"): - PathUtil.clearExpressionEngine(tc.Tool) - doc.removeObject(tc.Tool.Name) - PathUtil.clearExpressionEngine(tc) - tc.Proxy.onDelete(tc) - doc.removeObject(tc.Name) - obj.Tools.Group = [] - doc.removeObject(obj.Tools.Name) - obj.Tools = None + if getattr(obj, 'Tools', None): + PathLog.debug('taking down tool controller') + for tc in obj.Tools.Group: + if hasattr(tc.Tool, "Proxy"): + PathUtil.clearExpressionEngine(tc.Tool) + doc.removeObject(tc.Tool.Name) + PathUtil.clearExpressionEngine(tc) + tc.Proxy.onDelete(tc) + doc.removeObject(tc.Name) + obj.Tools.Group = [] + doc.removeObject(obj.Tools.Name) + obj.Tools = None # SetupSheet - PathUtil.clearExpressionEngine(obj.SetupSheet) - doc.removeObject(obj.SetupSheet.Name) - obj.SetupSheet = None + if getattr(obj, 'SetupSheet', None): + PathUtil.clearExpressionEngine(obj.SetupSheet) + doc.removeObject(obj.SetupSheet.Name) + obj.SetupSheet = None + return True def fixupOperations(self, obj): - if obj.Operations.ViewObject: + if getattr(obj.Operations, 'ViewObject', None): try: obj.Operations.ViewObject.DisplayMode except Exception: # pylint: disable=broad-except @@ -409,7 +414,7 @@ class ObjectJob: return None def execute(self, obj): - if hasattr(obj, 'Operations'): + if getattr(obj, 'Operations', None): obj.Path = obj.Operations.Path self.getCycleTime() @@ -479,8 +484,11 @@ class ObjectJob: ops.append(op) for sub in op.Group: collectBaseOps(sub) - for op in self.obj.Operations.Group: - collectBaseOps(op) + + if getattr(self.obj, 'Operations', None) and getattr(self.obj.Operations, 'Group', None): + for op in self.obj.Operations.Group: + collectBaseOps(op) + return ops def setCenterOfRotation(self, center):