diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 8cab6b9d56..9e021aaaf1 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -116,6 +116,7 @@ if TYPE_CHECKING: from plugins.SliceInfoPlugin.SliceInfo import SliceInfo from cura.Machines.MaterialManager import MaterialManager from cura.Machines.QualityManager import QualityManager + from UM.Settings.EmptyInstanceContainer import EmptyInstanceContainer numpy.seterr(all = "ignore") @@ -177,12 +178,12 @@ class CuraApplication(QtApplication): self._machine_action_manager = None - self.empty_container = None - self.empty_definition_changes_container = None - self.empty_variant_container = None - self.empty_material_container = None - self.empty_quality_container = None - self.empty_quality_changes_container = None + self.empty_container = None # type: EmptyInstanceContainer + self.empty_definition_changes_container = None # type: EmptyInstanceContainer + self.empty_variant_container = None # type: EmptyInstanceContainer + self.empty_material_container = None # type: EmptyInstanceContainer + self.empty_quality_container = None # type: EmptyInstanceContainer + self.empty_quality_changes_container = None # type: EmptyInstanceContainer self._variant_manager = None self._material_manager = None @@ -370,7 +371,7 @@ class CuraApplication(QtApplication): # Add empty variant, material and quality containers. # Since they are empty, they should never be serialized and instead just programmatically created. # We need them to simplify the switching between materials. - self.empty_container = cura.Settings.cura_empty_instance_containers.empty_container + self.empty_container = cura.Settings.cura_empty_instance_containers.empty_container # type: EmptyInstanceContainer self._container_registry.addContainer( cura.Settings.cura_empty_instance_containers.empty_definition_changes_container) diff --git a/cura/Machines/MachineErrorChecker.py b/cura/Machines/MachineErrorChecker.py index 37de4f30ce..06f064315b 100644 --- a/cura/Machines/MachineErrorChecker.py +++ b/cura/Machines/MachineErrorChecker.py @@ -50,7 +50,7 @@ class MachineErrorChecker(QObject): self._error_check_timer.setInterval(100) self._error_check_timer.setSingleShot(True) - def initialize(self): + def initialize(self) -> None: self._error_check_timer.timeout.connect(self._rescheduleCheck) # Reconnect all signals when the active machine gets changed. @@ -62,7 +62,7 @@ class MachineErrorChecker(QObject): self._onMachineChanged() - def _onMachineChanged(self): + def _onMachineChanged(self) -> None: if self._global_stack: self._global_stack.propertyChanged.disconnect(self.startErrorCheck) self._global_stack.containersChanged.disconnect(self.startErrorCheck) @@ -94,7 +94,7 @@ class MachineErrorChecker(QObject): return self._need_to_check or self._check_in_progress # Starts the error check timer to schedule a new error check. - def startErrorCheck(self, *args): + def startErrorCheck(self, *args) -> None: if not self._check_in_progress: self._need_to_check = True self.needToWaitForResultChanged.emit() @@ -103,7 +103,7 @@ class MachineErrorChecker(QObject): # This function is called by the timer to reschedule a new error check. # If there is no check in progress, it will start a new one. If there is any, it sets the "_need_to_check" flag # to notify the current check to stop and start a new one. - def _rescheduleCheck(self): + def _rescheduleCheck(self) -> None: if self._check_in_progress and not self._need_to_check: self._need_to_check = True self.needToWaitForResultChanged.emit() @@ -128,7 +128,7 @@ class MachineErrorChecker(QObject): self._start_time = time.time() Logger.log("d", "New error check scheduled.") - def _checkStack(self): + def _checkStack(self) -> None: if self._need_to_check: Logger.log("d", "Need to check for errors again. Discard the current progress and reschedule a check.") self._check_in_progress = False @@ -169,7 +169,7 @@ class MachineErrorChecker(QObject): # Schedule the check for the next key self._application.callLater(self._checkStack) - def _setResult(self, result: bool): + def _setResult(self, result: bool) -> None: if result != self._has_errors: self._has_errors = result self.hasErrorUpdated.emit() diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index e081d4db3e..99fa71abe6 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import TYPE_CHECKING, Optional, cast +from typing import TYPE_CHECKING, Optional, cast, Dict, List from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtSlot @@ -20,6 +20,8 @@ if TYPE_CHECKING: from UM.Settings.DefinitionContainer import DefinitionContainer from cura.Settings.GlobalStack import GlobalStack from .QualityChangesGroup import QualityChangesGroup + from cura.CuraApplication import CuraApplication + from UM.Settings.ContainerRegistry import ContainerRegistry # @@ -36,17 +38,20 @@ class QualityManager(QObject): qualitiesUpdated = pyqtSignal() - def __init__(self, container_registry, parent = None): + def __init__(self, container_registry: "ContainerRegistry", parent = None) -> None: super().__init__(parent) - self._application = Application.getInstance() + self._application = Application.getInstance() # type: CuraApplication self._material_manager = self._application.getMaterialManager() self._container_registry = container_registry self._empty_quality_container = self._application.empty_quality_container self._empty_quality_changes_container = self._application.empty_quality_changes_container - self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {} # for quality lookup - self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup + # For quality lookup + self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {} # type: Dict[str, QualityNode] + + # For quality_changes lookup + self._machine_quality_type_to_quality_changes_dict = {} # type: Dict[str, QualityNode] self._default_machine_definition_id = "fdmprinter" @@ -62,7 +67,7 @@ class QualityManager(QObject): self._update_timer.setSingleShot(True) self._update_timer.timeout.connect(self._updateMaps) - def initialize(self): + def initialize(self) -> None: # Initialize the lookup tree for quality profiles with following structure: # -> -> -> # -> @@ -133,13 +138,13 @@ class QualityManager(QObject): Logger.log("d", "Lookup tables updated.") self.qualitiesUpdated.emit() - def _updateMaps(self): + def _updateMaps(self) -> None: self.initialize() - def _onContainerMetadataChanged(self, container): + def _onContainerMetadataChanged(self, container: InstanceContainer) -> None: self._onContainerChanged(container) - def _onContainerChanged(self, container): + def _onContainerChanged(self, container: InstanceContainer) -> None: container_type = container.getMetaDataEntry("type") if container_type not in ("quality", "quality_changes"): return @@ -148,7 +153,7 @@ class QualityManager(QObject): self._update_timer.start() # Updates the given quality groups' availabilities according to which extruders are being used/ enabled. - def _updateQualityGroupsAvailability(self, machine: "GlobalStack", quality_group_list): + def _updateQualityGroupsAvailability(self, machine: "GlobalStack", quality_group_list) -> None: used_extruders = set() for i in range(machine.getProperty("machine_extruder_count", "value")): if str(i) in machine.extruders and machine.extruders[str(i)].isEnabled: @@ -196,12 +201,9 @@ class QualityManager(QObject): # Whether a QualityGroup is available can be unknown via the field QualityGroup.is_available. # For more details, see QualityGroup. # - def getQualityGroups(self, machine: "GlobalStack") -> dict: + def getQualityGroups(self, machine: "GlobalStack") -> Dict[str, QualityGroup]: machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition) - # This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks - has_machine_specific_qualities = machine.getHasMachineQuality() - # To find the quality container for the GlobalStack, check in the following fall-back manner: # (1) the machine-specific node # (2) the generic node @@ -214,7 +216,12 @@ class QualityManager(QObject): has_extruder_specific_qualities = True default_machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(self._default_machine_definition_id) - nodes_to_check = [machine_node, default_machine_node] + + nodes_to_check = [] # type: List[QualityNode] + if machine_node is not None: + nodes_to_check.append(machine_node) + if default_machine_node is not None: + nodes_to_check.append(default_machine_node) # Iterate over all quality_types in the machine node quality_group_dict = {} @@ -273,13 +280,16 @@ class QualityManager(QObject): # Each points above can be represented as a node in the lookup tree, so here we simply put those nodes into # the list with priorities as the order. Later, we just need to loop over each node in this list and fetch # qualities from there. - node_info_list_0 = [nozzle_name, buildplate_name, root_material_id] + node_info_list_0 = [nozzle_name, buildplate_name, root_material_id] # type: List[Optional[str]] nodes_to_check = [] # This function tries to recursively find the deepest (the most specific) branch and add those nodes to # the search list in the order described above. So, by iterating over that search node list, we first look # in the more specific branches and then the less specific (generic) ones. - def addNodesToCheck(node, nodes_to_check_list, node_info_list, node_info_idx): + def addNodesToCheck(node: Optional[QualityNode], nodes_to_check_list: List[QualityNode], node_info_list, node_info_idx: int) -> None: + if node is None: + return + if node_info_idx < len(node_info_list): node_name = node_info_list[node_info_idx] if node_name is not None: @@ -300,9 +310,10 @@ class QualityManager(QObject): # The last fall back will be the global qualities (either from the machine-specific node or the generic # node), but we only use one. For details see the overview comments above. - if machine_node.quality_type_map: + + if machine_node is not None and machine_node.quality_type_map: nodes_to_check += [machine_node] - else: + elif default_machine_node is not None: nodes_to_check += [default_machine_node] for node_idx, node in enumerate(nodes_to_check): @@ -334,7 +345,7 @@ class QualityManager(QObject): return quality_group_dict - def getQualityGroupsForMachineDefinition(self, machine: "GlobalStack") -> dict: + def getQualityGroupsForMachineDefinition(self, machine: "GlobalStack") -> Dict[str, QualityGroup]: machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition) # To find the quality container for the GlobalStack, check in the following fall-back manner: @@ -372,7 +383,7 @@ class QualityManager(QObject): # Remove the given quality changes group. # @pyqtSlot(QObject) - def removeQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup"): + def removeQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup") -> None: Logger.log("i", "Removing quality changes group [%s]", quality_changes_group.name) removed_quality_changes_ids = set() for node in quality_changes_group.getAllNodes(): @@ -415,7 +426,7 @@ class QualityManager(QObject): # Duplicates the given quality. # @pyqtSlot(str, "QVariantMap") - def duplicateQualityChanges(self, quality_changes_name, quality_model_item): + def duplicateQualityChanges(self, quality_changes_name: str, quality_model_item) -> None: global_stack = self._application.getGlobalContainerStack() if not global_stack: Logger.log("i", "No active global stack, cannot duplicate quality changes.") @@ -443,7 +454,7 @@ class QualityManager(QObject): # the user containers in each stack. These then replace the quality_changes containers in the # stack and clear the user settings. @pyqtSlot(str) - def createQualityChanges(self, base_name): + def createQualityChanges(self, base_name: str) -> None: machine_manager = Application.getInstance().getMachineManager() global_stack = machine_manager.activeMachine diff --git a/cura/Machines/QualityNode.py b/cura/Machines/QualityNode.py index f384ee7825..a821a1e15d 100644 --- a/cura/Machines/QualityNode.py +++ b/cura/Machines/QualityNode.py @@ -16,6 +16,9 @@ class QualityNode(ContainerNode): super().__init__(metadata = metadata) self.quality_type_map = {} # type: Dict[str, QualityNode] # quality_type -> QualityNode for InstanceContainer + def getChildNode(self, child_key: str) -> Optional["QualityNode"]: + return self.children_map.get(child_key) + def addQualityMetadata(self, quality_type: str, metadata: dict): if quality_type not in self.quality_type_map: self.quality_type_map[quality_type] = QualityNode(metadata) diff --git a/cura/Machines/VariantManager.py b/cura/Machines/VariantManager.py index 969fed670e..9c8cff9efb 100644 --- a/cura/Machines/VariantManager.py +++ b/cura/Machines/VariantManager.py @@ -2,7 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from collections import OrderedDict -from typing import Optional, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING, Dict from UM.ConfigurationErrorMessage import ConfigurationErrorMessage from UM.Logger import Logger @@ -36,11 +36,11 @@ if TYPE_CHECKING: # class VariantManager: - def __init__(self, container_registry): - self._container_registry = container_registry # type: ContainerRegistry + def __init__(self, container_registry: ContainerRegistry) -> None: + self._container_registry = container_registry - self._machine_to_variant_dict_map = dict() # -> - self._machine_to_buildplate_dict_map = dict() + self._machine_to_variant_dict_map = dict() # type: Dict[str, Dict["VariantType", Dict[str, ContainerNode]]] + self._machine_to_buildplate_dict_map = dict() # type: Dict[str, Dict[str, ContainerNode]] self._exclude_variant_id_list = ["empty_variant"] @@ -48,7 +48,7 @@ class VariantManager: # Initializes the VariantManager including: # - initializing the variant lookup table based on the metadata in ContainerRegistry. # - def initialize(self): + def initialize(self) -> None: self._machine_to_variant_dict_map = OrderedDict() self._machine_to_buildplate_dict_map = OrderedDict() @@ -106,10 +106,10 @@ class VariantManager: variant_node = variant_dict[variant_name] break return variant_node + return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name) - def getVariantNodes(self, machine: "GlobalStack", - variant_type: Optional["VariantType"] = None) -> dict: + def getVariantNodes(self, machine: "GlobalStack", variant_type: "VariantType") -> Dict[str, ContainerNode]: machine_definition_id = machine.definition.getId() return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {})