From 293b5687724e753c968b65a781f486215ace205c Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Thu, 1 Jan 2026 14:17:16 +0100 Subject: [PATCH] simplified deserialisation --- pyPhotoAlbum/commands.py | 172 +++++++++++---------------------------- tests/test_commands.py | 2 + 2 files changed, 48 insertions(+), 126 deletions(-) diff --git a/pyPhotoAlbum/commands.py b/pyPhotoAlbum/commands.py index a4decbe..b46a367 100644 --- a/pyPhotoAlbum/commands.py +++ b/pyPhotoAlbum/commands.py @@ -27,6 +27,34 @@ def _normalize_asset_path(image_path: str, asset_manager) -> str: return image_path +def _deserialize_element(elem_data: Dict[str, Any]) -> BaseLayoutElement: + """ + Deserialize element data into the appropriate element type. + + Args: + elem_data: Dictionary containing serialized element data with 'type' key + + Returns: + Deserialized element instance (ImageData, PlaceholderData, or TextBoxData) + + Raises: + ValueError: If element type is unknown + """ + elem_type = elem_data.get("type") + + if elem_type == "image": + element = ImageData() + elif elem_type == "placeholder": + element = PlaceholderData() + elif elem_type == "textbox": + element = TextBoxData() + else: + raise ValueError(f"Unknown element type: {elem_type}") + + element.deserialize(elem_data) + return element + + class Command(ABC): """Abstract base class for all commands""" @@ -94,24 +122,8 @@ class AddElementCommand(Command): @staticmethod def deserialize(data: Dict[str, Any], project) -> "AddElementCommand": """Deserialize from dictionary""" - # Reconstruct element from serialized data - elem_data = data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: - raise ValueError(f"Unknown element type: {elem_type}") - - element.deserialize(elem_data) - - # Note: We need to find the correct page_layout - # This will be handled by the CommandHistory deserializer + element = _deserialize_element(data["element"]) + # Note: page_layout will be handled by the CommandHistory deserializer cmd = AddElementCommand(None, element) cmd.executed = data.get("executed", False) return cmd @@ -154,21 +166,7 @@ class DeleteElementCommand(Command): @staticmethod def deserialize(data: Dict[str, Any], project) -> "DeleteElementCommand": """Deserialize from dictionary""" - elem_data = data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: - raise ValueError(f"Unknown element type: {elem_type}") - - element.deserialize(elem_data) - + element = _deserialize_element(data["element"]) cmd = DeleteElementCommand(None, element) cmd.executed = data.get("executed", False) return cmd @@ -206,21 +204,7 @@ class MoveElementCommand(Command): @staticmethod def deserialize(data: Dict[str, Any], project) -> "MoveElementCommand": """Deserialize from dictionary""" - elem_data = data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: - raise ValueError(f"Unknown element type: {elem_type}") - - element.deserialize(elem_data) - + element = _deserialize_element(data["element"]) return MoveElementCommand(element, tuple(data["old_position"]), tuple(data["new_position"])) @@ -264,21 +248,7 @@ class ResizeElementCommand(Command): @staticmethod def deserialize(data: Dict[str, Any], project) -> "ResizeElementCommand": """Deserialize from dictionary""" - elem_data = data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: - raise ValueError(f"Unknown element type: {elem_type}") - - element.deserialize(elem_data) - + element = _deserialize_element(data["element"]) return ResizeElementCommand( element, tuple(data["old_position"]), @@ -389,21 +359,7 @@ class RotateElementCommand(Command): @staticmethod def deserialize(data: Dict[str, Any], project) -> "RotateElementCommand": """Deserialize from dictionary""" - elem_data = data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: - raise ValueError(f"Unknown element type: {elem_type}") - - element.deserialize(elem_data) - + element = _deserialize_element(data["element"]) return RotateElementCommand(element, data["old_rotation"], data["new_rotation"]) @@ -487,23 +443,12 @@ class AlignElementsCommand(Command): """Deserialize from dictionary""" changes = [] for change_data in data.get("changes", []): - elem_data = change_data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: + try: + element = _deserialize_element(change_data["element"]) + old_position = tuple(change_data["old_position"]) + changes.append((element, old_position)) + except ValueError: continue - - element.deserialize(elem_data) - old_position = tuple(change_data["old_position"]) - changes.append((element, old_position)) - return AlignElementsCommand(changes) @@ -549,24 +494,13 @@ class ResizeElementsCommand(Command): """Deserialize from dictionary""" changes = [] for change_data in data.get("changes", []): - elem_data = change_data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: + try: + element = _deserialize_element(change_data["element"]) + old_position = tuple(change_data["old_position"]) + old_size = tuple(change_data["old_size"]) + changes.append((element, old_position, old_size)) + except ValueError: continue - - element.deserialize(elem_data) - old_position = tuple(change_data["old_position"]) - old_size = tuple(change_data["old_size"]) - changes.append((element, old_position, old_size)) - return ResizeElementsCommand(changes) @@ -609,21 +543,7 @@ class ChangeZOrderCommand(Command): @staticmethod def deserialize(data: Dict[str, Any], project) -> "ChangeZOrderCommand": """Deserialize from dictionary""" - elem_data = data["element"] - elem_type = elem_data.get("type") - - element: BaseLayoutElement - if elem_type == "image": - element = ImageData() - elif elem_type == "placeholder": - element = PlaceholderData() - elif elem_type == "textbox": - element = TextBoxData() - else: - raise ValueError(f"Unknown element type: {elem_type}") - - element.deserialize(elem_data) - + element = _deserialize_element(data["element"]) return ChangeZOrderCommand( None, element, data["old_index"], data["new_index"] # page_layout will be set by CommandHistory ) diff --git a/tests/test_commands.py b/tests/test_commands.py index 70ec2eb..4273298 100755 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -734,6 +734,7 @@ class TestCommandHistory: """Test deserializing unknown command type returns None and continues""" history = CommandHistory() mock_project = Mock() + mock_project.pages = [] data = { "undo_stack": [ @@ -797,6 +798,7 @@ class TestCommandHistory: # Deserialize mock_project = Mock() + mock_project.pages = [] new_history = CommandHistory() new_history.deserialize(data, mock_project)