diff --git a/plugins/UM3NetworkPrinting/src/Models.py b/plugins/UM3NetworkPrinting/src/Models.py index 89bf665377..e8efa577f6 100644 --- a/plugins/UM3NetworkPrinting/src/Models.py +++ b/plugins/UM3NetworkPrinting/src/Models.py @@ -1,87 +1,32 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional +from collections import namedtuple +ClusterMaterial = namedtuple('ClusterMaterial', [ + 'guid', + 'material', + 'brand', + 'version', + 'color', + 'density' +]) -class BaseModel: - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - def __eq__(self, other): - return self.__dict__ == other.__dict__ if type(self) == type(other) else False - - -## Represents an item in the cluster API response for installed materials. -class ClusterMaterial(BaseModel): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.version = int(self.version) - self.density = float(self.density) - - guid = None # type: Optional[str] - - material = None # type: Optional[str] - - brand = None # type: Optional[str] - - version = None # type: Optional[int] - - color = None # type: Optional[str] - - density = None # type: Optional[float] - - -class LocalMaterialProperties(BaseModel): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.density = float(self.density) - self.diameter = float(self.diameter) - self.weight = float(self.weight) - - density = None # type: Optional[float] - - diameter = None # type: Optional[float] - - weight = None # type: Optional[int] - - -class LocalMaterial(BaseModel): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.properties = LocalMaterialProperties(**self.properties) - self.approximate_diameter = float(self.approximate_diameter) - self.version = int(self.version) - - GUID = None # type: Optional[str] - - id = None # type: Optional[str] - - type = None # type: Optional[str] - - status = None # type: Optional[str] - - base_file = None # type: Optional[str] - - setting_version = None # type: Optional[str] - - version = None # type: Optional[int] - - name = None # type: Optional[str] - - brand = None # type: Optional[str] - - material = None # type: Optional[str] - - color_name = None # type: Optional[str] - - description = None # type: Optional[str] - - adhesion_info = None # type: Optional[str] - - approximate_diameter = None # type: Optional[float] - - properties = None # type: LocalMaterialProperties - - definition = None # type: Optional[str] - - compatible = None # type: Optional[bool] +LocalMaterial = namedtuple('LocalMaterial', [ + 'GUID', + 'id', + 'type', + 'status', + 'base_file', + 'setting_version', + 'version', + 'name', + 'brand', + 'material', + 'color_name', + 'description', + 'adhesion_info', + 'approximate_diameter', + 'properties', + 'definition', + 'compatible' +]) diff --git a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py index 6260752f3f..cbe79aef6a 100644 --- a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py @@ -156,8 +156,8 @@ class SendMaterialJob(Job): # \throw KeyError Raised when on of the materials does not include a valid guid @classmethod def _parseReply(cls, reply: QNetworkReply) -> Dict[str, ClusterMaterial]: - remote_materials_list = json.loads(reply.readAll().data().decode("utf-8")) - return {material["guid"]: ClusterMaterial(**material) for material in remote_materials_list} + remote_materials = json.loads(reply.readAll().data().decode("utf-8")) + return {material["id"]: ClusterMaterial(**material) for material in remote_materials} ## Retrieves a list of local materials # @@ -170,12 +170,12 @@ class SendMaterialJob(Job): material_containers = container_registry.findContainersMetadata(type = "material") # Find the latest version of all material containers in the registry. - for m in material_containers: + local_materials = {} # type: Dict[str, LocalMaterial] + for material in material_containers: try: - material = LocalMaterial(**m) + material = LocalMaterial(**material) if material.GUID not in result or material.version > result.get(material.GUID).version: - result[material.GUID] = material + local_materials[material.GUID] = material except ValueError: - Logger.logException("w", "Local material {} has invalid values.".format(m["id"])) - + Logger.logException("w", "Local material {} has invalid values.".format(material["id"])) return result diff --git a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py index a71ded75b6..73bca2b0ad 100644 --- a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py @@ -1,5 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import json + from typing import Any, List from unittest import TestCase from unittest.mock import patch, call @@ -108,26 +110,25 @@ class TestSendMaterialJob(TestCase): job._onGetRemoteMaterials(reply_mock) # We expect the reply to be called once to try to get the printers from the list (readAll()). - # Given that the parsing there fails we do no expect the device to be called for any follow up. + # Given that the parsing fails we do no expect the device to be called for any follow up. self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls) self.assertEqual(0, device_mock.createFormPart.call_count) - # @patch("PyQt5.QtNetwork.QNetworkReply") - # def test_sendMissingMaterials_withMissingGuid(self, reply_mock): - # reply_mock.attribute.return_value = 200 - # remoteMaterialWithoutGuid = self._REMOTEMATERIAL_WHITE.copy() - # del remoteMaterialWithoutGuid["guid"] - # reply_mock.readAll.return_value = QByteArray(json.dumps([remoteMaterialWithoutGuid]).encode("ascii")) - # - # with mock.patch.object(Logger, "log", new=new_log): - # SendMaterialJob(None).sendMissingMaterials(reply_mock) - # - # reply_mock.attribute.assert_called_with(0) - # self.assertEqual(reply_mock.method_calls, [call.attribute(0), call.readAll()]) - # self._assertLogEntries( - # [("e", "Request material storage on printer: Printer"s answer was missing GUIDs.")], - # _logentries) - # + @patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice") + @patch("PyQt5.QtNetwork.QNetworkReply") + def test_sendMissingMaterials_withMissingGuid(self, reply_mock, device_mock): + reply_mock.attribute.return_value = 200 + remote_material_without_guid = self._REMOTE_MATERIAL_WHITE.copy() + del remote_material_without_guid["guid"] + reply_mock.readAll.return_value = QByteArray(json.dumps([remote_material_without_guid]).encode("ascii")) + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + # We expect the reply to be called once to try to get the printers from the list (readAll()). + # Given that parsing fails we do not expect the device to be called for any follow up. + self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls) + self.assertEqual(1, device_mock.createFormPart.call_count) + # @patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: []) # @patch("PyQt5.QtNetwork.QNetworkReply") # def test_sendMissingMaterials_WithInvalidVersionInLocalMaterial(self, reply_mock):