From 1eef33be90c78a9ecf4a0f393ddf414c986f93c8 Mon Sep 17 00:00:00 2001 From: Andy Arijs Date: Tue, 10 Mar 2026 19:09:09 +0100 Subject: [PATCH 1/4] Fix metadata retrieval flag --- faststack/app.py | 12 ++++++------ faststack/io/sidecar.py | 10 +++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/faststack/app.py b/faststack/app.py index d18f96a..1778321 100644 --- a/faststack/app.py +++ b/faststack/app.py @@ -1793,7 +1793,7 @@ def jump_to_last_uploaded(self): for idx in range(len(self.image_files) - 1, -1, -1): img = self.image_files[idx] # Dynamic look-up of self.sidecar as requested (important for mocks in tests) - meta = self.sidecar.get_metadata(img.path.stem) + meta = self.sidecar.get_metadata(img.path.stem, create=False) # Robust extraction of 'uploaded' flag: handle both object and dict formats. # Mock-safety: must evaluate False if it's a MagicMock (test requirement). @@ -2120,7 +2120,7 @@ def _on_thumbnail_ready_gui(self, thumbnail_id: str): def _get_metadata_dict(self, stem: str) -> dict: """Get metadata for a file stem as a dict for thumbnail model.""" try: - meta = self.sidecar.get_metadata(stem) + meta = self.sidecar.get_metadata(stem, create=False) return { "stacked": getattr(meta, "stacked", False), "uploaded": getattr(meta, "uploaded", False), @@ -2351,7 +2351,7 @@ def get_current_metadata(self) -> Dict: # Compute and cache stem = self.image_files[self.current_index].path.stem - meta = self.sidecar.get_metadata(stem) + meta = self.sidecar.get_metadata(stem, create=False) stack_info = self._get_stack_info(self.current_index) batch_info = self._get_batch_info(self.current_index) @@ -2612,7 +2612,7 @@ def add_favorites_to_batch(self): # Find indices of all favorited images indices_to_add = [] for i, img in enumerate(self.image_files): - meta = self.sidecar.get_metadata(img.path.stem) + meta = self.sidecar.get_metadata(img.path.stem, create=False) if meta.favorite: indices_to_add.append(i) @@ -2667,7 +2667,7 @@ def add_uploaded_to_batch(self): # Find indices of all uploaded images indices_to_add = [] for i, img in enumerate(self.image_files): - meta = self.sidecar.get_metadata(img.path.stem) + meta = self.sidecar.get_metadata(img.path.stem, create=False) if not meta: continue uploaded = ( @@ -7374,7 +7374,7 @@ def is_stacked(self) -> bool: if not self.image_files or self.current_index >= len(self.image_files): return False stem = self.image_files[self.current_index].path.stem - meta = self.sidecar.get_metadata(stem) + meta = self.sidecar.get_metadata(stem, create=False) return meta.stacked def _update_cache_stats(self): diff --git a/faststack/io/sidecar.py b/faststack/io/sidecar.py index 8137852..2491208 100644 --- a/faststack/io/sidecar.py +++ b/faststack/io/sidecar.py @@ -118,9 +118,13 @@ def save(self): if was_watcher_running: self.start_watcher() - def get_metadata(self, image_stem: str) -> EntryMetadata: - """Gets metadata for an image, creating it if it doesn't exist.""" - return self.data.entries.setdefault(image_stem, EntryMetadata()) + def get_metadata(self, image_stem: str, *, create: bool = True) -> EntryMetadata: + """Get metadata for an image, optionally creating a persistent entry.""" + meta = self.data.entries.get(image_stem) + if meta is None and create: + meta = EntryMetadata() + self.data.entries[image_stem] = meta + return meta if meta is not None else EntryMetadata() def set_last_index(self, index: int): self.data.last_index = index From 3a0d52df2970d84ce7fdd2d4f3d0c745e094c936 Mon Sep 17 00:00:00 2001 From: Andy Arijs Date: Tue, 10 Mar 2026 19:43:56 +0100 Subject: [PATCH 2/4] Handle dict metadata badges --- faststack/app.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/faststack/app.py b/faststack/app.py index 1778321..50a884b 100644 --- a/faststack/app.py +++ b/faststack/app.py @@ -2378,17 +2378,17 @@ def get_current_metadata(self) -> Dict: self._metadata_cache = { "filename": filename, "exif_brief": exif_brief, - "stacked": meta.stacked, - "stacked_date": meta.stacked_date or "", - "uploaded": meta.uploaded, - "uploaded_date": meta.uploaded_date or "", - "edited": meta.edited, - "edited_date": meta.edited_date or "", - "restacked": meta.restacked, - "restacked_date": meta.restacked_date or "", - "favorite": meta.favorite, - "todo": getattr(meta, "todo", False), - "todo_date": getattr(meta, "todo_date", None) or "", + "stacked": meta.get("stacked", False) if isinstance(meta, dict) else getattr(meta, "stacked", False), + "stacked_date": (meta.get("stacked_date") if isinstance(meta, dict) else getattr(meta, "stacked_date", None)) or "", + "uploaded": meta.get("uploaded", False) if isinstance(meta, dict) else getattr(meta, "uploaded", False), + "uploaded_date": (meta.get("uploaded_date") if isinstance(meta, dict) else getattr(meta, "uploaded_date", None)) or "", + "edited": meta.get("edited", False) if isinstance(meta, dict) else getattr(meta, "edited", False), + "edited_date": (meta.get("edited_date") if isinstance(meta, dict) else getattr(meta, "edited_date", None)) or "", + "restacked": meta.get("restacked", False) if isinstance(meta, dict) else getattr(meta, "restacked", False), + "restacked_date": (meta.get("restacked_date") if isinstance(meta, dict) else getattr(meta, "restacked_date", None)) or "", + "favorite": meta.get("favorite", False) if isinstance(meta, dict) else getattr(meta, "favorite", False), + "todo": meta.get("todo", False) if isinstance(meta, dict) else getattr(meta, "todo", False), + "todo_date": (meta.get("todo_date") if isinstance(meta, dict) else getattr(meta, "todo_date", None)) or "", "stack_info_text": stack_info, "batch_info_text": batch_info, } @@ -2613,7 +2613,7 @@ def add_favorites_to_batch(self): indices_to_add = [] for i, img in enumerate(self.image_files): meta = self.sidecar.get_metadata(img.path.stem, create=False) - if meta.favorite: + if meta.get("favorite", False) if isinstance(meta, dict) else getattr(meta, "favorite", False): indices_to_add.append(i) if not indices_to_add: @@ -7375,7 +7375,7 @@ def is_stacked(self) -> bool: return False stem = self.image_files[self.current_index].path.stem meta = self.sidecar.get_metadata(stem, create=False) - return meta.stacked + return meta.get("stacked", False) if isinstance(meta, dict) else getattr(meta, "stacked", False) def _update_cache_stats(self): if self.debug_cache: From 9ed596788af98fbe434e002d7cebe4462fd5e615 Mon Sep 17 00:00:00 2001 From: Andy Arijs Date: Tue, 10 Mar 2026 20:16:29 +0100 Subject: [PATCH 3/4] Remove unreachable dict branches from app metadata reads --- faststack/app.py | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/faststack/app.py b/faststack/app.py index 50a884b..d4d79fb 100644 --- a/faststack/app.py +++ b/faststack/app.py @@ -1795,13 +1795,7 @@ def jump_to_last_uploaded(self): # Dynamic look-up of self.sidecar as requested (important for mocks in tests) meta = self.sidecar.get_metadata(img.path.stem, create=False) - # Robust extraction of 'uploaded' flag: handle both object and dict formats. - # Mock-safety: must evaluate False if it's a MagicMock (test requirement). - # We explicitly check for boolean True. - if isinstance(meta, dict): - uploaded = meta.get("uploaded") - else: - uploaded = getattr(meta, "uploaded", None) + uploaded = meta.uploaded if uploaded is True: last_uploaded_index = idx @@ -2378,17 +2372,17 @@ def get_current_metadata(self) -> Dict: self._metadata_cache = { "filename": filename, "exif_brief": exif_brief, - "stacked": meta.get("stacked", False) if isinstance(meta, dict) else getattr(meta, "stacked", False), - "stacked_date": (meta.get("stacked_date") if isinstance(meta, dict) else getattr(meta, "stacked_date", None)) or "", - "uploaded": meta.get("uploaded", False) if isinstance(meta, dict) else getattr(meta, "uploaded", False), - "uploaded_date": (meta.get("uploaded_date") if isinstance(meta, dict) else getattr(meta, "uploaded_date", None)) or "", - "edited": meta.get("edited", False) if isinstance(meta, dict) else getattr(meta, "edited", False), - "edited_date": (meta.get("edited_date") if isinstance(meta, dict) else getattr(meta, "edited_date", None)) or "", - "restacked": meta.get("restacked", False) if isinstance(meta, dict) else getattr(meta, "restacked", False), - "restacked_date": (meta.get("restacked_date") if isinstance(meta, dict) else getattr(meta, "restacked_date", None)) or "", - "favorite": meta.get("favorite", False) if isinstance(meta, dict) else getattr(meta, "favorite", False), - "todo": meta.get("todo", False) if isinstance(meta, dict) else getattr(meta, "todo", False), - "todo_date": (meta.get("todo_date") if isinstance(meta, dict) else getattr(meta, "todo_date", None)) or "", + "stacked": meta.stacked, + "stacked_date": meta.stacked_date or "", + "uploaded": meta.uploaded, + "uploaded_date": meta.uploaded_date or "", + "edited": meta.edited, + "edited_date": meta.edited_date or "", + "restacked": meta.restacked, + "restacked_date": meta.restacked_date or "", + "favorite": meta.favorite, + "todo": meta.todo, + "todo_date": meta.todo_date or "", "stack_info_text": stack_info, "batch_info_text": batch_info, } @@ -2613,7 +2607,7 @@ def add_favorites_to_batch(self): indices_to_add = [] for i, img in enumerate(self.image_files): meta = self.sidecar.get_metadata(img.path.stem, create=False) - if meta.get("favorite", False) if isinstance(meta, dict) else getattr(meta, "favorite", False): + if meta.favorite: indices_to_add.append(i) if not indices_to_add: @@ -2668,14 +2662,7 @@ def add_uploaded_to_batch(self): indices_to_add = [] for i, img in enumerate(self.image_files): meta = self.sidecar.get_metadata(img.path.stem, create=False) - if not meta: - continue - uploaded = ( - meta.get("uploaded", False) - if isinstance(meta, dict) - else getattr(meta, "uploaded", False) - ) - if uploaded: + if meta.uploaded: indices_to_add.append(i) if not indices_to_add: @@ -7375,7 +7362,7 @@ def is_stacked(self) -> bool: return False stem = self.image_files[self.current_index].path.stem meta = self.sidecar.get_metadata(stem, create=False) - return meta.get("stacked", False) if isinstance(meta, dict) else getattr(meta, "stacked", False) + return meta.stacked def _update_cache_stats(self): if self.debug_cache: From 2bad95c1b85a78faee7257769706f7d3a32b189d Mon Sep 17 00:00:00 2001 From: Andy Arijs Date: Wed, 11 Mar 2026 08:00:50 +0100 Subject: [PATCH 4/4] Handle missing metadata todo fields --- faststack/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/faststack/app.py b/faststack/app.py index d4d79fb..31e1502 100644 --- a/faststack/app.py +++ b/faststack/app.py @@ -2381,8 +2381,8 @@ def get_current_metadata(self) -> Dict: "restacked": meta.restacked, "restacked_date": meta.restacked_date or "", "favorite": meta.favorite, - "todo": meta.todo, - "todo_date": meta.todo_date or "", + "todo": getattr(meta, "todo", False), + "todo_date": getattr(meta, "todo_date", "") or "", "stack_info_text": stack_info, "batch_info_text": batch_info, }