diff --git a/plugins/Toolbox/src/AuthorsModel.py b/plugins/Toolbox/src/AuthorsModel.py index 81158978b0..4d1c812981 100644 --- a/plugins/Toolbox/src/AuthorsModel.py +++ b/plugins/Toolbox/src/AuthorsModel.py @@ -9,8 +9,12 @@ from PyQt5.QtCore import Qt, pyqtProperty from UM.Qt.ListModel import ListModel -## Model that holds cura packages. By setting the filter property the instances held by this model can be changed. class AuthorsModel(ListModel): + """Model that holds cura packages. + + By setting the filter property the instances held by this model can be changed. + """ + def __init__(self, parent = None) -> None: super().__init__(parent) @@ -67,9 +71,11 @@ class AuthorsModel(ListModel): filtered_items.sort(key = lambda k: k["name"]) self.setItems(filtered_items) - ## Set the filter of this model based on a string. - # \param filter_dict \type{Dict} Dictionary to do the filtering by. def setFilter(self, filter_dict: Dict[str, str]) -> None: + """Set the filter of this model based on a string. + + :param filter_dict: Dictionary to do the filtering by. + """ if filter_dict != self._filter: self._filter = filter_dict self._update() diff --git a/plugins/Toolbox/src/CloudApiModel.py b/plugins/Toolbox/src/CloudApiModel.py index 3386cffb51..b4ff00c6cd 100644 --- a/plugins/Toolbox/src/CloudApiModel.py +++ b/plugins/Toolbox/src/CloudApiModel.py @@ -20,9 +20,9 @@ class CloudApiModel: cloud_api_version=cloud_api_version, ) - ## https://api.ultimaker.com/cura-packages/v1/user/packages/{package_id} @classmethod def userPackageUrl(cls, package_id: str) -> str: + """https://api.ultimaker.com/cura-packages/v1/user/packages/{package_id}""" return (CloudApiModel.api_url_user_packages + "/{package_id}").format( package_id=package_id diff --git a/plugins/Toolbox/src/CloudSync/DiscrepanciesPresenter.py b/plugins/Toolbox/src/CloudSync/DiscrepanciesPresenter.py index ddf1a39e78..a168381efa 100644 --- a/plugins/Toolbox/src/CloudSync/DiscrepanciesPresenter.py +++ b/plugins/Toolbox/src/CloudSync/DiscrepanciesPresenter.py @@ -8,9 +8,11 @@ from UM.Signal import Signal from .SubscribedPackagesModel import SubscribedPackagesModel -## Shows a list of packages to be added or removed. The user can select which packages to (un)install. The user's -# choices are emitted on the `packageMutations` Signal. class DiscrepanciesPresenter(QObject): + """Shows a list of packages to be added or removed. The user can select which packages to (un)install. The user's + + choices are emitted on the `packageMutations` Signal. + """ def __init__(self, app: QtApplication) -> None: super().__init__(app) diff --git a/plugins/Toolbox/src/CloudSync/DownloadPresenter.py b/plugins/Toolbox/src/CloudSync/DownloadPresenter.py index a5d6eee0b6..11c1dffcb4 100644 --- a/plugins/Toolbox/src/CloudSync/DownloadPresenter.py +++ b/plugins/Toolbox/src/CloudSync/DownloadPresenter.py @@ -16,9 +16,11 @@ from cura.UltimakerCloud.UltimakerCloudScope import UltimakerCloudScope from .SubscribedPackagesModel import SubscribedPackagesModel -## Downloads a set of packages from the Ultimaker Cloud Marketplace -# use download() exactly once: should not be used for multiple sets of downloads since this class contains state class DownloadPresenter: + """Downloads a set of packages from the Ultimaker Cloud Marketplace + + use download() exactly once: should not be used for multiple sets of downloads since this class contains state + """ DISK_WRITE_BUFFER_SIZE = 256 * 1024 # 256 KB diff --git a/plugins/Toolbox/src/CloudSync/LicensePresenter.py b/plugins/Toolbox/src/CloudSync/LicensePresenter.py index 778a36fbde..8701120cc5 100644 --- a/plugins/Toolbox/src/CloudSync/LicensePresenter.py +++ b/plugins/Toolbox/src/CloudSync/LicensePresenter.py @@ -43,10 +43,12 @@ class LicensePresenter(QObject): self._compatibility_dialog_path = "resources/qml/dialogs/ToolboxLicenseDialog.qml" - ## Show a license dialog for multiple packages where users can read a license and accept or decline them - # \param plugin_path: Root directory of the Toolbox plugin - # \param packages: Dict[package id, file path] def present(self, plugin_path: str, packages: Dict[str, Dict[str, str]]) -> None: + """Show a license dialog for multiple packages where users can read a license and accept or decline them + + :param plugin_path: Root directory of the Toolbox plugin + :param packages: Dict[package id, file path] + """ if self._presented: Logger.error("{clazz} is single-use. Create a new {clazz} instead", clazz=self.__class__.__name__) return diff --git a/plugins/Toolbox/src/CloudSync/RestartApplicationPresenter.py b/plugins/Toolbox/src/CloudSync/RestartApplicationPresenter.py index 6e2bc53e7e..1242bd3b49 100644 --- a/plugins/Toolbox/src/CloudSync/RestartApplicationPresenter.py +++ b/plugins/Toolbox/src/CloudSync/RestartApplicationPresenter.py @@ -3,9 +3,11 @@ from UM.Message import Message from cura.CuraApplication import CuraApplication -## Presents a dialog telling the user that a restart is required to apply changes -# Since we cannot restart Cura, the app is closed instead when the button is clicked class RestartApplicationPresenter: + """Presents a dialog telling the user that a restart is required to apply changes + + Since we cannot restart Cura, the app is closed instead when the button is clicked + """ def __init__(self, app: CuraApplication) -> None: self._app = app self._i18n_catalog = i18nCatalog("cura") diff --git a/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py b/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py index fc3dfaea38..89f20815bf 100644 --- a/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py +++ b/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py @@ -16,20 +16,23 @@ from .RestartApplicationPresenter import RestartApplicationPresenter from .SubscribedPackagesModel import SubscribedPackagesModel -## Orchestrates the synchronizing of packages from the user account to the installed packages -# Example flow: -# - CloudPackageChecker compares a list of packages the user `subscribed` to in their account -# If there are `discrepancies` between the account and locally installed packages, they are emitted -# - DiscrepanciesPresenter shows a list of packages to be added or removed to the user. It emits the `packageMutations` -# the user selected to be performed -# - The SyncOrchestrator uses PackageManager to remove local packages the users wants to see removed -# - The DownloadPresenter shows a download progress dialog. It emits A tuple of succeeded and failed downloads -# - The LicensePresenter extracts licenses from the downloaded packages and presents a license for each package to -# be installed. It emits the `licenseAnswers` signal for accept or declines -# - The CloudApiClient removes the declined packages from the account -# - The SyncOrchestrator uses PackageManager to install the downloaded packages and delete temp files. -# - The RestartApplicationPresenter notifies the user that a restart is required for changes to take effect class SyncOrchestrator(Extension): + """Orchestrates the synchronizing of packages from the user account to the installed packages + + Example flow: + + - CloudPackageChecker compares a list of packages the user `subscribed` to in their account + If there are `discrepancies` between the account and locally installed packages, they are emitted + - DiscrepanciesPresenter shows a list of packages to be added or removed to the user. It emits the `packageMutations` + the user selected to be performed + - The SyncOrchestrator uses PackageManager to remove local packages the users wants to see removed + - The DownloadPresenter shows a download progress dialog. It emits A tuple of succeeded and failed downloads + - The LicensePresenter extracts licenses from the downloaded packages and presents a license for each package to + be installed. It emits the `licenseAnswers` signal for accept or declines + - The CloudApiClient removes the declined packages from the account + - The SyncOrchestrator uses PackageManager to install the downloaded packages and delete temp files. + - The RestartApplicationPresenter notifies the user that a restart is required for changes to take effect + """ def __init__(self, app: CuraApplication) -> None: super().__init__() @@ -63,10 +66,12 @@ class SyncOrchestrator(Extension): self._download_presenter.done.connect(self._onDownloadFinished) self._download_presenter.download(mutations) - ## Called when a set of packages have finished downloading - # \param success_items: Dict[package_id, Dict[str, str]] - # \param error_items: List[package_id] def _onDownloadFinished(self, success_items: Dict[str, Dict[str, str]], error_items: List[str]) -> None: + """Called when a set of packages have finished downloading + + :param success_items:: Dict[package_id, Dict[str, str]] + :param error_items:: List[package_id] + """ if error_items: message = i18n_catalog.i18nc("@info:generic", "{} plugins failed to download".format(len(error_items))) self._showErrorMessage(message) @@ -96,7 +101,8 @@ class SyncOrchestrator(Extension): if has_changes: self._restart_presenter.present() - ## Logs an error and shows it to the user def _showErrorMessage(self, text: str): + """Logs an error and shows it to the user""" + Logger.error(text) Message(text, lifetime=0).show() diff --git a/plugins/Toolbox/src/ConfigsModel.py b/plugins/Toolbox/src/ConfigsModel.py index a92f9c0d93..a53817653f 100644 --- a/plugins/Toolbox/src/ConfigsModel.py +++ b/plugins/Toolbox/src/ConfigsModel.py @@ -6,8 +6,9 @@ from PyQt5.QtCore import Qt from UM.Qt.ListModel import ListModel -## Model that holds supported configurations (for material/quality packages). class ConfigsModel(ListModel): + """Model that holds supported configurations (for material/quality packages).""" + def __init__(self, parent = None): super().__init__(parent) diff --git a/plugins/Toolbox/src/PackagesModel.py b/plugins/Toolbox/src/PackagesModel.py index c84e0da5d0..4cbabde07e 100644 --- a/plugins/Toolbox/src/PackagesModel.py +++ b/plugins/Toolbox/src/PackagesModel.py @@ -12,8 +12,12 @@ from UM.Qt.ListModel import ListModel from .ConfigsModel import ConfigsModel -## Model that holds Cura packages. By setting the filter property the instances held by this model can be changed. class PackagesModel(ListModel): + """Model that holds Cura packages. + + By setting the filter property the instances held by this model can be changed. + """ + def __init__(self, parent = None): super().__init__(parent) @@ -131,9 +135,11 @@ class PackagesModel(ListModel): filtered_items.sort(key = lambda k: k["name"]) self.setItems(filtered_items) - ## Set the filter of this model based on a string. - # \param filter_dict \type{Dict} Dictionary to do the filtering by. def setFilter(self, filter_dict: Dict[str, str]) -> None: + """Set the filter of this model based on a string. + + :param filter_dict: Dictionary to do the filtering by. + """ if filter_dict != self._filter: self._filter = filter_dict self._update() diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index 3b1f85a69e..632af456b5 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -37,10 +37,10 @@ try: except ImportError: CuraMarketplaceRoot = DEFAULT_MARKETPLACE_ROOT -# todo Remove license and download dialog, use SyncOrchestrator instead -## Provides a marketplace for users to download plugins an materials class Toolbox(QObject, Extension): + """Provides a marketplace for users to download plugins an materials""" + def __init__(self, application: CuraApplication) -> None: super().__init__() @@ -135,8 +135,9 @@ class Toolbox(QObject, Extension): closeLicenseDialog = pyqtSignal() uninstallVariablesChanged = pyqtSignal() - ## Go back to the start state (welcome screen or loading if no login required) def _restart(self): + """Go back to the start state (welcome screen or loading if no login required)""" + # For an Essentials build, login is mandatory if not self._application.getCuraAPI().account.isLoggedIn and ApplicationMetadata.IsEnterpriseVersion: self.setViewPage("welcome") @@ -311,10 +312,13 @@ class Toolbox(QObject, Extension): self.restartRequiredChanged.emit() return package_id - ## Check package usage and uninstall - # If the package is in use, you'll get a confirmation dialog to set everything to default @pyqtSlot(str) def checkPackageUsageAndUninstall(self, package_id: str) -> None: + """Check package usage and uninstall + + If the package is in use, you'll get a confirmation dialog to set everything to default + """ + package_used_materials, package_used_qualities = self._package_manager.getMachinesUsingPackage(package_id) if package_used_materials or package_used_qualities: # Set up "uninstall variables" for resetMaterialsQualitiesAndUninstall @@ -352,10 +356,13 @@ class Toolbox(QObject, Extension): if self._confirm_reset_dialog is not None: self._confirm_reset_dialog.close() - ## Uses "uninstall variables" to reset qualities and materials, then uninstall - # It's used as an action on Confirm reset on Uninstall @pyqtSlot() def resetMaterialsQualitiesAndUninstall(self) -> None: + """Uses "uninstall variables" to reset qualities and materials, then uninstall + + It's used as an action on Confirm reset on Uninstall + """ + application = CuraApplication.getInstance() machine_manager = application.getMachineManager() container_tree = ContainerTree.getInstance() @@ -418,8 +425,9 @@ class Toolbox(QObject, Extension): self._restart_required = True self.restartRequiredChanged.emit() - ## Actual update packages that are in self._to_update def _update(self) -> None: + """Actual update packages that are in self._to_update""" + if self._to_update: plugin_id = self._to_update.pop(0) remote_package = self.getRemotePackage(plugin_id) @@ -433,9 +441,10 @@ class Toolbox(QObject, Extension): if self._to_update: self._application.callLater(self._update) - ## Update a plugin by plugin_id @pyqtSlot(str) def update(self, plugin_id: str) -> None: + """Update a plugin by plugin_id""" + self._to_update.append(plugin_id) self._application.callLater(self._update) @@ -714,9 +723,10 @@ class Toolbox(QObject, Extension): self._active_package = package self.activePackageChanged.emit() - ## The active package is the package that is currently being downloaded @pyqtProperty(QObject, fset = setActivePackage, notify = activePackageChanged) def activePackage(self) -> Optional[QObject]: + """The active package is the package that is currently being downloaded""" + return self._active_package def setViewCategory(self, category: str = "plugin") -> None: @@ -724,7 +734,7 @@ class Toolbox(QObject, Extension): self._view_category = category self.viewChanged.emit() - ## Function explicitly defined so that it can be called through the callExtensionsMethod + # Function explicitly defined so that it can be called through the callExtensionsMethod # which cannot receive arguments. def setViewCategoryToMaterials(self) -> None: self.setViewCategory("material") diff --git a/plugins/TrimeshReader/TrimeshReader.py b/plugins/TrimeshReader/TrimeshReader.py index 6ed7435f88..f746c55cc5 100644 --- a/plugins/TrimeshReader/TrimeshReader.py +++ b/plugins/TrimeshReader/TrimeshReader.py @@ -22,8 +22,10 @@ from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator # Adde if TYPE_CHECKING: from UM.Scene.SceneNode import SceneNode -## Class that leverages Trimesh to import files. + class TrimeshReader(MeshReader): + """Class that leverages Trimesh to import files.""" + def __init__(self) -> None: super().__init__() @@ -79,11 +81,13 @@ class TrimeshReader(MeshReader): ) ) - ## Reads a file using Trimesh. - # \param file_name The file path. This is assumed to be one of the file - # types that Trimesh can read. It will not be checked again. - # \return A scene node that contains the file's contents. def _read(self, file_name: str) -> Union["SceneNode", List["SceneNode"]]: + """Reads a file using Trimesh. + + :param file_name: The file path. This is assumed to be one of the file + types that Trimesh can read. It will not be checked again. + :return: A scene node that contains the file's contents. + """ # CURA-6739 # GLTF files are essentially JSON files. If you directly give a file name to trimesh.load(), it will # try to figure out the format, but for GLTF, it loads it as a binary file with flags "rb", and the json.load() @@ -130,13 +134,14 @@ class TrimeshReader(MeshReader): node.setParent(group_node) return group_node - ## Converts a Trimesh to Uranium's MeshData. - # \param tri_node A Trimesh containing the contents of a file that was - # just read. - # \param file_name The full original filename used to watch for changes - # \return Mesh data from the Trimesh in a way that Uranium can understand - # it. def _toMeshData(self, tri_node: trimesh.base.Trimesh, file_name: str = "") -> MeshData: + """Converts a Trimesh to Uranium's MeshData. + + :param tri_node: A Trimesh containing the contents of a file that was just read. + :param file_name: The full original filename used to watch for changes + :return: Mesh data from the Trimesh in a way that Uranium can understand it. + """ + tri_faces = tri_node.faces tri_vertices = tri_node.vertices