mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
follow-up(queue): cache per-plate 3MF metadata so queue polling stops re-parsing every row (#2573)
This commit is contained in:
@@ -493,19 +493,23 @@ def _parse_plate_metadata_uncached(file_path: Path, plate_id: int | None) -> Pla
|
||||
out: list[dict] = []
|
||||
for f in plate_elem.findall("filament"):
|
||||
filament_id = f.get("id")
|
||||
# Both the used_g float() and the id int() must stay inside the guard:
|
||||
# a non-numeric id or used_g is silently skipped (matches the legacy
|
||||
# helpers, which tolerated garbage rows rather than raising — a raise
|
||||
# here would 500 the whole queue listing).
|
||||
try:
|
||||
used_amount = float(f.get("used_g", "0"))
|
||||
if filament_id:
|
||||
out.append(
|
||||
{
|
||||
"slot_id": int(filament_id),
|
||||
"used_g": used_amount,
|
||||
"type": f.get("type", ""),
|
||||
"color": f.get("color", ""),
|
||||
}
|
||||
)
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
if filament_id:
|
||||
out.append(
|
||||
{
|
||||
"slot_id": int(filament_id),
|
||||
"used_g": used_amount,
|
||||
"type": f.get("type", ""),
|
||||
"color": f.get("color", ""),
|
||||
}
|
||||
)
|
||||
return out
|
||||
|
||||
print_time: int | None = None
|
||||
@@ -539,19 +543,20 @@ def _parse_plate_metadata_uncached(file_path: Path, plate_id: int | None) -> Pla
|
||||
# Legacy plate_id=None usage: every filament in the file, not just plate 1.
|
||||
for f in root.findall(".//filament"):
|
||||
filament_id = f.get("id")
|
||||
# int()/float() both guarded — a garbage id/used_g row is skipped, not raised.
|
||||
try:
|
||||
used_amount = float(f.get("used_g", "0"))
|
||||
if filament_id:
|
||||
filament_usage.append(
|
||||
{
|
||||
"slot_id": int(filament_id),
|
||||
"used_g": used_amount,
|
||||
"type": f.get("type", ""),
|
||||
"color": f.get("color", ""),
|
||||
}
|
||||
)
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
if filament_id:
|
||||
filament_usage.append(
|
||||
{
|
||||
"slot_id": int(filament_id),
|
||||
"used_g": used_amount,
|
||||
"type": f.get("type", ""),
|
||||
"color": f.get("color", ""),
|
||||
}
|
||||
)
|
||||
|
||||
return PlateMetadata(
|
||||
print_time_seconds=print_time,
|
||||
|
||||
@@ -1151,6 +1151,37 @@ class TestExtractPlateMetadataFrom3mf:
|
||||
assert len(cached.filament_usage) == 2
|
||||
assert all(f["used_g"] > 0 for f in cached.filament_usage)
|
||||
|
||||
def test_non_numeric_filament_id_is_skipped_not_raised(self, tmp_path):
|
||||
# A garbage filament id (or used_g) must be silently skipped, exactly as
|
||||
# the legacy helpers did — a raise here would 500 the queue listing that
|
||||
# calls this per row. Guards both the plate-specific and plate_id=None paths.
|
||||
from backend.app.utils.threemf_tools import (
|
||||
extract_filament_usage_from_3mf,
|
||||
extract_plate_metadata_from_3mf,
|
||||
)
|
||||
|
||||
xml_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config>
|
||||
<plate>
|
||||
<metadata key="index" value="1"/>
|
||||
<metadata key="prediction" value="3600"/>
|
||||
<filament id="abc" used_g="5.0" type="PLA" color="#FFFFFF"/>
|
||||
<filament id="1" used_g="10.0" type="PLA" color="#FF0000"/>
|
||||
<filament id="2" used_g="bad" type="PLA" color="#00FF00"/>
|
||||
</plate>
|
||||
</config>
|
||||
"""
|
||||
file_path = self._write(tmp_path, xml_content)
|
||||
|
||||
meta = extract_plate_metadata_from_3mf(file_path, plate_id=1)
|
||||
assert [f["slot_id"] for f in meta.filament_usage] == [1]
|
||||
assert meta.filament_used_grams == 10.0
|
||||
assert meta.print_time_seconds == 3600
|
||||
|
||||
# plate_id=None path (collects all filaments in the file) must skip too.
|
||||
none_result = extract_filament_usage_from_3mf(file_path, plate_id=None)
|
||||
assert [f["slot_id"] for f in none_result] == [1]
|
||||
|
||||
def test_missing_file_returns_empty_and_is_not_cached(self, tmp_path):
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
Reference in New Issue
Block a user