diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index baa8e3ed29..6b5766c127 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -77,6 +77,10 @@ class SettingVisibilityPresetsModel(QObject): items.append(setting_visibility_preset) + # Add the "all" visibility: + all_setting_visibility_preset = SettingVisibilityPreset(preset_id = "all", name = "All", weight = 9001) + all_setting_visibility_preset.setSettings(list(CuraApplication.getInstance().getMachineManager().getAllSettingKeys())) + items.append(all_setting_visibility_preset) # Sort them on weight (and if that fails, use ID) items.sort(key = lambda k: (int(k.weight), k.presetId)) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 876f10ebf8..2a9b2e8f83 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -4,12 +4,11 @@ import time import re import unicodedata -from typing import Any, List, Dict, TYPE_CHECKING, Optional, cast +from typing import Any, List, Dict, TYPE_CHECKING, Optional, cast, Set from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer from UM.ConfigurationErrorMessage import ConfigurationErrorMessage -from UM.Decorators import deprecated from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.Interfaces import ContainerInterface @@ -212,10 +211,13 @@ class MachineManager(QObject): @pyqtProperty(int, constant=True) def totalNumberOfSettings(self) -> int: - general_definition_containers = CuraContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter") + return len(self.getAllSettingKeys()) + + def getAllSettingKeys(self) -> Set[str]: + general_definition_containers = CuraContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter") if not general_definition_containers: - return 0 - return len(general_definition_containers[0].getAllKeys()) + return set() + return general_definition_containers[0].getAllKeys() ## Triggered when the global container stack is changed in CuraApplication. def _onGlobalContainerChanged(self) -> None: diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 6d6f19c57c..4282806ff5 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -292,8 +292,9 @@ class SimulationView(CuraView): # # \param layer_view_type integer as in SimulationView.qml and this class def setSimulationViewType(self, layer_view_type: int) -> None: - self._layer_view_type = layer_view_type - self.currentLayerNumChanged.emit() + if layer_view_type != self._layer_view_type: + self._layer_view_type = layer_view_type + self.currentLayerNumChanged.emit() ## Return the layer view type, integer as in SimulationView.qml and this class def getSimulationViewType(self) -> int: @@ -571,6 +572,8 @@ class SimulationView(CuraView): def _onCurrentLayerNumChanged(self) -> None: self.calculateMaxPathsOnLayer(self._current_layer_num) + scene = Application.getInstance().getController().getScene() + scene.sceneChanged.emit(scene.getRoot()) def _startUpdateTopLayers(self) -> None: if not self._compatibility_mode: diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index 58a004cc31..1183244ab3 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -149,6 +149,9 @@ class SimulationViewProxy(QObject): self.currentPathChanged.emit() self._layerActivityChanged() + scene = Application.getInstance().getController().getScene() + scene.sceneChanged.emit(scene.getRoot()) + def _onMaxLayersChanged(self): self.maxLayersChanged.emit() diff --git a/plugins/Toolbox/resources/qml/dialogs/CompatibilityDialog.qml b/plugins/Toolbox/resources/qml/dialogs/CompatibilityDialog.qml new file mode 100644 index 0000000000..f5a20986d1 --- /dev/null +++ b/plugins/Toolbox/resources/qml/dialogs/CompatibilityDialog.qml @@ -0,0 +1,142 @@ +// Copyright (c) 2020 Ultimaker B.V. +// Toolbox is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.10 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.3 + +import UM 1.1 as UM +import Cura 1.6 as Cura + + +UM.Dialog{ + visible: true + title: catalog.i18nc("@title", "Changes from your account") + width: UM.Theme.getSize("popup_dialog").width + height: UM.Theme.getSize("popup_dialog").height + minimumWidth: width + maximumWidth: minimumWidth + minimumHeight: height + maximumHeight: minimumHeight + margin: 0 + + Rectangle + { + id: root + anchors.fill: parent + color: UM.Theme.getColor("main_background") + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + ScrollView + { + width: parent.width + height: parent.height - nextButton.height - nextButton.anchors.margins * 2 // We want some leftover space for the button at the bottom + clip: true + + Column + { + anchors.fill: parent + anchors.margins: UM.Theme.getSize("default_margin").width + + // Compatible packages + Label + { + font: UM.Theme.getFont("default") + text: catalog.i18nc("@label", "The following packages will be added:") + color: UM.Theme.getColor("text") + height: contentHeight + UM.Theme.getSize("default_margin").height + } + Repeater + { + model: toolbox.subscribedPackagesModel + Component + { + Item + { + width: parent.width + property var lineHeight: 60 + visible: model.is_compatible == "True" ? true : false + height: visible ? (lineHeight + UM.Theme.getSize("default_margin").height) : 0 // We only show the compatible packages here + Image + { + id: packageIcon + source: model.icon_url || "../../images/logobot.svg" + height: lineHeight + width: height + mipmap: true + fillMode: Image.PreserveAspectFit + } + Label + { + text: model.name + font: UM.Theme.getFont("medium_bold") + anchors.left: packageIcon.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.verticalCenter: packageIcon.verticalCenter + color: UM.Theme.getColor("text") + elide: Text.ElideRight + } + } + } + } + + // Incompatible packages + Label + { + font: UM.Theme.getFont("default") + text: catalog.i18nc("@label", "The following packages can not be installed because of incompatible Cura version:") + color: UM.Theme.getColor("text") + height: contentHeight + UM.Theme.getSize("default_margin").height + } + Repeater + { + model: toolbox.subscribedPackagesModel + Component + { + Item + { + width: parent.width + property var lineHeight: 60 + visible: model.is_compatible == "True" ? false : true + height: visible ? (lineHeight + UM.Theme.getSize("default_margin").height) : 0 // We only show the incompatible packages here + Image + { + id: packageIcon + source: model.icon_url || "../../images/logobot.svg" + height: lineHeight + width: height + mipmap: true + fillMode: Image.PreserveAspectFit + } + Label + { + text: model.name + font: UM.Theme.getFont("medium_bold") + anchors.left: packageIcon.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.verticalCenter: packageIcon.verticalCenter + color: UM.Theme.getColor("text") + elide: Text.ElideRight + } + } + } + } + } + + } // End of ScrollView + + Cura.ActionButton + { + id: nextButton + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.margins: UM.Theme.getSize("default_margin").height + text: catalog.i18nc("@button", "Next") + } + } +} diff --git a/plugins/Toolbox/src/SubscribedPackagesModel.py b/plugins/Toolbox/src/SubscribedPackagesModel.py new file mode 100644 index 0000000000..f8340ab7a0 --- /dev/null +++ b/plugins/Toolbox/src/SubscribedPackagesModel.py @@ -0,0 +1,46 @@ +# Copyright (c) 2020 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import Qt +from UM.Qt.ListModel import ListModel +from cura import ApplicationMetadata + + +class SubscribedPackagesModel(ListModel): + def __init__(self, parent = None): + super().__init__(parent) + + self._metadata = None + self._discrepancies = None + self._sdk_version = ApplicationMetadata.CuraSDKVersion + + self.addRoleName(Qt.UserRole + 1, "name") + self.addRoleName(Qt.UserRole + 2, "icon_url") + self.addRoleName(Qt.UserRole + 3, "is_compatible") + + def setMetadata(self, data): + if self._metadata != data: + self._metadata = data + + def addValue(self, discrepancy): + if self._discrepancies != discrepancy: + self._discrepancies = discrepancy + + def update(self): + items = [] + + for item in self._metadata: + if item["package_id"] not in self._discrepancies: + continue + package = {"name": item["display_name"], "sdk_versions": item["sdk_versions"]} + if self._sdk_version not in item["sdk_versions"]: + package.update({"is_compatible": "False"}) + else: + package.update({"is_compatible": "True"}) + try: + package.update({"icon_url": item["icon_url"]}) + except KeyError: # There is no 'icon_url" in the response payload for this package + package.update({"icon_url": ""}) + + items.append(package) + self.setItems(items) \ No newline at end of file diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index 27197275b8..af0a0748e7 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -15,6 +15,7 @@ from UM.PluginRegistry import PluginRegistry from UM.Extension import Extension from UM.i18n import i18nCatalog from UM.Version import Version +from UM.Message import Message from cura import ApplicationMetadata from cura import UltimakerCloudAuthentication @@ -23,6 +24,7 @@ from cura.Machines.ContainerTree import ContainerTree from .AuthorsModel import AuthorsModel from .PackagesModel import PackagesModel +from .SubscribedPackagesModel import SubscribedPackagesModel if TYPE_CHECKING: from cura.Settings.GlobalStack import GlobalStack @@ -58,17 +60,19 @@ class Toolbox(QObject, Extension): # The responses as given by the server parsed to a list. self._server_response_data = { - "authors": [], - "packages": [], - "updates": [], + "authors": [], + "packages": [], + "updates": [], + "subscribed_packages": [], } # type: Dict[str, List[Any]] # Models: self._models = { - "authors": AuthorsModel(self), - "packages": PackagesModel(self), - "updates": PackagesModel(self), - } # type: Dict[str, Union[AuthorsModel, PackagesModel]] + "authors": AuthorsModel(self), + "packages": PackagesModel(self), + "updates": PackagesModel(self), + "subscribed_packages": SubscribedPackagesModel(self), + } # type: Dict[str, Union[AuthorsModel, PackagesModel, SubscribedPackagesModel]] self._plugins_showcase_model = PackagesModel(self) self._plugins_available_model = PackagesModel(self) @@ -161,7 +165,7 @@ class Toolbox(QObject, Extension): @pyqtSlot(str, int) def ratePackage(self, package_id: str, rating: int) -> None: - url = QUrl("{base_url}/packages/{package_id}/ratings".format(base_url=self._api_url, package_id = package_id)) + url = QUrl("{base_url}/packages/{package_id}/ratings".format(base_url = self._api_url, package_id = package_id)) self._rate_request = QNetworkRequest(url) for header_name, header_value in self._request_headers: @@ -197,6 +201,11 @@ class Toolbox(QObject, Extension): cloud_api_version = self._cloud_api_version, sdk_version = self._sdk_version ) + # https://api.ultimaker.com/cura-packages/v1/user/packages + self._api_url_user_packages = "{cloud_api_root}/cura-packages/v{cloud_api_version}/user/packages".format( + cloud_api_root = self._cloud_api_root, + cloud_api_version = self._cloud_api_version, + ) # We need to construct a query like installed_packages=ID:VERSION&installed_packages=ID:VERSION, etc. installed_package_ids_with_versions = [":".join(items) for items in @@ -207,15 +216,18 @@ class Toolbox(QObject, Extension): "authors": QUrl("{base_url}/authors".format(base_url = self._api_url)), "packages": QUrl("{base_url}/packages".format(base_url = self._api_url)), "updates": QUrl("{base_url}/packages/package-updates?installed_packages={query}".format( - base_url = self._api_url, query = installed_packages_query)) + base_url = self._api_url, query = installed_packages_query)), + "subscribed_packages": QUrl(self._api_url_user_packages) } self._application.getCuraAPI().account.loginStateChanged.connect(self._restart) + self._application.getCuraAPI().account.loginStateChanged.connect(self._fetchUserSubscribedPackages) # On boot we check which packages have updates. if CuraApplication.getInstance().getPreferences().getValue("info/automatic_update_check") and len(installed_package_ids_with_versions) > 0: # Request the latest and greatest! self._fetchPackageUpdates() + self._fetchUserSubscribedPackages() def _prepareNetworkManager(self): if self._network_manager is not None: @@ -237,6 +249,11 @@ class Toolbox(QObject, Extension): # Gather installed packages: self._updateInstalledModels() + def _fetchUserSubscribedPackages(self): + if self._application.getCuraAPI().account.isLoggedIn: + self._prepareNetworkManager() + self._makeRequestByType("subscribed_packages") + # Displays the toolbox @pyqtSlot() def launch(self) -> None: @@ -540,9 +557,7 @@ class Toolbox(QObject, Extension): @pyqtSlot(str, result = bool) def isEnabled(self, package_id: str) -> bool: - if package_id in self._plugin_registry.getActivePlugins(): - return True - return False + return package_id in self._plugin_registry.getActivePlugins() # Check for plugins that were installed with the old plugin browser def isOldPlugin(self, plugin_id: str) -> bool: @@ -561,10 +576,11 @@ class Toolbox(QObject, Extension): # Make API Calls # -------------------------------------------------------------------------- def _makeRequestByType(self, request_type: str) -> None: - Logger.log("d", "Requesting %s metadata from server.", request_type) + Logger.log("d", "Requesting '%s' metadata from server.", request_type) request = QNetworkRequest(self._request_urls[request_type]) for header_name, header_value in self._request_headers: request.setRawHeader(header_name, header_value) + self._updateRequestHeader() if self._network_manager: self._network_manager.get(request) @@ -661,6 +677,8 @@ class Toolbox(QObject, Extension): # Tell the package manager that there's a new set of updates available. packages = set([pkg["package_id"] for pkg in self._server_response_data[response_type]]) self._package_manager.setPackagesWithUpdate(packages) + elif response_type == "subscribed_packages": + self._checkCompatibilities(json_data["data"]) self.metadataChanged.emit() @@ -674,9 +692,38 @@ class Toolbox(QObject, Extension): Logger.log("w", "Unable to connect with the server, we got a response code %s while trying to connect to %s", reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url()) self.setViewPage("errored") self.resetDownload() - elif reply.operation() == QNetworkAccessManager.PutOperation: - # Ignore any operation that is not a get operation - pass + + def _checkCompatibilities(self, json_data) -> None: + user_subscribed_packages = [plugin["package_id"] for plugin in json_data] + user_installed_packages = self._package_manager.getUserInstalledPackages() + + # We check if there are packages installed in Cloud Marketplace but not in Cura marketplace (discrepancy) + package_discrepancy = list(set(user_subscribed_packages).difference(user_installed_packages)) + if package_discrepancy: + self._models["subscribed_packages"].addValue(package_discrepancy) + self._models["subscribed_packages"].update() + Logger.log("d", "Discrepancy found between Cloud subscribed packages and Cura installed packages") + sync_message = Message(i18n_catalog.i18nc( + "@info:generic", + "\nDo you want to sync material and software packages with your account?"), + lifetime=0, + title=i18n_catalog.i18nc("@info:title", "Changes detected from your Ultimaker account", )) + sync_message.addAction("sync", + name=i18n_catalog.i18nc("@action:button", "Sync"), + icon="", + description="Sync your Cloud subscribed packages to your local environment.", + button_align=Message.ActionButtonAlignment.ALIGN_RIGHT) + + sync_message.actionTriggered.connect(self._onSyncButtonClicked) + sync_message.show() + + def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None: + sync_message.hide() + compatibility_dialog_path = "resources/qml/dialogs/CompatibilityDialog.qml" + plugin_path_prefix = PluginRegistry.getInstance().getPluginPath(self.getPluginId()) + if plugin_path_prefix: + path = os.path.join(plugin_path_prefix, compatibility_dialog_path) + self.compatibility_dialog_view = self._application.getInstance().createQmlComponent(path, {"toolbox": self}) # This function goes through all known remote versions of a package and notifies the package manager of this change def _notifyPackageManager(self): @@ -772,39 +819,43 @@ class Toolbox(QObject, Extension): # Exposed Models: # -------------------------------------------------------------------------- - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def authorsModel(self) -> AuthorsModel: return cast(AuthorsModel, self._models["authors"]) - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) + def subscribedPackagesModel(self) -> SubscribedPackagesModel: + return cast(SubscribedPackagesModel, self._models["subscribed_packages"]) + + @pyqtProperty(QObject, constant = True) def packagesModel(self) -> PackagesModel: return cast(PackagesModel, self._models["packages"]) - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def pluginsShowcaseModel(self) -> PackagesModel: return self._plugins_showcase_model - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def pluginsAvailableModel(self) -> PackagesModel: return self._plugins_available_model - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def pluginsInstalledModel(self) -> PackagesModel: return self._plugins_installed_model - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def materialsShowcaseModel(self) -> AuthorsModel: return self._materials_showcase_model - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def materialsAvailableModel(self) -> AuthorsModel: return self._materials_available_model - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def materialsInstalledModel(self) -> PackagesModel: return self._materials_installed_model - @pyqtProperty(QObject, constant=True) + @pyqtProperty(QObject, constant = True) def materialsGenericModel(self) -> PackagesModel: return self._materials_generic_model diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index e13f3e6f8b..46d194c6a0 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -7650,7 +7650,7 @@ "default_value": 50, "minimum_value": "1", "minimum_value_warning": "25", - "maximum_value": "100", + "maximum_value_warning": "100", "settable_per_mesh": true }, "small_feature_speed_factor_0": @@ -7663,7 +7663,7 @@ "value": "small_feature_speed_factor", "minimum_value": "1", "minimum_value_warning": "25", - "maximum_value": "100", + "maximum_value_warning": "100", "settable_per_mesh": true } } diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index b6edc3a4a9..56cb001ff5 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -14,7 +14,6 @@ Menu property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel() - signal showAllSettings() signal collapseAllCategories() Instantiator @@ -37,17 +36,6 @@ Menu onObjectRemoved: menu.removeItem(object) } - MenuSeparator {} - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Show All Settings") - checkable: false - exclusiveGroup: group - onTriggered: - { - showAllSettings(); - } - } MenuSeparator {} MenuItem { diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml index 047710a1c8..fd4a181a56 100644 --- a/resources/qml/Settings/SettingCategory.qml +++ b/resources/qml/Settings/SettingCategory.qml @@ -19,7 +19,7 @@ Button background: Rectangle { id: backgroundRectangle - implicitHeight: UM.Theme.getSize("section").height + height: UM.Theme.getSize("section").height color: { if (base.color) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index c27da466b6..eefcefeadf 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -187,12 +187,6 @@ Item menu: SettingVisibilityPresetsMenu { - onShowAllSettings: - { - definitionsModel.setAllVisible(true) - filter.updateDefinitionModel() - } - onCollapseAllCategories: { settingsSearchTimer.stop() @@ -230,7 +224,6 @@ Item ListView { id: contents - spacing: UM.Theme.getSize("default_lining").height cacheBuffer: 1000000 // Set a large cache to effectively just cache every list item. model: UM.SettingDefinitionsModel @@ -259,7 +252,7 @@ Item id: delegate width: scrollView.width - height: provider.properties.enabled === "True" ? UM.Theme.getSize("section").height : - contents.spacing + height: provider.properties.enabled === "True" ? UM.Theme.getSize("section").height + 2 * UM.Theme.getSize("default_lining").height : 0 Behavior on height { NumberAnimation { duration: 100 } } opacity: provider.properties.enabled === "True" ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 100 } } diff --git a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg index 9d6fcd0159..df82701b13 100644 --- a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg +++ b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg @@ -12,7 +12,6 @@ material = generic_petg [values] material_print_temperature = =default_material_print_temperature + 35 -material_bed_temperature = 70 cool_fan_enabled = False speed_print = 30 diff --git a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg index 67dbe2c33b..9ab962068b 100644 --- a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg +++ b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg @@ -12,7 +12,6 @@ material = generic_petg [values] material_print_temperature = =default_material_print_temperature + 35 -material_bed_temperature = 70 cool_fan_enabled = False speed_print = 30 diff --git a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg index 5f79e3b1c4..77e5f3dc0e 100644 --- a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg +++ b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg @@ -12,7 +12,6 @@ material = generic_petg [values] material_print_temperature = =default_material_print_temperature + 35 -material_bed_temperature = 70 cool_fan_enabled = False speed_print = 30 diff --git a/run_mypy.py b/run_mypy.py index 6be424bda8..d93e1cafc8 100644 --- a/run_mypy.py +++ b/run_mypy.py @@ -1,8 +1,9 @@ #!/usr/bin/env python import os import sys -import subprocess - +from multiprocessing.dummy import Pool +from functools import partial +from subprocess import call # A quick Python implementation of unix 'where' command. def where(exe_name: str, search_path: str = os.getenv("PATH")) -> str: @@ -62,21 +63,23 @@ def main(): mods = ["cura"] + plugins + findModules("plugins/VersionUpgrade") success_code = 0 - for mod in mods: - print("------------- Checking module {mod}".format(**locals())) - if sys.platform == "win32": - result = subprocess.run([mypy_module, "-p", mod, "--ignore-missing-imports"]) - else: - result = subprocess.run([sys.executable, mypy_module, "-p", mod, "--ignore-missing-imports"]) - if result.returncode != 0: - print("\nModule {mod} failed checking. :(".format(**locals())) - success_code = 1 - if success_code: - print("\n\nSome modules failed checking!") + + pool = Pool(2) # Run two commands at once + + if sys.platform == "win32": + commands = ["%s -p %s --ignore-missing-imports" % (mypy_module, mod) for mod in mods] else: - print("\n\nDone checking. All is good.") + commands = ["%s %s -p %s --ignore-missing-imports" % (sys.executable, mypy_module, mod) for mod in mods] + + for i, returncode in enumerate(pool.imap(partial(call, shell=True), commands)): + if returncode != 0: + print("\nCommand %s failed checking. :(" % commands[i]) + success_code = 1 + if success_code: + print("MYPY check was compleded, but did not pass") + else: + print("MYPY check was compleded and passed with flying colors") return success_code - if __name__ == "__main__": - sys.exit(main()) + sys.exit(main()) \ No newline at end of file diff --git a/tests/Settings/TestSettingVisibilityPresets.py b/tests/Settings/TestSettingVisibilityPresets.py index b82aa62ea7..017bb6077a 100644 --- a/tests/Settings/TestSettingVisibilityPresets.py +++ b/tests/Settings/TestSettingVisibilityPresets.py @@ -1,4 +1,4 @@ -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch import os.path @@ -28,8 +28,8 @@ def test_createVisibilityPresetFromLocalFile(): def test_visibilityFromPrevious(): # This test checks that all settings in basic are in advanced and all settings in advanced are in expert. - - visibility_model = SettingVisibilityPresetsModel(Preferences()) + with patch("cura.CuraApplication.CuraApplication.getInstance"): + visibility_model = SettingVisibilityPresetsModel(Preferences()) basic_visibility = visibility_model.getVisibilityPresetById("basic") advanced_visibility = visibility_model.getVisibilityPresetById("advanced") @@ -46,7 +46,8 @@ def test_visibilityFromPrevious(): def test_setActivePreset(): preferences = Preferences() - visibility_model = SettingVisibilityPresetsModel(preferences) + with patch("cura.CuraApplication.CuraApplication.getInstance"): + visibility_model = SettingVisibilityPresetsModel(preferences) visibility_model.activePresetChanged = MagicMock() # Ensure that we start off with basic (since we didn't change anyting just yet!) assert visibility_model.activePreset == "basic" @@ -71,13 +72,13 @@ def test_preferenceChanged(): preferences = Preferences() # Set the visible_settings to something silly preferences.addPreference("general/visible_settings", "omgzomg") - visibility_model = SettingVisibilityPresetsModel(preferences) + with patch("cura.CuraApplication.CuraApplication.getInstance"): + visibility_model = SettingVisibilityPresetsModel(preferences) visibility_model.activePresetChanged = MagicMock() assert visibility_model.activePreset == "custom" # This should make the model start at "custom assert visibility_model.activePresetChanged.emit.call_count == 0 - basic_visibility = visibility_model.getVisibilityPresetById("basic") new_visibility_string = ";".join(basic_visibility.settings) preferences.setValue("general/visible_settings", new_visibility_string)