From 60c8712b10cd5612c09412c2d7405a8ffe070005 Mon Sep 17 00:00:00 2001 From: digitalfrost Date: Tue, 9 Aug 2022 11:42:18 +0200 Subject: [PATCH 01/25] CuraContainerStack.py: improve TypeIndexMap Cleaner and more idiomatic way to reverse a dictionary --- cura/Settings/CuraContainerStack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index 5348deb4bd..a8a1d780ea 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -427,4 +427,4 @@ class _ContainerIndexes: } # Reverse lookup: type -> index - TypeIndexMap = dict([(v, k) for k, v in IndexTypeMap.items()]) + TypeIndexMap = {v: k for k, v in IndexTypeMap.items()} From 57d739a848dc96a4d38b7ae6f8d3a61b69c2467c Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 15 Aug 2022 15:43:37 +0200 Subject: [PATCH 02/25] Move source of truth for latest.json url into ApplicationMetadata.py and out of the Uranium repository. CURA-9272 --- cura/ApplicationMetadata.py | 8 ++++++++ cura/CuraApplication.py | 1 + 2 files changed, 9 insertions(+) diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py index 60d9201d8e..678f8b7e4a 100644 --- a/cura/ApplicationMetadata.py +++ b/cura/ApplicationMetadata.py @@ -9,12 +9,20 @@ DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura" DEFAULT_CURA_VERSION = "dev" DEFAULT_CURA_BUILD_TYPE = "" DEFAULT_CURA_DEBUG_MODE = False +DEFAULT_CURA_LATEST_URL = "https://raw.githubusercontent.com/Ultimaker/Uranium/CURA-9272_semver_postfix/tests/latest.json" # Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for # example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the # CuraVersion.py.in template. CuraSDKVersion = "8.1.0" +try: + from cura.CuraVersion import CuraLatestURL + if CuraLatestURL == "": + CuraLatestURL = DEFAULT_CURA_LATEST_URL +except ImportError: + CuraLatestURL = DEFAULT_CURA_LATEST_URL + try: from cura.CuraVersion import CuraAppName # type: ignore if CuraAppName == "": diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index eeaead4f71..94492d22c8 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -152,6 +152,7 @@ class CuraApplication(QtApplication): super().__init__(name = ApplicationMetadata.CuraAppName, app_display_name = ApplicationMetadata.CuraAppDisplayName, version = ApplicationMetadata.CuraVersion if not ApplicationMetadata.IsAlternateVersion else ApplicationMetadata.CuraBuildType, + latest_url = ApplicationMetadata.CuraLatestURL, api_version = ApplicationMetadata.CuraSDKVersion, build_type = ApplicationMetadata.CuraBuildType, is_debug_mode = ApplicationMetadata.CuraDebugMode, From a20e7bf8d9792c81e655c2003e55d7f12daa6ff2 Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 15 Aug 2022 15:59:08 +0200 Subject: [PATCH 03/25] Add cura latest.json url to template so it can be set from the conanfile. CURA-9272 --- CuraVersion.py.jinja | 1 + conanfile.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CuraVersion.py.jinja b/CuraVersion.py.jinja index 1c30a0b5af..1c8ff0551c 100644 --- a/CuraVersion.py.jinja +++ b/CuraVersion.py.jinja @@ -11,3 +11,4 @@ CuraCloudAPIVersion = "{{ cura_cloud_api_version }}" CuraCloudAccountAPIRoot = "{{ cura_cloud_account_api_root }}" CuraMarketplaceRoot = "{{ cura_marketplace_root }}" CuraDigitalFactoryURL = "{{ cura_digital_factory_url }}" +CuraLatestURL = "{{ cura_latest_url }}" diff --git a/conanfile.py b/conanfile.py index a07500e17a..87dfd175ad 100644 --- a/conanfile.py +++ b/conanfile.py @@ -100,6 +100,10 @@ class CuraConan(ConanFile): def _digital_factory_url(self): return "https://digitalfactory-staging.ultimaker.com" if self._staging else "https://digitalfactory.ultimaker.com" + @property + def _cura_latest_url(self): + return "https://raw.githubusercontent.com/Ultimaker/Uranium/CURA-9272_semver_postfix/tests/latest.json" + @property def requirements_txts(self): if self.options.devtools: @@ -161,7 +165,8 @@ class CuraConan(ConanFile): cura_cloud_api_version = self.options.cloud_api_version, cura_cloud_account_api_root = self._cloud_account_api_root, cura_marketplace_root = self._marketplace_root, - cura_digital_factory_url = self._digital_factory_url)) + cura_digital_factory_url = self._digital_factory_url, + cura_latest_url = self._cura_latest_url)) def _generate_pyinstaller_spec(self, location, entrypoint_location, icon_path, entitlements_file): pyinstaller_metadata = self._um_data()["pyinstaller"] From 5900cac9c8b7bd7a7885a221084e7b41140a61de Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 15 Aug 2022 16:00:14 +0200 Subject: [PATCH 04/25] Default the prerelease number to 1 when it is not set in the github tags. CURA-9272 --- .github/workflows/conan-recipe-version.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/conan-recipe-version.yml b/.github/workflows/conan-recipe-version.yml index 5a24754f03..3ab3d59547 100644 --- a/.github/workflows/conan-recipe-version.yml +++ b/.github/workflows/conan-recipe-version.yml @@ -135,6 +135,9 @@ jobs: user = "_" channel = "_" else: + if not latest_branch_version.prerelease.contains("."): + # The prerealese did not contain a version number, default it to 1 + latest_branch_version.prerelease.append(".1") if event_name == "pull_request": actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{latest_branch_version.prerelease.lower()}+{buildmetadata}pr_{issue_number}_{no_commits}" else: From b82f1f4a8c66fbe0a587d1f0cc6a15b0ee55d421 Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Fri, 19 Aug 2022 13:53:43 +0200 Subject: [PATCH 05/25] Add new Abstract machine stack type. This represents a type of printers (ultimaker_s3 etc). These are created whenever a cloud printer of a new printer type is added. CURA-9277 Co-authored-by: casperlamboo --- cura/Settings/AbstractMachine.py | 16 ++++ cura/Settings/CuraContainerRegistry.py | 1 + cura/Settings/CuraStackBuilder.py | 77 +++++++++++++++++-- .../src/Cloud/CloudOutputDeviceManager.py | 2 + 4 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 cura/Settings/AbstractMachine.py diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py new file mode 100644 index 0000000000..0dd4dfb1c0 --- /dev/null +++ b/cura/Settings/AbstractMachine.py @@ -0,0 +1,16 @@ +from typing import List + +from cura.Settings.GlobalStack import GlobalStack + + +class AbstractMachine(GlobalStack): + """ Behaves as a type of machine, represents multiple machines of the same type """ + + def __init__(self): + super(self) + self.setMetaDataEntry("type", "abstract_machine") + + def getMachinesOfType(self) -> List[GlobalStack]: + pass + + diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 6ff856efcb..f65697277e 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -108,6 +108,7 @@ class CuraContainerRegistry(ContainerRegistry): :param container_type: :type{string} Type of the container (machine, quality, ...) :param container_name: :type{string} Name to check """ + # FIXME: this should check for abstract machine container_class = ContainerStack if container_type == "machine" else InstanceContainer return self.findContainersMetadata(container_type = container_class, id = container_name, type = container_type, ignore_case = True) or \ diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index ff9a795c43..bc02fd6cd1 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -9,6 +9,7 @@ from UM.Settings.Interfaces import DefinitionContainerInterface from UM.Settings.InstanceContainer import InstanceContainer from cura.Machines.ContainerTree import ContainerTree +from .AbstractMachine import AbstractMachine from .GlobalStack import GlobalStack from .ExtruderStack import ExtruderStack @@ -199,17 +200,25 @@ class CuraStackBuilder: :return: A new Global stack instance with the specified parameters. """ - - from cura.CuraApplication import CuraApplication - application = CuraApplication.getInstance() - registry = application.getContainerRegistry() - stack = GlobalStack(new_stack_id) stack.setDefinition(definition) + cls.createUserContainer(new_stack_id, definition, stack, variant_container, material_container, quality_container) + return stack + + @classmethod + def createUserContainer(cls, new_stack_id: str, definition: DefinitionContainerInterface, + stack: GlobalStack, + variant_container: "InstanceContainer", + material_container: "InstanceContainer", + quality_container: "InstanceContainer"): + from cura.CuraApplication import CuraApplication + application = CuraApplication.getInstance() + + registry = application.getContainerRegistry() # Create user container user_container = cls.createUserChangesContainer(new_stack_id + "_user", definition.getId(), new_stack_id, - is_global_stack = True) + is_global_stack=True) stack.definitionChanges = cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings") stack.variant = variant_container @@ -221,8 +230,6 @@ class CuraStackBuilder: registry.addContainer(user_container) - return stack - @classmethod def createUserChangesContainer(cls, container_name: str, definition_id: str, stack_id: str, is_global_stack: bool) -> "InstanceContainer": @@ -259,3 +266,57 @@ class CuraStackBuilder: container_stack.definitionChanges = definition_changes_container return definition_changes_container + + @classmethod + def createAbstractMachine(cls, name, definition_id): + # cls.createMachine(definition_id, definition_id) + """Create a new instance of a machine. + + :param name: The name of the new machine. + :param definition_id: The ID of the machine definition to use. + :param machine_extruder_count: The number of extruders in the machine. + + :return: The new global stack or None if an error occurred. + """ + + from cura.CuraApplication import CuraApplication + application = CuraApplication.getInstance() + registry = application.getContainerRegistry() + container_tree = ContainerTree.getInstance() + + if registry.findContainerStacks(type="abstract_machine", id=definition_id): + # This abstract machine already exists + return + + match registry.findDefinitionContainers(id=definition_id): + case []: + # It should not be possible for the definition to be missing since an abstract machine will only + # be created as a result of a machine with definition_id being created. + Logger.error("w", "Definition {definition} was not found!", definition=definition_id) + return None + case [machine_definition, *_definitions]: + machine_node = container_tree.machines[machine_definition.getId()] + + generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName()) + # Make sure the new name does not collide with any definition or (quality) profile + # createUniqueName() only looks at other stacks, but not at definitions or quality profiles + # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true + if registry.findContainersMetadata(id=generated_name): + generated_name = registry.uniqueName(generated_name) + + stack = AbstractMachine(generated_name) + stack.setDefinition(machine_definition) + cls.createUserContainer( + generated_name, + machine_definition, + application.empty_variant_container, + application.empty_material_container, + machine_node.preferredGlobalQuality().container, + ) + + # FIXME: This should have a pretty name + stack.setName(generated_name) + + registry.addContainer(stack) + + return stack diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index f7f659124c..f5ede7c0d1 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -405,6 +405,8 @@ class CloudOutputDeviceManager: self._setOutputDeviceMetadata(device, new_machine) + CuraStackBuilder.createAbstractMachine(new_machine) + if activate: CuraApplication.getInstance().getMachineManager().setActiveMachine(new_machine.getId()) From 761bf3b8fab02b8884d1780b211abfd92b8ced53 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 19 Aug 2022 14:44:19 +0200 Subject: [PATCH 06/25] Fix creating abstract machines on account sync Cura-9277 Co-authored-by: joeydelarago --- cura/Settings/AbstractMachine.py | 4 ++-- .../UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py index 0dd4dfb1c0..837cfad4bd 100644 --- a/cura/Settings/AbstractMachine.py +++ b/cura/Settings/AbstractMachine.py @@ -6,8 +6,8 @@ from cura.Settings.GlobalStack import GlobalStack class AbstractMachine(GlobalStack): """ Behaves as a type of machine, represents multiple machines of the same type """ - def __init__(self): - super(self) + def __init__(self, container_id: str): + super().__init__(container_id) self.setMetaDataEntry("type", "abstract_machine") def getMachinesOfType(self) -> List[GlobalStack]: diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index f5ede7c0d1..a73d08d8fa 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -405,7 +405,7 @@ class CloudOutputDeviceManager: self._setOutputDeviceMetadata(device, new_machine) - CuraStackBuilder.createAbstractMachine(new_machine) + CuraStackBuilder.createAbstractMachine(device.name, device.printerType) if activate: CuraApplication.getInstance().getMachineManager().setActiveMachine(new_machine.getId()) From d7f119415f572c360dd3199d3acd842c8fcc6792 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 19 Aug 2022 16:35:00 +0200 Subject: [PATCH 07/25] Use pretty-printed string for the `AbstractMachine` name Cura-9277 Co-authored-by: joeydelarago --- cura/Settings/CuraStackBuilder.py | 36 ++++++++----------- .../src/Cloud/CloudOutputDeviceManager.py | 2 +- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index bc02fd6cd1..0b700eae93 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -268,27 +268,25 @@ class CuraStackBuilder: return definition_changes_container @classmethod - def createAbstractMachine(cls, name, definition_id): - # cls.createMachine(definition_id, definition_id) - """Create a new instance of a machine. + def createAbstractMachine(cls, definition_id) -> Optional[AbstractMachine]: + """Create a new instance of an abstract machine. - :param name: The name of the new machine. - :param definition_id: The ID of the machine definition to use. - :param machine_extruder_count: The number of extruders in the machine. + :param definition_id: The ID of the machine definition to use. - :return: The new global stack or None if an error occurred. - """ + :return: The new Abstract Machine or None if an error occurred. + """ + abstract_machine_id = definition_id + "_abstract_machine" from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() - if registry.findContainerStacks(type="abstract_machine", id=definition_id): + if registry.findContainerStacks(type="abstract_machine", id=abstract_machine_id): # This abstract machine already exists - return + return None - match registry.findDefinitionContainers(id=definition_id): + match registry.findDefinitionContainers(type="machine", id=definition_id): case []: # It should not be possible for the definition to be missing since an abstract machine will only # be created as a result of a machine with definition_id being created. @@ -296,26 +294,20 @@ class CuraStackBuilder: return None case [machine_definition, *_definitions]: machine_node = container_tree.machines[machine_definition.getId()] + name = machine_definition.getName() - generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName()) - # Make sure the new name does not collide with any definition or (quality) profile - # createUniqueName() only looks at other stacks, but not at definitions or quality profiles - # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true - if registry.findContainersMetadata(id=generated_name): - generated_name = registry.uniqueName(generated_name) - - stack = AbstractMachine(generated_name) + stack = AbstractMachine(abstract_machine_id) stack.setDefinition(machine_definition) cls.createUserContainer( - generated_name, + name, machine_definition, + stack, application.empty_variant_container, application.empty_material_container, machine_node.preferredGlobalQuality().container, ) - # FIXME: This should have a pretty name - stack.setName(generated_name) + stack.setName(name) registry.addContainer(stack) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index a73d08d8fa..94b2eec80b 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -405,7 +405,7 @@ class CloudOutputDeviceManager: self._setOutputDeviceMetadata(device, new_machine) - CuraStackBuilder.createAbstractMachine(device.name, device.printerType) + CuraStackBuilder.createAbstractMachine(device.printerType) if activate: CuraApplication.getInstance().getMachineManager().setActiveMachine(new_machine.getId()) From f22d446fa401d5a2e6e8650184826c4ccb2878df Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 19 Aug 2022 16:35:13 +0200 Subject: [PATCH 08/25] Implement `getMachines` function Cura-9277 Co-authored-by: joeydelarago --- cura/Settings/AbstractMachine.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py index 837cfad4bd..7bf8454a49 100644 --- a/cura/Settings/AbstractMachine.py +++ b/cura/Settings/AbstractMachine.py @@ -1,16 +1,21 @@ from typing import List +from UM.Settings.ContainerStack import ContainerStack from cura.Settings.GlobalStack import GlobalStack class AbstractMachine(GlobalStack): - """ Behaves as a type of machine, represents multiple machines of the same type """ + """ Represents a group of machines of the same type. This allows the user to select settings before selecting a printer. """ def __init__(self, container_id: str): super().__init__(container_id) self.setMetaDataEntry("type", "abstract_machine") - def getMachinesOfType(self) -> List[GlobalStack]: - pass - + def getMachines(self) -> List[ContainerStack]: + from cura.CuraApplication import CuraApplication + application = CuraApplication.getInstance() + registry = application.getContainerRegistry() + printer_type = self.definition.getId() + cloud_printer_type = 3 + return [machine for machine in registry.findContainerStacks(type="machine") if machine.definition.id == printer_type and cloud_printer_type in machine.configuredConnectionTypes] From 963110a9c636a2d80a7db93b5aa53f9255a8ef12 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 19 Aug 2022 16:41:02 +0200 Subject: [PATCH 09/25] Remove Fix me Cura-9277 Co-authored-by: joeydelarago --- cura/Settings/CuraContainerRegistry.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index f65697277e..70d03b5ddc 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -108,8 +108,7 @@ class CuraContainerRegistry(ContainerRegistry): :param container_type: :type{string} Type of the container (machine, quality, ...) :param container_name: :type{string} Name to check """ - # FIXME: this should check for abstract machine - container_class = ContainerStack if container_type == "machine" else InstanceContainer + container_class = ContainerStack if container_type in "machine" else InstanceContainer return self.findContainersMetadata(container_type = container_class, id = container_name, type = container_type, ignore_case = True) or \ self.findContainersMetadata(container_type = container_class, name = container_name, type = container_type) From 544ac33537a0d0f078bcf73ae4175e9c615faaac Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 22 Aug 2022 10:33:47 +0200 Subject: [PATCH 10/25] Add resource type for abstract machine so they can be saved. CURA-9277 --- cura/CuraApplication.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index eeaead4f71..a5664ec524 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -145,6 +145,8 @@ class CuraApplication(QtApplication): DefinitionChangesContainer = Resources.UserType + 10 SettingVisibilityPreset = Resources.UserType + 11 IntentInstanceContainer = Resources.UserType + 12 + AbstractMachineStack = Resources.UserType + 13 + pyqtEnum(ResourceTypes) @@ -432,6 +434,7 @@ class CuraApplication(QtApplication): self._container_registry.addResourceType(self.ResourceTypes.MachineStack, "machine") self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes") self._container_registry.addResourceType(self.ResourceTypes.IntentInstanceContainer, "intent") + self._container_registry.addResourceType(self.ResourceTypes.AbstractMachineStack, "abstract_machine") Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") From c4be0e298caaab54a0135ddfab336a8ffba10744 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 22 Aug 2022 11:57:18 +0200 Subject: [PATCH 11/25] Add mime type to `AbstractMachine` Cura-9277 Co-authored-by: joeydelarago --- cura/Settings/AbstractMachine.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py index 7bf8454a49..50321d9a9f 100644 --- a/cura/Settings/AbstractMachine.py +++ b/cura/Settings/AbstractMachine.py @@ -2,6 +2,8 @@ from typing import List from UM.Settings.ContainerStack import ContainerStack from cura.Settings.GlobalStack import GlobalStack +from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase +from UM.Settings.ContainerRegistry import ContainerRegistry class AbstractMachine(GlobalStack): @@ -19,3 +21,14 @@ class AbstractMachine(GlobalStack): printer_type = self.definition.getId() cloud_printer_type = 3 return [machine for machine in registry.findContainerStacks(type="machine") if machine.definition.id == printer_type and cloud_printer_type in machine.configuredConnectionTypes] + + +## private: +abstract_machine_mime = MimeType( + name = "application/x-cura-abstract-machine", + comment = "Cura Abstract Machine", + suffixes = ["global.cfg"] +) + +MimeTypeDatabase.addMimeType(abstract_machine_mime) +ContainerRegistry.addContainerTypeByName(AbstractMachine, "abstract_machine", abstract_machine_mime.name) From 61ce8dff7dba43fb771b7541d69b01a9dda843bb Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 22 Aug 2022 11:58:05 +0200 Subject: [PATCH 12/25] Add the abstract stack to the `Resources` Cura-9277 Co-authored-by: joeydelarago --- cura/CuraApplication.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a5664ec524..f8812285bc 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -424,6 +424,7 @@ class CuraApplication(QtApplication): Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes") Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility") Resources.addStorageType(self.ResourceTypes.IntentInstanceContainer, "intent") + Resources.addStorageType(self.ResourceTypes.AbstractMachineStack, "abstract_machine_instances") self._container_registry.addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality") self._container_registry.addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes") @@ -483,6 +484,7 @@ class CuraApplication(QtApplication): ("variant", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.VariantInstanceContainer, "application/x-uranium-instancecontainer"), ("setting_visibility", SettingVisibilityPresetsModel.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.SettingVisibilityPreset, "application/x-uranium-preferences"), ("machine", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"), + ("abstract_machine", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"), ("extruder", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer") } ) From d83673a972b6922c5d35a9d476f289b85369cf8c Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 22 Aug 2022 14:25:17 +0200 Subject: [PATCH 13/25] Use ConnectionType enum Move import statement CURA-9277 --- cura/Settings/AbstractMachine.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py index 50321d9a9f..477edc0a0e 100644 --- a/cura/Settings/AbstractMachine.py +++ b/cura/Settings/AbstractMachine.py @@ -1,6 +1,8 @@ from typing import List from UM.Settings.ContainerStack import ContainerStack +from cura.CuraApplication import CuraApplication +from cura.PrinterOutput.PrinterOutputDevice import ConnectionType from cura.Settings.GlobalStack import GlobalStack from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase from UM.Settings.ContainerRegistry import ContainerRegistry @@ -14,13 +16,11 @@ class AbstractMachine(GlobalStack): self.setMetaDataEntry("type", "abstract_machine") def getMachines(self) -> List[ContainerStack]: - from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() registry = application.getContainerRegistry() printer_type = self.definition.getId() - cloud_printer_type = 3 - return [machine for machine in registry.findContainerStacks(type="machine") if machine.definition.id == printer_type and cloud_printer_type in machine.configuredConnectionTypes] + return [machine for machine in registry.findContainerStacks(type="machine") if machine.definition.id == printer_type and ConnectionType.CloudConnection in machine.configuredConnectionTypes] ## private: From 77a179be76a1f1370f9a5487a968ad5946489bde Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Mon, 22 Aug 2022 14:32:59 +0200 Subject: [PATCH 14/25] Code style CURA-9277 Co-authored-by: Jelle Spijker --- cura/Settings/CuraStackBuilder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 0b700eae93..98ad3075b7 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -218,7 +218,7 @@ class CuraStackBuilder: # Create user container user_container = cls.createUserChangesContainer(new_stack_id + "_user", definition.getId(), new_stack_id, - is_global_stack=True) + is_global_stack = True) stack.definitionChanges = cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings") stack.variant = variant_container @@ -282,11 +282,11 @@ class CuraStackBuilder: registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() - if registry.findContainerStacks(type="abstract_machine", id=abstract_machine_id): + if registry.findContainerStacks(type = "abstract_machine", id = abstract_machine_id): # This abstract machine already exists return None - match registry.findDefinitionContainers(type="machine", id=definition_id): + match registry.findDefinitionContainers(type = "machine", id = definition_id): case []: # It should not be possible for the definition to be missing since an abstract machine will only # be created as a result of a machine with definition_id being created. From 5761b3f27b9098c8ffe138876b634d7d6f7ad1a8 Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Mon, 22 Aug 2022 14:35:07 +0200 Subject: [PATCH 15/25] Typing CUR-9277 Co-authored-by: Jelle Spijker --- cura/Settings/AbstractMachine.py | 2 +- cura/Settings/CuraStackBuilder.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py index 477edc0a0e..d3cae76ccb 100644 --- a/cura/Settings/AbstractMachine.py +++ b/cura/Settings/AbstractMachine.py @@ -11,7 +11,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry class AbstractMachine(GlobalStack): """ Represents a group of machines of the same type. This allows the user to select settings before selecting a printer. """ - def __init__(self, container_id: str): + def __init__(self, container_id: str) -> None: super().__init__(container_id) self.setMetaDataEntry("type", "abstract_machine") diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 98ad3075b7..6a9ae728b7 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -210,7 +210,7 @@ class CuraStackBuilder: stack: GlobalStack, variant_container: "InstanceContainer", material_container: "InstanceContainer", - quality_container: "InstanceContainer"): + quality_container: "InstanceContainer") -> None: from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() @@ -268,7 +268,7 @@ class CuraStackBuilder: return definition_changes_container @classmethod - def createAbstractMachine(cls, definition_id) -> Optional[AbstractMachine]: + def createAbstractMachine(cls, definition_id: str) -> Optional[AbstractMachine]: """Create a new instance of an abstract machine. :param definition_id: The ID of the machine definition to use. From 12f3581337b434f26e120ab08e0bccedbe253777 Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Mon, 22 Aug 2022 14:44:45 +0200 Subject: [PATCH 16/25] Assign result of `createAbstractMachine` to a variable With prepended underscore to highlight the result of the function is not being used. CURA-9277 --- .../UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index 94b2eec80b..c2d00e98e0 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -405,7 +405,7 @@ class CloudOutputDeviceManager: self._setOutputDeviceMetadata(device, new_machine) - CuraStackBuilder.createAbstractMachine(device.printerType) + _abstract_machine = CuraStackBuilder.createAbstractMachine(device.printerType) if activate: CuraApplication.getInstance().getMachineManager().setActiveMachine(new_machine.getId()) From 35502e45faaa003419340347e7daa7df862415b6 Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Mon, 22 Aug 2022 14:48:04 +0200 Subject: [PATCH 17/25] Apply suggestions from code review CURA-9277 Co-authored-by: Jelle Spijker --- cura/CuraApplication.py | 2 +- cura/Settings/AbstractMachine.py | 6 +++--- cura/Settings/CuraContainerRegistry.py | 2 +- cura/Settings/CuraStackBuilder.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index f8812285bc..e696609666 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -484,7 +484,7 @@ class CuraApplication(QtApplication): ("variant", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.VariantInstanceContainer, "application/x-uranium-instancecontainer"), ("setting_visibility", SettingVisibilityPresetsModel.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.SettingVisibilityPreset, "application/x-uranium-preferences"), ("machine", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"), - ("abstract_machine", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"), + ("abstract_machine", 1): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"), ("extruder", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer") } ) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py index d3cae76ccb..3a8dbd54ea 100644 --- a/cura/Settings/AbstractMachine.py +++ b/cura/Settings/AbstractMachine.py @@ -24,11 +24,11 @@ class AbstractMachine(GlobalStack): ## private: -abstract_machine_mime = MimeType( +_abstract_machine_mime = MimeType( name = "application/x-cura-abstract-machine", comment = "Cura Abstract Machine", suffixes = ["global.cfg"] ) -MimeTypeDatabase.addMimeType(abstract_machine_mime) -ContainerRegistry.addContainerTypeByName(AbstractMachine, "abstract_machine", abstract_machine_mime.name) +MimeTypeDatabase.addMimeType(_abstract_machine_mime) +ContainerRegistry.addContainerTypeByName(AbstractMachine, "abstract_machine", _abstract_machine_mime.name) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 70d03b5ddc..1a711ef919 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -108,7 +108,7 @@ class CuraContainerRegistry(ContainerRegistry): :param container_type: :type{string} Type of the container (machine, quality, ...) :param container_name: :type{string} Name to check """ - container_class = ContainerStack if container_type in "machine" else InstanceContainer + container_class = ContainerStack if "machine" in container_type else InstanceContainer return self.findContainersMetadata(container_type = container_class, id = container_name, type = container_type, ignore_case = True) or \ self.findContainersMetadata(container_type = container_class, name = container_name, type = container_type) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 6a9ae728b7..1c55026dcf 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -290,7 +290,7 @@ class CuraStackBuilder: case []: # It should not be possible for the definition to be missing since an abstract machine will only # be created as a result of a machine with definition_id being created. - Logger.error("w", "Definition {definition} was not found!", definition=definition_id) + Logger.error(f"Definition {definition_id} was not found!") return None case [machine_definition, *_definitions]: machine_node = container_tree.machines[machine_definition.getId()] From 54e9dbf82793da9e41525813822e4b8aebe73c52 Mon Sep 17 00:00:00 2001 From: jspijker Date: Mon, 22 Aug 2022 14:57:28 +0200 Subject: [PATCH 18/25] Show device name of failed machine creation in log CURA-9277 Detect and Load Specific printers and Cloud Printer Types --- .../UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index c2d00e98e0..30bbf68f6c 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -400,7 +400,7 @@ class CloudOutputDeviceManager: # We do not use use MachineManager.addMachine here because we need to set the cluster ID before activating it. new_machine = CuraStackBuilder.createMachine(device.name, device.printerType, show_warning_message=False) if not new_machine: - Logger.log("e", "Failed creating a new machine") + Logger.error(f"Failed creating a new machine for {device.name}") return False self._setOutputDeviceMetadata(device, new_machine) From 5082e64f0c1d60e4820a3ba35fd3ca82c8be3051 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 22 Aug 2022 14:58:32 +0200 Subject: [PATCH 19/25] Move cura-import to top of the file Cura-9277 Co-authored-by: joeydelarago --- cura/Settings/CuraStackBuilder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 1c55026dcf..b016db22d7 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -9,6 +9,7 @@ from UM.Settings.Interfaces import DefinitionContainerInterface from UM.Settings.InstanceContainer import InstanceContainer from cura.Machines.ContainerTree import ContainerTree +from cura.CuraApplication import CuraApplication from .AbstractMachine import AbstractMachine from .GlobalStack import GlobalStack from .ExtruderStack import ExtruderStack @@ -277,7 +278,6 @@ class CuraStackBuilder: """ abstract_machine_id = definition_id + "_abstract_machine" - from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() From f6bf7050fb5d574ccfb94310bf58cf9beeab38c6 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 22 Aug 2022 15:01:51 +0200 Subject: [PATCH 20/25] Revert "Move cura-import to top of the file" This reverts commit 5082e64f0c1d60e4820a3ba35fd3ca82c8be3051. --- cura/Settings/CuraStackBuilder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index b016db22d7..1c55026dcf 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -9,7 +9,6 @@ from UM.Settings.Interfaces import DefinitionContainerInterface from UM.Settings.InstanceContainer import InstanceContainer from cura.Machines.ContainerTree import ContainerTree -from cura.CuraApplication import CuraApplication from .AbstractMachine import AbstractMachine from .GlobalStack import GlobalStack from .ExtruderStack import ExtruderStack @@ -278,6 +277,7 @@ class CuraStackBuilder: """ abstract_machine_id = definition_id + "_abstract_machine" + from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() From 5884aa3311578f5e9d8043cdfc747f07eadf314e Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 22 Aug 2022 15:03:48 +0200 Subject: [PATCH 21/25] Add comment about circular import Cura-9277 Co-authored-by: joeydelarago --- cura/Settings/CuraStackBuilder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 1c55026dcf..7eff275457 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -28,7 +28,7 @@ class CuraStackBuilder: :return: The new global stack or None if an error occurred. """ - from cura.CuraApplication import CuraApplication + from cura.CuraApplication import CuraApplication # inline import needed due to circular import application = CuraApplication.getInstance() registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() @@ -92,7 +92,7 @@ class CuraStackBuilder: :param extruder_position: The position of the current extruder. """ - from cura.CuraApplication import CuraApplication + from cura.CuraApplication import CuraApplication # inline import needed due to circular import application = CuraApplication.getInstance() registry = application.getContainerRegistry() From 3413caab6218d550bbc9f0ebc9d266394a0ca686 Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 22 Aug 2022 16:29:08 +0200 Subject: [PATCH 22/25] Set latest.json location back to ultimaker website. CURA-9272 --- conanfile.py | 2 +- cura/ApplicationMetadata.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index ca835a53fc..bcdaeda5d9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -102,7 +102,7 @@ class CuraConan(ConanFile): @property def _cura_latest_url(self): - return "https://raw.githubusercontent.com/Ultimaker/Uranium/CURA-9272_semver_postfix/tests/latest.json" + return "https://software.ultimaker.com/latest.json" @property def requirements_txts(self): diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py index 678f8b7e4a..4938d569e7 100644 --- a/cura/ApplicationMetadata.py +++ b/cura/ApplicationMetadata.py @@ -9,7 +9,7 @@ DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura" DEFAULT_CURA_VERSION = "dev" DEFAULT_CURA_BUILD_TYPE = "" DEFAULT_CURA_DEBUG_MODE = False -DEFAULT_CURA_LATEST_URL = "https://raw.githubusercontent.com/Ultimaker/Uranium/CURA-9272_semver_postfix/tests/latest.json" +DEFAULT_CURA_LATEST_URL = "https://software.ultimaker.com/latest.json" # Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for # example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the From c80dd621696ace2889d7df51a88079bb96c8af66 Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 22 Aug 2022 16:34:18 +0200 Subject: [PATCH 23/25] Fix circular import. CURA-9277 --- cura/Settings/AbstractMachine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py index 3a8dbd54ea..a89201a294 100644 --- a/cura/Settings/AbstractMachine.py +++ b/cura/Settings/AbstractMachine.py @@ -1,7 +1,6 @@ from typing import List from UM.Settings.ContainerStack import ContainerStack -from cura.CuraApplication import CuraApplication from cura.PrinterOutput.PrinterOutputDevice import ConnectionType from cura.Settings.GlobalStack import GlobalStack from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase @@ -16,6 +15,8 @@ class AbstractMachine(GlobalStack): self.setMetaDataEntry("type", "abstract_machine") def getMachines(self) -> List[ContainerStack]: + from cura.CuraApplication import CuraApplication + application = CuraApplication.getInstance() registry = application.getContainerRegistry() From e073adfa9efbe922f1c1058039bbfc285fe8676d Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 22 Aug 2022 17:02:53 +0200 Subject: [PATCH 24/25] Fix conditional in recipe versioning to use proper syntax --- .github/workflows/conan-recipe-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/conan-recipe-version.yml b/.github/workflows/conan-recipe-version.yml index 3ab3d59547..9b662e215b 100644 --- a/.github/workflows/conan-recipe-version.yml +++ b/.github/workflows/conan-recipe-version.yml @@ -135,7 +135,7 @@ jobs: user = "_" channel = "_" else: - if not latest_branch_version.prerelease.contains("."): + if not "." in latest_branch_version.prerelease: # The prerealese did not contain a version number, default it to 1 latest_branch_version.prerelease.append(".1") if event_name == "pull_request": From 21878058eb501647582668ccad5e3214d6f43edd Mon Sep 17 00:00:00 2001 From: joeydelarago Date: Mon, 22 Aug 2022 17:08:55 +0200 Subject: [PATCH 25/25] Fix prerelease string assignment --- .github/workflows/conan-recipe-version.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/conan-recipe-version.yml b/.github/workflows/conan-recipe-version.yml index 9b662e215b..ddadfe1781 100644 --- a/.github/workflows/conan-recipe-version.yml +++ b/.github/workflows/conan-recipe-version.yml @@ -135,9 +135,9 @@ jobs: user = "_" channel = "_" else: - if not "." in latest_branch_version.prerelease: + if latest_branch_version.prerelease and not "." in latest_branch_version.prerelease: # The prerealese did not contain a version number, default it to 1 - latest_branch_version.prerelease.append(".1") + latest_branch_version.prerelease += ".1" if event_name == "pull_request": actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{latest_branch_version.prerelease.lower()}+{buildmetadata}pr_{issue_number}_{no_commits}" else: