99
1010from __future__ import annotations
1111
12+ import getpass
1213import logging
1314import os
1415import shutil
@@ -72,7 +73,9 @@ def __init__(self, napari_viewer: napari.Viewer) -> None:
7273 self .viewer = napari_viewer
7374 self ._tracks_fov = None
7475 self ._tracks_csv_path : Path | None = None
75- self ._resume_csv_path : Path | None = None # Optional CSV for resuming annotations
76+ self ._resume_csv_path : Path | None = (
77+ None # Optional CSV for resuming annotations
78+ )
7679 self ._fov_name : str = ""
7780 self ._output_path : Path = Path .cwd ()
7881
@@ -96,9 +99,7 @@ def _setup_ui(self) -> None:
9699 layout .addWidget (title )
97100
98101 # Instructions
99- instructions = QLabel (
100- "Shortcuts: a/d=time, q/e=layers, r=interpolate, s=save"
101- )
102+ instructions = QLabel ("Shortcuts: a/d=time, q/e=layers, r=interpolate, s=save" )
102103 instructions .setWordWrap (True )
103104 layout .addWidget (instructions )
104105
@@ -248,9 +249,7 @@ def _on_tracks_path_changed(self) -> None:
248249 self ._row_cb .clear ()
249250 self ._well_cb .clear ()
250251 self ._fov_cb .clear ()
251- self ._row_names = [
252- row .name for row in self ._tracks_dataset .metadata .rows
253- ]
252+ self ._row_names = [row .name for row in self ._tracks_dataset .metadata .rows ]
254253 self ._col_names = [
255254 col .name for col in self ._tracks_dataset .metadata .columns
256255 ]
@@ -346,9 +345,7 @@ def _load_data(self) -> None:
346345 tracks_z_index = image_z // 2
347346
348347 # Load tracks CSV from OME-Zarr directory
349- tracks_dir = (
350- Path (self ._tracks_path_le .text ()) / self ._fov_name .strip ("/" )
351- )
348+ tracks_dir = Path (self ._tracks_path_le .text ()) / self ._fov_name .strip ("/" )
352349 self ._tracks_csv_path = next (tracks_dir .glob ("*.csv" ))
353350 _logger .info (f"Loading tracks from { self ._tracks_csv_path } " )
354351 tracks_layer = _ultrack_read_csv (self ._tracks_csv_path )
@@ -366,7 +363,9 @@ def _load_data(self) -> None:
366363
367364 # Load existing annotations from resume CSV if provided, otherwise from tracks CSV
368365 if self ._resume_csv_path is not None :
369- _logger .info (f"Loading annotations from resume CSV: { self ._resume_csv_path } " )
366+ _logger .info (
367+ f"Loading annotations from resume CSV: { self ._resume_csv_path } "
368+ )
370369 annotation_df = pd .read_csv (self ._resume_csv_path )
371370 else :
372371 annotation_df = pd .read_csv (self ._tracks_csv_path )
@@ -579,7 +578,11 @@ def _save_annotations(self) -> None:
579578 tracks_df = pd .read_csv (self ._tracks_csv_path )
580579
581580 # Annotation metadata
582- annotator = os .getlogin ()
581+ try :
582+ annotator = os .getlogin ()
583+ except OSError :
584+ # Fallback for VMs/containers where getlogin() fails
585+ annotator = getpass .getuser ()
583586 annotation_date = datetime .now ().isoformat ()
584587
585588 # Determine version: increment if re-saving from resume CSV, otherwise start at 1.0
@@ -772,7 +775,9 @@ def _save_annotations(self) -> None:
772775
773776 merged_df .to_csv (output_csv , index = False )
774777
775- self ._status_label .setText (f"Saved to { output_csv .name } (v{ annotation_version } )" )
778+ self ._status_label .setText (
779+ f"Saved to { output_csv .name } (v{ annotation_version } )"
780+ )
776781 _logger .info (f"Saved annotations to { output_csv } " )
777782
778783 except Exception as e :
0 commit comments