def setUp(self): self._application = MagicMock() self._container_registry = MagicMock() self._machine_manager = MagicMock() self._mocked_mime = MagicMock() self._mocked_mime.preferredSuffix = "omg" self._mocked_mime.suffixes = ["omg"] self._mocked_mime.comment = "UnitTest!" self._mocked_container = MagicMock() self._mocked_container_data = "SOME DATA :D" self._mocked_container.serialize = MagicMock( return_value=self._mocked_container_data) self._containers_meta_data = [{"id": "test", "test_data": "omg"}] self._container_registry.findContainersMetadata = MagicMock( return_value=self._containers_meta_data) self._container_registry.getMimeTypeForContainer = MagicMock( return_value=self._mocked_mime) self._container_registry.findContainers = MagicMock( return_value=[self._mocked_container]) self._application.getContainerRegistry = MagicMock( return_value=self._container_registry) self._application.getMachineManager = MagicMock( return_value=self._machine_manager) # Destroy the previous instance of the container manager if ContainerManager.getInstance() is not None: ContainerManager._ContainerManager__instance = None self._container_manager = ContainerManager(self._application) MimeTypeDatabase.addMimeType(self._mocked_mime)
def setUp(self): self._application = MagicMock() self._container_registry = MagicMock() self._machine_manager = MagicMock() self._mocked_mime = MagicMock() self._mocked_mime.preferredSuffix = "omg" self._mocked_mime.suffixes = ["omg"] self._mocked_mime.comment = "UnitTest!" self._mocked_container = MagicMock() self._mocked_container_data = "SOME DATA :D" self._mocked_container.serialize = MagicMock(return_value = self._mocked_container_data) self._containers_meta_data = [{"id": "test", "test_data": "omg"}] self._container_registry.findContainersMetadata = MagicMock(return_value = self._containers_meta_data) self._container_registry.getMimeTypeForContainer = MagicMock(return_value = self._mocked_mime) self._container_registry.findContainers = MagicMock(return_value = [self._mocked_container]) self._application.getContainerRegistry = MagicMock(return_value = self._container_registry) self._application.getMachineManager = MagicMock(return_value = self._machine_manager) # Destroy the previous instance of the container manager if ContainerManager.getInstance() is not None: ContainerManager._ContainerManager__instance = None self._container_manager = ContainerManager(self._application) MimeTypeDatabase.addMimeType(self._mocked_mime)
def createQualityChanges(self, base_name: str) -> None: machine_manager = self._application.getMachineManager() global_stack = machine_manager.activeMachine if not global_stack: return active_quality_name = machine_manager.activeQualityOrQualityChangesName if active_quality_name == "": Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId()) return machine_manager.blurSettings.emit() if base_name is None or base_name == "": base_name = active_quality_name unique_name = self._container_registry.uniqueName(base_name) # Go through the active stacks and create quality_changes containers from the user containers. stack_list = [global_stack] + list(global_stack.extruders.values()) for stack in stack_list: user_container = stack.userChanges quality_container = stack.quality quality_changes_container = stack.qualityChanges if not quality_container or not quality_changes_container: Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId()) continue quality_type = quality_container.getMetaDataEntry("quality_type") extruder_stack = None if isinstance(stack, ExtruderStack): extruder_stack = stack new_changes = self._createQualityChanges(quality_type, unique_name, global_stack, extruder_stack) from cura.Settings.ContainerManager import ContainerManager ContainerManager.getInstance()._performMerge(new_changes, quality_changes_container, clear_settings = False) ContainerManager.getInstance()._performMerge(new_changes, user_container) self._container_registry.addContainer(new_changes)
def _sendMaterialProfiles(self): Logger.log("i", "Sending material profiles to printer") # TODO: Might want to move this to a job... for container in ContainerRegistry.getInstance( ).findInstanceContainers(type="material"): try: xml_data = container.serialize() if xml_data == "" or xml_data is None: continue names = ContainerManager.getInstance().getLinkedMaterials( container.getId()) if names: # There are other materials that share this GUID. if not container.isReadOnly(): continue # If it's not readonly, it's created by user, so skip it. file_name = "none.xml" self.postForm("materials", "form-data; name=\"file\";filename=\"%s\"" % file_name, xml_data.encode(), on_finished=None) except NotImplementedError: # If the material container is not the most "generic" one it can't be serialized an will raise a # NotImplementedError. We can simply ignore these. pass
def _materialWarningMessageAction(self, message, button): if button == "Undo": container_manager = ContainerManager.getInstance() container_manager.setContainerMetaDataEntry(self._material_diameter_warning_message.material_id, "properties/diameter", self._material_diameter_warning_message.previous_diameter) message.hide() else: Logger.log("w", "Unknown button action for material diameter warning message: {action}".format(action = button))
def duplicateMaterial(self, message: QDBusMessage): from cura.Settings.ContainerManager import ContainerManager container_manager = ContainerManager.getInstance() base_material_id = message.arguments()[0] # material to duplicate from new_id = message.arguments()[1] # (preferred) duplicated material ID container_manager.duplicateMaterial(base_material_id, new_id)
def createMaterial(self, message: QDBusMessage): from cura.Settings.ContainerManager import ContainerManager container_manager = ContainerManager.getInstance() new_id = message.arguments()[0] new_name = message.arguments()[1] container_manager.createMaterial(new_id=new_id, new_name=new_name)
def _materialWarningMessageAction(self, message, button): if button == "Undo": container_manager = ContainerManager.getInstance() container_manager.setContainerMetaDataEntry(self._material_diameter_warning_message.material_id, "properties/diameter", self._material_diameter_warning_message.previous_diameter) approximate_previous_diameter = str(round(float(self._material_diameter_warning_message.previous_diameter))) container_manager.setContainerMetaDataEntry(self._material_diameter_warning_message.material_id, "approximate_diameter", approximate_previous_diameter) message.hide() else: Logger.log("w", "Unknown button action for material diameter warning message: {action}".format(action = button))
def exportMaterial(self, message: QDBusMessage): material_id = message.arguments()[0] material_file_path = message.arguments()[1] from cura.Settings.ContainerManager import ContainerManager container_manager = ContainerManager.getInstance() container_manager.exportContainer( material_id, container_manager.getContainerNameFilters("material")[0], material_file_path)
def createQualityChanges(self, base_name: str) -> None: machine_manager = cura.CuraApplication.CuraApplication.getInstance( ).getMachineManager() global_stack = machine_manager.activeMachine if not global_stack: return active_quality_name = machine_manager.activeQualityOrQualityChangesName if active_quality_name == "": Logger.log( "w", "No quality container found in stack %s, cannot create profile", global_stack.getId()) return machine_manager.blurSettings.emit() if base_name is None or base_name == "": base_name = active_quality_name container_registry = cura.CuraApplication.CuraApplication.getInstance( ).getContainerRegistry() unique_name = container_registry.uniqueName(base_name) # Go through the active stacks and create quality_changes containers from the user containers. container_manager = ContainerManager.getInstance() stack_list = [global_stack] + list(global_stack.extruders.values()) for stack in stack_list: quality_container = stack.quality quality_changes_container = stack.qualityChanges if not quality_container or not quality_changes_container: Logger.log( "w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId()) continue extruder_stack = None intent_category = None if stack.getMetaDataEntry("position") is not None: extruder_stack = stack intent_category = stack.intent.getMetaDataEntry( "intent_category") new_changes = self._createQualityChanges( quality_container.getMetaDataEntry("quality_type"), intent_category, unique_name, global_stack, extruder_stack) container_manager._performMerge(new_changes, quality_changes_container, clear_settings=False) container_manager._performMerge(new_changes, stack.userChanges) container_registry.addContainer(new_changes)
def createQualityChanges(self, base_name: str) -> None: """Create quality changes containers from the user containers in the active stacks. This will go through the global and extruder stacks and create quality_changes containers from the user containers in each stack. These then replace the quality_changes containers in the stack and clear the user settings. :param base_name: The new name for the quality changes profile. The final name of the profile might be different from this, because it needs to be made unique. """ machine_manager = cura.CuraApplication.CuraApplication.getInstance().getMachineManager() global_stack = machine_manager.activeMachine if not global_stack: return active_quality_name = machine_manager.activeQualityOrQualityChangesName if active_quality_name == "": Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId()) return machine_manager.blurSettings.emit() if base_name is None or base_name == "": base_name = active_quality_name container_registry = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry() unique_name = container_registry.uniqueName(base_name) # Go through the active stacks and create quality_changes containers from the user containers. container_manager = ContainerManager.getInstance() stack_list = [global_stack] + global_stack.extruderList for stack in stack_list: quality_container = stack.quality quality_changes_container = stack.qualityChanges if not quality_container or not quality_changes_container: Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId()) continue extruder_stack = None intent_category = None if stack.getMetaDataEntry("position") is not None: extruder_stack = stack intent_category = stack.intent.getMetaDataEntry("intent_category") new_changes = self._createQualityChanges(quality_container.getMetaDataEntry("quality_type"), intent_category, unique_name, global_stack, extruder_stack) container_manager._performMerge(new_changes, quality_changes_container, clear_settings = False) container_manager._performMerge(new_changes, stack.userChanges) container_registry.addContainer(new_changes)
def _sendMaterialProfiles(self): Logger.log("i", "Sending material profiles to printer") # TODO: Might want to move this to a job... for container in ContainerRegistry.getInstance().findInstanceContainers(type="material"): try: xml_data = container.serialize() if xml_data == "" or xml_data is None: continue names = ContainerManager.getInstance().getLinkedMaterials(container.getId()) if names: # There are other materials that share this GUID. if not container.isReadOnly(): continue # If it's not readonly, it's created by user, so skip it. file_name = "none.xml" self.postForm("materials", "form-data; name=\"file\";filename=\"%s\"" % file_name, xml_data.encode(), on_finished=None) except NotImplementedError: # If the material container is not the most "generic" one it can't be serialized an will raise a # NotImplementedError. We can simply ignore these. pass
class TestContainerManager(TestCase): def setUp(self): self._application = MagicMock() self._container_registry = MagicMock() self._machine_manager = MagicMock() self._mocked_mime = MagicMock() self._mocked_mime.preferredSuffix = "omg" self._mocked_mime.suffixes = ["omg"] self._mocked_mime.comment = "UnitTest!" self._mocked_container = MagicMock() self._mocked_container_data = "SOME DATA :D" self._mocked_container.serialize = MagicMock( return_value=self._mocked_container_data) self._containers_meta_data = [{"id": "test", "test_data": "omg"}] self._container_registry.findContainersMetadata = MagicMock( return_value=self._containers_meta_data) self._container_registry.getMimeTypeForContainer = MagicMock( return_value=self._mocked_mime) self._container_registry.findContainers = MagicMock( return_value=[self._mocked_container]) self._application.getContainerRegistry = MagicMock( return_value=self._container_registry) self._application.getMachineManager = MagicMock( return_value=self._machine_manager) # Destroy the previous instance of the container manager if ContainerManager.getInstance() is not None: ContainerManager._ContainerManager__instance = None self._container_manager = ContainerManager(self._application) MimeTypeDatabase.addMimeType(self._mocked_mime) def tearDown(self): MimeTypeDatabase.removeMimeType(self._mocked_mime) def test_getContainerMetaDataEntry(self): with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=self._application)): assert self._container_manager.getContainerMetaDataEntry( "test", "test_data") == "omg" assert self._container_manager.getContainerMetaDataEntry( "test", "entry_that_is_not_defined") == "" def test_clearUserContainer(self): with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=self._application)): self._container_manager.clearUserContainers() assert self._machine_manager.activeMachine.userChanges.clear.call_count == 1 def test_getContainerNameFilters(self): with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=self._application)): # If nothing is added, we still expect to get the all files filter assert self._container_manager.getContainerNameFilters("") == [ 'All Files (*)' ] # Pretend that a new type was added. self._container_registry.getContainerTypes = MagicMock( return_value=[("None", None)]) assert self._container_manager.getContainerNameFilters("") == [ 'UnitTest! (*.omg)', 'All Files (*)' ] def test_exportContainerUnknownFileType(self): # The filetype is not known, so this should cause an error! assert self._container_manager.exportContainer( "test", "zomg", "whatever")["status"] == "error" def test_exportContainerInvalidPath(self): assert self._container_manager.exportContainer("test", "zomg", "")["status"] == "error" assert self._container_manager.exportContainer( "test", "zomg", QUrl())["status"] == "error" def test_exportContainerInvalidId(self): assert self._container_manager.exportContainer( "", "whatever", "whatever")["status"] == "error" def test_exportContainer(self): with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=self._application)): with tempfile.TemporaryDirectory() as tmpdirname: result = self._container_manager.exportContainer( "test", "whatever", os.path.join(tmpdirname, "whatever.omg")) assert (os.path.exists(result["path"])) with open(result["path"], "r", encoding="utf-8") as f: assert f.read() == self._mocked_container_data
def importProfile(self, file_name): Logger.log("d", "Attempting to import profile %s", file_name) if not file_name: return { "status": "error", "message": catalog.i18nc( "@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path", ), } plugin_registry = PluginRegistry.getInstance() extension = file_name.split(".")[-1] global_container_stack = Application.getInstance().getGlobalContainerStack() if not global_container_stack: return machine_extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId())) machine_extruders.sort(key=lambda k: k.getMetaDataEntry("position")) for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. except Exception as e: # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log( "e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name, profile_reader.getPluginId(), str(e), ) return { "status": "error", "message": catalog.i18nc( "@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e), ), } if profile_or_list: # Success! name_seed = os.path.splitext(os.path.basename(file_name))[0] new_name = self.uniqueName(name_seed) if type(profile_or_list) is not list: profile = profile_or_list self._configureProfile(profile, name_seed, new_name) return { "status": "ok", "message": catalog.i18nc( "@info:status", "Successfully imported profile {0}", profile.getName() ), } else: profile_index = -1 global_profile = None for profile in profile_or_list: if profile_index >= 0: if len(machine_extruders) > profile_index: extruder_id = ( Application.getInstance() .getMachineManager() .getQualityDefinitionId(machine_extruders[profile_index].getBottom()) ) # Ensure the extruder profiles get non-conflicting names # NB: these are not user-facing if "extruder" in profile.getMetaData(): profile.setMetaDataEntry("extruder", extruder_id) else: profile.addMetaDataEntry("extruder", extruder_id) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") elif profile_index == 0: # Importing a multiextrusion profile into a single extrusion machine; merge 1st extruder profile into global profile profile._id = self.uniqueName("temporary_profile") self.addContainer(profile) ContainerManager.getInstance().mergeContainers(global_profile.getId(), profile.getId()) self.removeContainer(profile.getId()) break else: # The imported composite profile has a profile for an extruder that this machine does not have. Ignore this extruder-profile break else: global_profile = profile profile_id = ( (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") ) self._configureProfile(profile, profile_id, new_name) profile_index += 1 return { "status": "ok", "message": catalog.i18nc( "@info:status", "Successfully imported profile {0}", profile_or_list[0].getName() ), } # If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc( "@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name ), }
class TestContainerManager(TestCase): def setUp(self): self._application = MagicMock() self._container_registry = MagicMock() self._machine_manager = MagicMock() self._mocked_mime = MagicMock() self._mocked_mime.preferredSuffix = "omg" self._mocked_mime.suffixes = ["omg"] self._mocked_mime.comment = "UnitTest!" self._mocked_container = MagicMock() self._mocked_container_data = "SOME DATA :D" self._mocked_container.serialize = MagicMock(return_value = self._mocked_container_data) self._containers_meta_data = [{"id": "test", "test_data": "omg"}] self._container_registry.findContainersMetadata = MagicMock(return_value = self._containers_meta_data) self._container_registry.getMimeTypeForContainer = MagicMock(return_value = self._mocked_mime) self._container_registry.findContainers = MagicMock(return_value = [self._mocked_container]) self._application.getContainerRegistry = MagicMock(return_value = self._container_registry) self._application.getMachineManager = MagicMock(return_value = self._machine_manager) # Destroy the previous instance of the container manager if ContainerManager.getInstance() is not None: ContainerManager._ContainerManager__instance = None self._container_manager = ContainerManager(self._application) MimeTypeDatabase.addMimeType(self._mocked_mime) def tearDown(self): MimeTypeDatabase.removeMimeType(self._mocked_mime) def test_getContainerMetaDataEntry(self): assert self._container_manager.getContainerMetaDataEntry("test", "test_data") == "omg" assert self._container_manager.getContainerMetaDataEntry("test", "entry_that_is_not_defined") == "" def test_clearUserContainer(self): self._container_manager.clearUserContainers() assert self._machine_manager.activeMachine.userChanges.clear.call_count == 1 def test_getContainerNameFilters(self): # If nothing is added, we still expect to get the all files filter assert self._container_manager.getContainerNameFilters("") == ['All Files (*)'] # Pretend that a new type was added. self._container_registry.getContainerTypes = MagicMock(return_value=[("None", None)]) assert self._container_manager.getContainerNameFilters("") == ['UnitTest! (*.omg)', 'All Files (*)'] def test_exportContainerUnknownFileType(self): # The filetype is not known, so this should cause an error! assert self._container_manager.exportContainer("test", "zomg", "whatever")["status"] == "error" def test_exportContainerInvalidPath(self): assert self._container_manager.exportContainer("test", "zomg", "")["status"] == "error" assert self._container_manager.exportContainer("test", "zomg", QUrl())["status"] == "error" def test_exportContainerInvalidId(self): assert self._container_manager.exportContainer("", "whatever", "whatever")["status"] == "error" def test_exportContainer(self): with tempfile.TemporaryDirectory() as tmpdirname: result = self._container_manager.exportContainer("test", "whatever", os.path.join(tmpdirname, "whatever.omg")) assert(os.path.exists(result["path"])) with open(result["path"], "r", encoding="utf-8") as f: assert f.read() == self._mocked_container_data
def importProfile(self, file_name): Logger.log("d", "Attempting to import profile %s", file_name) if not file_name: return { "status": "error", "message": catalog.i18nc( "@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path") } plugin_registry = PluginRegistry.getInstance() extension = file_name.split(".")[-1] global_container_stack = Application.getInstance( ).getGlobalContainerStack() if not global_container_stack: return machine_extruders = list( ExtruderManager.getInstance().getMachineExtruders( global_container_stack.getId())) machine_extruders.sort(key=lambda k: k.getMetaDataEntry("position")) for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read( file_name) # Try to open the file with the profile reader. except Exception as e: # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log( "e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name, profile_reader.getPluginId(), str(e)) return { "status": "error", "message": catalog.i18nc( "@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)) } if profile_or_list: # Success! name_seed = os.path.splitext(os.path.basename(file_name))[0] new_name = self.uniqueName(name_seed) if type(profile_or_list) is not list: profile = profile_or_list self._configureProfile(profile, name_seed, new_name) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } else: profile_index = -1 global_profile = None for profile in profile_or_list: if profile_index >= 0: if len(machine_extruders) > profile_index: extruder_id = Application.getInstance( ).getMachineManager().getQualityDefinitionId( machine_extruders[profile_index].getBottom( )) # Ensure the extruder profiles get non-conflicting names # NB: these are not user-facing if "extruder" in profile.getMetaData(): profile.setMetaDataEntry( "extruder", extruder_id) else: profile.addMetaDataEntry( "extruder", extruder_id) profile_id = (extruder_id + "_" + name_seed).lower().replace( " ", "_") elif profile_index == 0: # Importing a multiextrusion profile into a single extrusion machine; merge 1st extruder profile into global profile profile._id = self.uniqueName( "temporary_profile") self.addContainer(profile) ContainerManager.getInstance().mergeContainers( global_profile.getId(), profile.getId()) self.removeContainer(profile.getId()) break else: # The imported composite profile has a profile for an extruder that this machine does not have. Ignore this extruder-profile break else: global_profile = profile profile_id = ( global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") self._configureProfile(profile, profile_id, new_name) profile_index += 1 return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName()) } # If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc( "@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name) }
def importMaterial(self, message: QDBusMessage): material_file_path = message.arguments()[0] from cura.Settings.ContainerManager import ContainerManager container_manager = ContainerManager.getInstance() container_manager.importContainer(material_file_path)