From 89cdf30df56707058f4069ce6c042d841bac1496 Mon Sep 17 00:00:00 2001 From: vanous Date: Sun, 14 Sep 2025 00:02:58 +0200 Subject: [PATCH 1/3] Export FixtureIDs only if not none --- pymvr/__init__.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pymvr/__init__.py b/pymvr/__init__.py index 86291d3..bef5759 100644 --- a/pymvr/__init__.py +++ b/pymvr/__init__.py @@ -418,11 +418,11 @@ def __init__( gdtf_mode: Optional[str] = None, matrix: Optional[Matrix] = None, classing: Optional[str] = None, - fixture_id: Optional[str] = "", - fixture_id_numeric: int = 0, - unit_number: int = 0, - custom_id: int = 0, - custom_id_type: int = 0, + fixture_id: Optional[str] = None, + fixture_id_numeric: Optional[int] = None, + unit_number: Optional[int] = None, + custom_id: Optional[int] = None, + custom_id_type: Optional[int] = None, cast_shadow: bool = False, addresses: Optional["Addresses"] = None, alignments: Optional["Alignments"] = None, @@ -572,12 +572,14 @@ def populate_xml(self, element: Element): if self.connections: self.connections.to_xml(element) - ElementTree.SubElement(element, "FixtureID").text = ( - str(self.fixture_id or "") or "" - ) - ElementTree.SubElement(element, "FixtureIDNumeric").text = str( - self.fixture_id_numeric - ) + if self.fixture_id is not None: + ElementTree.SubElement(element, "FixtureID").text = str(self.fixture_id) + + if self.fixture_id_numeric is not None: + ElementTree.SubElement(element, "FixtureIDNumeric").text = str( + self.fixture_id_numeric + ) + if self.unit_number is not None: ElementTree.SubElement(element, "UnitNumber").text = str(self.unit_number) if self.custom_id_type is not None: From 0bca56b872552ccdd3e49f9ec090e2862714f51d Mon Sep 17 00:00:00 2001 From: vanous Date: Sun, 14 Sep 2025 00:11:22 +0200 Subject: [PATCH 2/3] Export matrix only if it carries values --- pymvr/__init__.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/pymvr/__init__.py b/pymvr/__init__.py index bef5759..9cf215b 100644 --- a/pymvr/__init__.py +++ b/pymvr/__init__.py @@ -31,7 +31,7 @@ from .value import Matrix, Color # type: ignore from enum import Enum -__version__ = "1.0.3" +__version__ = "1.0.4.dev0" def _find_root(pkg: "zipfile.ZipFile") -> "ElementTree.Element": @@ -909,10 +909,14 @@ def __str__(self): return f"{self.name}" def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element( type(self).__name__, name=self.name, uuid=self.uuid ) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix and check_mtx: + Matrix(self.matrix.matrix).to_xml(parent=element) if self.classing: ElementTree.SubElement(element, "Classing").text = self.classing if self.child_list: @@ -1026,10 +1030,14 @@ def _read_xml(self, xml_node: "Element"): self.matrix = Matrix(str_repr=matrix_node.text) def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element( type(self).__name__, name=self.name, uuid=self.uuid ) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix and check_mtx: + Matrix(self.matrix.matrix).to_xml(parent=element) if self.child_list: self.child_list.to_xml(parent=element) return element @@ -1185,8 +1193,12 @@ def __hash__(self): return hash((self.file_name, str(self.matrix))) def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element(type(self).__name__, fileName=self.file_name) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix and check_mtx: + Matrix(self.matrix.matrix).to_xml(parent=element) return element @@ -1220,10 +1232,14 @@ def __str__(self): return f"{self.uuid}" def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element( type(self).__name__, uuid=self.uuid, symdef=self.symdef ) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix and check_mtx: + Matrix(self.matrix.matrix).to_xml(parent=element) return element From 514cffaf9252cab8faf00bc29bf0f5f870000793 Mon Sep 17 00:00:00 2001 From: vanous Date: Sun, 14 Sep 2025 10:20:32 +0200 Subject: [PATCH 3/3] Add test for MVR read-write round-trip --- .gitignore | 1 + tests/test_read_write_round_trip.py | 51 +++++++++++++++++++ ...les.py => test_reading_with_many_files.py} | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/test_read_write_round_trip.py rename tests/{test_with_files.py => test_reading_with_many_files.py} (96%) diff --git a/.gitignore b/.gitignore index a8263a8..b9c1966 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ devel/ *whl *.mvr uv.lock +mvr-spec diff --git a/tests/test_read_write_round_trip.py b/tests/test_read_write_round_trip.py new file mode 100644 index 0000000..e8b19c9 --- /dev/null +++ b/tests/test_read_write_round_trip.py @@ -0,0 +1,51 @@ +# MIT License +# +# Copyright (C) 2025 vanous +# +# This file is part of pymvr. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import pytest +import os +from pathlib import Path + + +def test_read_write_round_trip(request, pymvr_module): + # tests a single file, reading and then exporting + # does not pack resources, only the XML + # uv run pytest --file-path=/path/to/file.mvr -s -x + file_path = request.config.getoption("--file-path") + + if file_path is None: + pytest.skip("File path not provided") + file_read_path = Path(file_path) + if not file_read_path.is_file(): + pytest.skip("File does not exist") + file_read_dir = file_read_path.parent + file_read_name = file_read_path.stem + file_write_path = Path(file_read_dir, f"{file_read_name}_exported.mvr") + + with pymvr_module.GeneralSceneDescription(file_read_path) as mvr_read: + mvr_writer = pymvr_module.GeneralSceneDescriptionWriter() + + mvr_read.scene.to_xml(parent=mvr_writer.xml_root) + mvr_read.user_data.to_xml(parent=mvr_writer.xml_root) + + mvr_writer.write_mvr(file_write_path) diff --git a/tests/test_with_files.py b/tests/test_reading_with_many_files.py similarity index 96% rename from tests/test_with_files.py rename to tests/test_reading_with_many_files.py index 30a45d2..9cb89a5 100644 --- a/tests/test_with_files.py +++ b/tests/test_reading_with_many_files.py @@ -27,7 +27,7 @@ from pathlib import Path -def test_with_file(request, pymvr_module): +def test_reading_with_many_files(request, pymvr_module): # uv run pytest --file-path=../../gdtfs/ -s file_path = request.config.getoption("--file-path")