diff --git a/cura/Machines/ContainerNode.py b/cura/Machines/ContainerNode.py index 6a839fb921..125aaf56ad 100644 --- a/cura/Machines/ContainerNode.py +++ b/cura/Machines/ContainerNode.py @@ -30,9 +30,10 @@ class ContainerNode: def getChildNode(self, child_key: str) -> Optional["ContainerNode"]: return self.children_map.get(child_key) - def getContainer(self) -> "InstanceContainer": + def getContainer(self) -> Optional["InstanceContainer"]: if self.metadata is None: - raise RuntimeError("Cannot get container for a ContainerNode without metadata") + Logger.log("e", "Cannot get container for a ContainerNode without metadata.") + return None if self.container is None: container_id = self.metadata["id"] @@ -40,7 +41,8 @@ class ContainerNode: from UM.Settings.ContainerRegistry import ContainerRegistry container_list = ContainerRegistry.getInstance().findInstanceContainers(id = container_id) if not container_list: - raise RuntimeError("Failed to lazy-load container [%s], cannot find it" % container_id) + Logger.log("e", "Failed to lazy-load container [{container_id}]. Cannot find it.".format(container_id = container_id)) + return None self.container = container_list[0] return self.container diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 24c7ccb8c0..5d78f589c6 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -423,7 +423,8 @@ class MaterialManager(QObject): return material_group = self.getMaterialGroup(root_material_id) - material_group.root_material_node.getContainer().setName(name) + if material_group: + material_group.root_material_node.getContainer().setName(name) # # Removes the given material. @@ -447,6 +448,8 @@ class MaterialManager(QObject): return None base_container = material_group.root_material_node.getContainer() + if not base_container: + return None # Ensure all settings are saved. self._application.saveSettings() @@ -466,6 +469,8 @@ class MaterialManager(QObject): # Clone all of them. for node in material_group.derived_material_node_list: container_to_copy = node.getContainer() + if not container_to_copy: + continue # Create unique IDs for every clone. new_id = new_base_id if container_to_copy.getMetaDataEntry("definition") != "fdmprinter": diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index b38f6f65c8..33eda2ec0d 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -90,7 +90,7 @@ class QualitySettingsModel(ListModel): quality_node = quality_group.nodes_for_extruders.get(str(self._selected_position)) settings_keys = quality_group.getAllKeys() quality_containers = [] - if quality_node is not None: + if quality_node is not None and quality_node.getContainer() is not None: quality_containers.append(quality_node.getContainer()) # Here, if the user has selected a quality changes, then "quality_changes_group" will not be None, and we fetch @@ -100,7 +100,7 @@ class QualitySettingsModel(ListModel): quality_changes_node = quality_changes_group.node_for_global else: quality_changes_node = quality_changes_group.nodes_for_extruders.get(str(self._selected_position)) - if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime + if quality_changes_node is not None and quality_changes_node.getContainer() is not None: # it can be None if number of extruders are changed during runtime try: quality_containers.insert(0, quality_changes_node.getContainer()) except RuntimeError: diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index 8d972c9192..f6b8e6e36c 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -393,6 +393,8 @@ class QualityManager(QObject): new_name = self._container_registry.uniqueName(quality_changes_name) for node in quality_changes_group.getAllNodes(): container = node.getContainer() + if not container: + continue new_id = self._container_registry.uniqueName(container.getId()) self._container_registry.addContainer(container.duplicate(new_id, new_name)) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 760a288b7b..f0eb2303f2 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -98,9 +98,10 @@ class ContainerManager(QObject): entry_value = root container = material_group.root_material_node.getContainer() - container.setMetaDataEntry(entry_name, entry_value) - if sub_item_changed: #If it was only a sub-item that has changed then the setMetaDataEntry won't correctly notice that something changed, and we must manually signal that the metadata changed. - container.metaDataChanged.emit(container) + if container is not None: + container.setMetaDataEntry(entry_name, entry_value) + if sub_item_changed: #If it was only a sub-item that has changed then the setMetaDataEntry won't correctly notice that something changed, and we must manually signal that the metadata changed. + container.metaDataChanged.emit(container) ## Set a setting property of the specified container. # @@ -377,7 +378,8 @@ class ContainerManager(QObject): # NOTE: We only need to set the root material container because XmlMaterialProfile.setMetaDataEntry() will # take care of the derived containers too container = material_group.root_material_node.getContainer() - container.setMetaDataEntry("GUID", new_guid) + if container is not None: + container.setMetaDataEntry("GUID", new_guid) ## Get the singleton instance for this class. @classmethod @@ -466,5 +468,5 @@ class ContainerManager(QObject): if not path: return - container_list = [n.getContainer() for n in quality_changes_group.getAllNodes()] + container_list = [n.getContainer() for n in quality_changes_group.getAllNodes() if n.getContainer() is not None] self._container_registry.exportQualityProfile(container_list, path, file_type) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index a8234b9de9..3c6ce59269 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -44,6 +44,8 @@ class CuraStackBuilder: global_variant_node = variant_manager.getDefaultVariantNode(machine_definition, VariantType.BUILD_PLATE) if global_variant_node: global_variant_container = global_variant_node.getContainer() + if not global_variant_container: + global_variant_container = application.empty_variant_container # get variant container for extruders extruder_variant_container = application.empty_variant_container @@ -51,6 +53,8 @@ class CuraStackBuilder: extruder_variant_name = None if extruder_variant_node: extruder_variant_container = extruder_variant_node.getContainer() + if not extruder_variant_container: + extruder_variant_container = application.empty_variant_container extruder_variant_name = extruder_variant_container.getName() generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName()) @@ -72,7 +76,7 @@ class CuraStackBuilder: # get material container for extruders material_container = application.empty_material_container material_node = material_manager.getDefaultMaterial(new_global_stack, extruder_variant_name) - if material_node: + if material_node and material_node.getContainer(): material_container = material_node.getContainer() # Create ExtruderStacks @@ -107,8 +111,10 @@ class CuraStackBuilder: quality_group = quality_group_dict.get(preferred_quality_type) new_global_stack.quality = quality_group.node_for_global.getContainer() + if not new_global_stack.quality: + new_global_stack.quality = application.empty_quality_container for position, extruder_stack in new_global_stack.extruders.items(): - if position in quality_group.nodes_for_extruders: + if position in quality_group.nodes_for_extruders and quality_group.nodes_for_extruders[position].getContainer(): extruder_stack.quality = quality_group.nodes_for_extruders[position].getContainer() else: extruder_stack.quality = application.empty_quality_container diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index c25b58fbcf..6694bba0d6 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -987,6 +987,12 @@ class MachineManager(QObject): self.activeQualityChangesGroupChanged.emit() def _setQualityGroup(self, quality_group, empty_quality_changes = True): + if quality_group.node_for_global.getContainer() is None: + return + for node in quality_group.nodes_for_extruders.values(): + if node.getContainer() is None: + return + self._current_quality_group = quality_group if empty_quality_changes: self._current_quality_changes_group = None @@ -1012,9 +1018,9 @@ class MachineManager(QObject): quality_changes_container = self._empty_quality_changes_container quality_container = self._empty_quality_changes_container - if quality_changes_group.node_for_global: + if quality_changes_group.node_for_global and quality_changes_group.node_for_global.getContainer(): quality_changes_container = quality_changes_group.node_for_global.getContainer() - if quality_group.node_for_global: + if quality_group.node_for_global and quality_group.node_for_global.getContainer(): quality_container = quality_group.node_for_global.getContainer() self._global_container_stack.quality = quality_container @@ -1026,9 +1032,9 @@ class MachineManager(QObject): quality_changes_container = self._empty_quality_changes_container quality_container = self._empty_quality_container - if quality_changes_node: + if quality_changes_node and quality_changes_node.getContainer(): quality_changes_container = quality_changes_node.getContainer() - if quality_node: + if quality_node and quality_node.getContainer(): quality_container = quality_node.getContainer() extruder.quality = quality_container @@ -1040,14 +1046,18 @@ class MachineManager(QObject): self.activeQualityChangesGroupChanged.emit() def _setVariantNode(self, position, container_node): + if container_node.getContainer() is None: + return self._global_container_stack.extruders[position].variant = container_node.getContainer() self.activeVariantChanged.emit() def _setGlobalVariant(self, container_node): self._global_container_stack.variant = container_node.getContainer() + if not self._global_container_stack.variant: + self._global_container_stack.variant = Application.getInstance().empty_variant_container def _setMaterial(self, position, container_node = None): - if container_node: + if container_node and container_node.getContainer(): self._global_container_stack.extruders[position].material = container_node.getContainer() root_material_id = container_node.metadata["base_file"] else: diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 633142187c..6a16c2905e 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -895,7 +895,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): variant_type = VariantType.BUILD_PLATE node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type) - if node is not None: + if node is not None and node.getContainer() is not None: global_stack.variant = node.getContainer() for position, extruder_stack in extruder_stack_dict.items(): @@ -911,7 +911,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): variant_type = VariantType.NOZZLE node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type) - if node is not None: + if node is not None and node.getContainer() is not None: extruder_stack.variant = node.getContainer() def _applyMaterials(self, global_stack, extruder_stack_dict): @@ -937,7 +937,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): extruder_stack.variant.getName(), machine_material_diameter, root_material_id) - if material_node is not None: + if material_node is not None and material_node.getContainer() is not None: extruder_stack.material = material_node.getContainer() def _applyChangesToMachine(self, global_stack, extruder_stack_dict): diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 54caca855e..6dcd5a5ccc 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -71,12 +71,14 @@ class XmlMaterialProfile(InstanceContainer): # Update the root material container root_material_container = material_group.root_material_node.getContainer() - root_material_container.setMetaDataEntry(key, value, apply_to_all = False) + if root_material_container is not None: + root_material_container.setMetaDataEntry(key, value, apply_to_all = False) # Update all containers derived from it for node in material_group.derived_material_node_list: container = node.getContainer() - container.setMetaDataEntry(key, value, apply_to_all = False) + if container is not None: + container.setMetaDataEntry(key, value, apply_to_all = False) ## Overridden from InstanceContainer, similar to setMetaDataEntry. # without this function the setName would only set the name of the specific nozzle / material / machine combination container