mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 06:57:28 -06:00
Implement deserializeMetadata
Let's hope this works... Contributes to issue CURA-4243.
This commit is contained in:
parent
202f7f87f8
commit
c4debbea8b
1 changed files with 156 additions and 1 deletions
|
@ -6,7 +6,7 @@ import io
|
||||||
import json #To parse the product-to-id mapping file.
|
import json #To parse the product-to-id mapping file.
|
||||||
import os.path #To find the product-to-id mapping.
|
import os.path #To find the product-to-id mapping.
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
|
@ -642,6 +642,161 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
for container_to_add in containers_to_add:
|
for container_to_add in containers_to_add:
|
||||||
ContainerRegistry.getInstance().addContainer(container_to_add)
|
ContainerRegistry.getInstance().addContainer(container_to_add)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def deserializeMetadata(cls, serialized: str, container_id: str) -> List[Dict[str, Any]]:
|
||||||
|
result_metadata = [] #All the metadata that we found except the base (because the base is returned).
|
||||||
|
|
||||||
|
#Update the serialized data to the latest version.
|
||||||
|
serialized = cls._updateSerialized(serialized)
|
||||||
|
|
||||||
|
base_metadata = {
|
||||||
|
"type": "material",
|
||||||
|
"status": "unknown", #TODO: Add material verification.
|
||||||
|
"container_type": XmlMaterialProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = ET.fromstring(serialized)
|
||||||
|
except:
|
||||||
|
Logger.logException("e", "An exception occurred while parsing the material profile")
|
||||||
|
return []
|
||||||
|
|
||||||
|
#TODO: Implement the <inherits> tag. It's unused at the moment though.
|
||||||
|
|
||||||
|
if "version" in data.attrib:
|
||||||
|
base_metadata["setting_version"] = cls.xmlVersionToSettingVersion(data.attrib["version"])
|
||||||
|
else:
|
||||||
|
base_metadata["setting_version"] = cls.xmlVersionToSettingVersion("1.2") #1.2 and lower didn't have that version number there yet.
|
||||||
|
|
||||||
|
for entry in data.iterfind("./um:metadata/*", cls.__namespaces):
|
||||||
|
tag_name = _tag_without_namespace(entry)
|
||||||
|
|
||||||
|
if tag_name == "name":
|
||||||
|
brand = entry.find("./um:brand", cls.__namespaces)
|
||||||
|
material = entry.find("./um:material", cls.__namespaces)
|
||||||
|
color = entry.find("./um:color", cls.__namespaces)
|
||||||
|
label = entry.find("./um:label", cls.__namespaces)
|
||||||
|
|
||||||
|
if label is not None:
|
||||||
|
base_metadata["name"] = label.text
|
||||||
|
else:
|
||||||
|
base_metadata["name"] = cls._profile_name(material.text, color.text)
|
||||||
|
base_metadata["brand"] = brand.text
|
||||||
|
base_metadata["material"] = material.text
|
||||||
|
base_metadata["color_name"] = color.text
|
||||||
|
continue
|
||||||
|
|
||||||
|
#Setting_version is derived from the "version" tag in the schema earlier, so don't set it here.
|
||||||
|
if tag_name == "setting_version":
|
||||||
|
continue
|
||||||
|
|
||||||
|
base_metadata[tag_name] = entry.text
|
||||||
|
|
||||||
|
if "description" not in base_metadata:
|
||||||
|
base_metadata["description"] = ""
|
||||||
|
if "adhesion_info" not in base_metadata:
|
||||||
|
base_metadata["adhesion_info"] = ""
|
||||||
|
|
||||||
|
property_values = {}
|
||||||
|
properties = data.iterfind("./um:properties/*", cls.__namespaces)
|
||||||
|
for entry in properties:
|
||||||
|
tag_name = _tag_without_namespace(entry)
|
||||||
|
property_values[tag_name] = entry.text
|
||||||
|
|
||||||
|
base_metadata["approximate_diameter"] = str(round(float(property_values.get("diameter", 2.85)))) # In mm
|
||||||
|
base_metadata["properties"] = property_values
|
||||||
|
|
||||||
|
compatible_entries = data.iterfind("./um:settings/um:setting[@key='hardware compatible']", cls.__namespaces)
|
||||||
|
try:
|
||||||
|
common_compatibility = cls._parseCompatibleValue(next(compatible_entries).text)
|
||||||
|
except StopIteration: #No 'hardware compatible' setting.
|
||||||
|
common_compatibility = True
|
||||||
|
base_metadata["compatible"] = common_compatibility
|
||||||
|
result_metadata.append(base_metadata)
|
||||||
|
|
||||||
|
# Map machine human-readable names to IDs
|
||||||
|
product_id_map = cls.getProductIdMap()
|
||||||
|
|
||||||
|
for machine in data.iterfind("./um:settings/um:machine", cls.__namespaces):
|
||||||
|
machine_compatibility = common_compatibility
|
||||||
|
for entry in machine.iterfind("./um:setting", cls.__namespaces):
|
||||||
|
key = entry.get("key")
|
||||||
|
if key == "hardware compatible":
|
||||||
|
machine_compatibility = cls._parseCompatibleValue(entry.text)
|
||||||
|
|
||||||
|
for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces):
|
||||||
|
machine_id = product_id_map.get(identifier.get("product"), None)
|
||||||
|
if machine_id is None:
|
||||||
|
# Lets try again with some naive heuristics.
|
||||||
|
machine_id = identifier.get("product").replace(" ", "").lower()
|
||||||
|
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
||||||
|
if not definition_metadata:
|
||||||
|
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
||||||
|
continue
|
||||||
|
definition_metadata = definition_metadata[0]
|
||||||
|
|
||||||
|
machine_manufacturer = identifier.get("manufacturer", definition_metadata.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
||||||
|
|
||||||
|
if machine_compatibility:
|
||||||
|
new_material_id = container_id + "_" + machine_id
|
||||||
|
|
||||||
|
# The child or derived material container may already exist. This can happen when a material in a
|
||||||
|
# project file and the a material in Cura have the same ID.
|
||||||
|
# In the case if a derived material already exists, override that material container because if
|
||||||
|
# the data in the parent material has been changed, the derived ones should be updated too.
|
||||||
|
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id)
|
||||||
|
if found_materials:
|
||||||
|
new_material_metadata = found_materials[0]
|
||||||
|
else:
|
||||||
|
new_material_metadata = {}
|
||||||
|
|
||||||
|
new_material_metadata.update(base_metadata)
|
||||||
|
new_material_metadata["compatible"] = machine_compatibility
|
||||||
|
new_material_metadata["machine_manufacturer"] = machine_manufacturer
|
||||||
|
|
||||||
|
if len(found_materials) == 0: #This is a new material.
|
||||||
|
result_metadata.append(new_material_metadata)
|
||||||
|
|
||||||
|
for hotend in machine.iterfind("./um:hotend", cls.__namespaces):
|
||||||
|
hotend_id = hotend.get("id")
|
||||||
|
if hotend_id is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
|
||||||
|
if not variant_containers:
|
||||||
|
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||||
|
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
|
||||||
|
if not variant_containers:
|
||||||
|
continue
|
||||||
|
|
||||||
|
hotend_compatibility = machine_compatibility
|
||||||
|
for entry in hotend.iterfind("./um:setting", cls.__namespaces):
|
||||||
|
key = entry.get("key")
|
||||||
|
if key == "hardware compatible":
|
||||||
|
hotend_compatibility = cls._parseCompatibleValue(entry.text)
|
||||||
|
|
||||||
|
new_hotend_id = container_id + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
|
||||||
|
|
||||||
|
# Same as machine compatibility, keep the derived material containers consistent with the parent
|
||||||
|
# material
|
||||||
|
found_materials = ContainerRegistry.getInstance().findInstanceContainers(id = new_hotend_id)
|
||||||
|
if found_materials:
|
||||||
|
new_hotend_material_metadata = found_materials[0]
|
||||||
|
else:
|
||||||
|
new_hotend_material_metadata = {}
|
||||||
|
|
||||||
|
new_hotend_material_metadata["name"] = base_metadata["name"]
|
||||||
|
new_hotend_material_metadata.update(base_metadata)
|
||||||
|
new_hotend_material_metadata["variant"] = variant_containers[0]["id"]
|
||||||
|
new_hotend_material_metadata["compatible"] = hotend_compatibility
|
||||||
|
new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer
|
||||||
|
|
||||||
|
if len(found_materials) == 0:
|
||||||
|
result_metadata.append(new_hotend_material_metadata)
|
||||||
|
|
||||||
|
for metadata in result_metadata:
|
||||||
|
#ContainerRegistry.getInstance().metadata[metadata["id"]] = metadata
|
||||||
|
|
||||||
## Override of getIdsFromFile because the XML files contain multiple IDs.
|
## Override of getIdsFromFile because the XML files contain multiple IDs.
|
||||||
@classmethod
|
@classmethod
|
||||||
def getIdsFromFile(cls, file_name):
|
def getIdsFromFile(cls, file_name):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue