mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-06 13:34:01 -06:00
Merge branch 'master' into feature_intent_container_tree
This commit is contained in:
commit
b18565d9cf
153 changed files with 12828 additions and 252 deletions
|
@ -6,7 +6,7 @@ import io
|
|||
import json #To parse the product-to-id mapping file.
|
||||
import os.path #To find the product-to-id mapping.
|
||||
import sys
|
||||
from typing import Any, Dict, List, Optional, Tuple, cast, Set
|
||||
from typing import Any, Dict, List, Optional, Tuple, cast, Set, Union
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from UM.Resources import Resources
|
||||
|
@ -20,7 +20,10 @@ from cura.CuraApplication import CuraApplication
|
|||
from cura.Machines.ContainerTree import ContainerTree
|
||||
from cura.Machines.VariantType import VariantType
|
||||
|
||||
from .XmlMaterialValidator import XmlMaterialValidator
|
||||
try:
|
||||
from .XmlMaterialValidator import XmlMaterialValidator
|
||||
except (ImportError, SystemError):
|
||||
import XmlMaterialValidator # type: ignore # This fixes the tests not being able to import.
|
||||
|
||||
|
||||
## Handles serializing and deserializing material containers from an XML file
|
||||
|
@ -41,11 +44,11 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
#
|
||||
# \param xml_version: The version number found in an XML file.
|
||||
# \return The corresponding setting_version.
|
||||
@classmethod
|
||||
def xmlVersionToSettingVersion(cls, xml_version: str) -> int:
|
||||
@staticmethod
|
||||
def xmlVersionToSettingVersion(xml_version: str) -> int:
|
||||
if xml_version == "1.3":
|
||||
return CuraApplication.SettingVersion
|
||||
return 0 #Older than 1.3.
|
||||
return 0 # Older than 1.3.
|
||||
|
||||
def getInheritedFiles(self):
|
||||
return self._inherited_files
|
||||
|
@ -407,7 +410,8 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
self._combineElement(self._expandMachinesXML(result), self._expandMachinesXML(second))
|
||||
return result
|
||||
|
||||
def _createKey(self, element):
|
||||
@staticmethod
|
||||
def _createKey(element):
|
||||
key = element.tag.split("}")[-1]
|
||||
if "key" in element.attrib:
|
||||
key += " key:" + element.attrib["key"]
|
||||
|
@ -423,15 +427,15 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
|
||||
# Recursively merges XML elements. Updates either the text or children if another element is found in first.
|
||||
# If it does not exist, copies it from second.
|
||||
def _combineElement(self, first, second):
|
||||
@staticmethod
|
||||
def _combineElement(first, second):
|
||||
# Create a mapping from tag name to element.
|
||||
|
||||
mapping = {}
|
||||
for element in first:
|
||||
key = self._createKey(element)
|
||||
key = XmlMaterialProfile._createKey(element)
|
||||
mapping[key] = element
|
||||
for element in second:
|
||||
key = self._createKey(element)
|
||||
key = XmlMaterialProfile._createKey(element)
|
||||
if len(element): # Check if element has children.
|
||||
try:
|
||||
if "setting" in element.tag and not "settings" in element.tag:
|
||||
|
@ -441,7 +445,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
for child in element:
|
||||
mapping[key].append(child)
|
||||
else:
|
||||
self._combineElement(mapping[key], element) # Multiple elements, handle those.
|
||||
XmlMaterialProfile._combineElement(mapping[key], element) # Multiple elements, handle those.
|
||||
except KeyError:
|
||||
mapping[key] = element
|
||||
first.append(element)
|
||||
|
@ -742,9 +746,9 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
ContainerRegistry.getInstance().addContainer(container_to_add)
|
||||
|
||||
@classmethod
|
||||
def _getSettingsDictForNode(cls, node) -> Tuple[dict, dict]:
|
||||
node_mapped_settings_dict = dict()
|
||||
node_unmapped_settings_dict = dict()
|
||||
def _getSettingsDictForNode(cls, node) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||
node_mapped_settings_dict = dict() # type: Dict[str, Any]
|
||||
node_unmapped_settings_dict = dict() # type: Dict[str, Any]
|
||||
|
||||
# Fetch settings in the "um" namespace
|
||||
um_settings = node.iterfind("./um:setting", cls.__namespaces)
|
||||
|
@ -1039,8 +1043,8 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
builder.data(data)
|
||||
builder.end(tag_name)
|
||||
|
||||
@classmethod
|
||||
def _profile_name(cls, material_name, color_name):
|
||||
@staticmethod
|
||||
def _profile_name(material_name, color_name):
|
||||
if material_name is None:
|
||||
return "Unknown Material"
|
||||
if color_name != "Generic":
|
||||
|
@ -1048,8 +1052,8 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
else:
|
||||
return material_name
|
||||
|
||||
@classmethod
|
||||
def getPossibleDefinitionIDsFromName(cls, name):
|
||||
@staticmethod
|
||||
def getPossibleDefinitionIDsFromName(name):
|
||||
name_parts = name.lower().split(" ")
|
||||
merged_name_parts = []
|
||||
for part in name_parts:
|
||||
|
@ -1087,8 +1091,8 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
return product_to_id_map
|
||||
|
||||
## Parse the value of the "material compatible" property.
|
||||
@classmethod
|
||||
def _parseCompatibleValue(cls, value: str):
|
||||
@staticmethod
|
||||
def _parseCompatibleValue(value: str):
|
||||
return value in {"yes", "unknown"}
|
||||
|
||||
## Small string representation for debugging.
|
||||
|
@ -1117,7 +1121,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
"break position": "material_break_retracted_position",
|
||||
"break speed": "material_break_speed",
|
||||
"break temperature": "material_break_temperature"
|
||||
}
|
||||
} # type: Dict[str, str]
|
||||
__unmapped_settings = [
|
||||
"hardware compatible",
|
||||
"hardware recommended"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"Ultimaker 2+": "ultimaker2_plus",
|
||||
"Ultimaker 3": "ultimaker3",
|
||||
"Ultimaker 3 Extended": "ultimaker3_extended",
|
||||
"Ultimaker S3": "ultimaker_s3",
|
||||
"Ultimaker S5": "ultimaker_s5",
|
||||
"Ultimaker Original": "ultimaker_original",
|
||||
"Ultimaker Original+": "ultimaker_original_plus",
|
||||
|
|
79
plugins/XmlMaterialProfile/tests/TestXmlMaterialProfile.py
Normal file
79
plugins/XmlMaterialProfile/tests/TestXmlMaterialProfile.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
from unittest.mock import patch, MagicMock
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Prevents error: "PyCapsule_GetPointer called with incorrect name" with conflicting SIP configurations between Arcus and PyQt: Import Arcus and Savitar first!
|
||||
import Savitar # Dont remove this line
|
||||
import Arcus # No really. Don't. It needs to be there!
|
||||
from UM.Qt.QtApplication import QtApplication # QtApplication import is required, even though it isn't used.
|
||||
|
||||
import pytest
|
||||
import XmlMaterialProfile
|
||||
|
||||
def createXmlMaterialProfile(material_id):
|
||||
try:
|
||||
return XmlMaterialProfile.XmlMaterialProfile.XmlMaterialProfile(material_id)
|
||||
except AttributeError:
|
||||
return XmlMaterialProfile.XmlMaterialProfile(material_id)
|
||||
|
||||
|
||||
def test_setName():
|
||||
material_1 = createXmlMaterialProfile("herpderp")
|
||||
material_2 = createXmlMaterialProfile("OMGZOMG")
|
||||
|
||||
material_1.getMetaData()["base_file"] = "herpderp"
|
||||
material_2.getMetaData()["base_file"] = "herpderp"
|
||||
|
||||
container_registry = MagicMock()
|
||||
container_registry.isReadOnly = MagicMock(return_value = False)
|
||||
container_registry.findInstanceContainers = MagicMock(return_value = [material_1, material_2])
|
||||
|
||||
with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value = container_registry)):
|
||||
material_1.setName("beep!")
|
||||
|
||||
assert material_1.getName() == "beep!"
|
||||
assert material_2.getName() == "beep!"
|
||||
|
||||
|
||||
def test_setDirty():
|
||||
material_1 = createXmlMaterialProfile("herpderp")
|
||||
material_2 = createXmlMaterialProfile("OMGZOMG")
|
||||
|
||||
material_1.getMetaData()["base_file"] = "herpderp"
|
||||
material_2.getMetaData()["base_file"] = "herpderp"
|
||||
|
||||
container_registry = MagicMock()
|
||||
container_registry.isReadOnly = MagicMock(return_value=False)
|
||||
container_registry.findContainers = MagicMock(return_value=[material_1, material_2])
|
||||
|
||||
# Sanity check. Since we did a hacky thing to set the metadata, the container should not be dirty.
|
||||
# But this test assumes that it works like that, so we need to validate that.
|
||||
assert not material_1.isDirty()
|
||||
assert not material_2.isDirty()
|
||||
|
||||
with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=container_registry)):
|
||||
material_2.setDirty(True)
|
||||
|
||||
assert material_1.isDirty()
|
||||
assert material_2.isDirty()
|
||||
|
||||
# Setting the base material dirty does not set it's child as dirty.
|
||||
with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=container_registry)):
|
||||
material_1.setDirty(False)
|
||||
|
||||
assert not material_1.isDirty()
|
||||
assert material_2.isDirty()
|
||||
|
||||
|
||||
def test_serializeNonBaseMaterial():
|
||||
material_1 = createXmlMaterialProfile("herpderp")
|
||||
material_1.getMetaData()["base_file"] = "omgzomg"
|
||||
|
||||
container_registry = MagicMock()
|
||||
container_registry.isReadOnly = MagicMock(return_value=False)
|
||||
container_registry.findContainers = MagicMock(return_value=[material_1])
|
||||
|
||||
with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=container_registry)):
|
||||
with pytest.raises(NotImplementedError):
|
||||
# This material is not a base material, so it can't be serialized!
|
||||
material_1.serialize()
|
Loading…
Add table
Add a link
Reference in a new issue