napari-tmidas 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -585,7 +585,8 @@ class ProcessingWorker(QThread):
585
585
  filepath = future_to_file[future]
586
586
  try:
587
587
  result = future.result()
588
- if result:
588
+ # Only process result if it's not None (folder functions may return None)
589
+ if result is not None:
589
590
  processed_files_info.append(result)
590
591
  self.file_processed.emit(result)
591
592
  except (
@@ -611,6 +612,16 @@ class ProcessingWorker(QThread):
611
612
 
612
613
  print(f"Original image shape: {image.shape}, dtype: {image_dtype}")
613
614
 
615
+ # Check if this is a folder-processing function that shouldn't save individual files
616
+ function_name = getattr(
617
+ self.processing_func, "__name__", "unknown"
618
+ )
619
+ is_folder_function = (
620
+ "timepoint" in function_name.lower()
621
+ or "merge" in function_name.lower()
622
+ or "folder" in function_name.lower()
623
+ )
624
+
614
625
  # Apply processing with parameters
615
626
  processed_image = self.processing_func(image, **self.param_values)
616
627
 
@@ -618,6 +629,19 @@ class ProcessingWorker(QThread):
618
629
  f"Processed image shape before removing singletons: {processed_image.shape}, dtype: {processed_image.dtype}"
619
630
  )
620
631
 
632
+ # For folder functions, check if the output is the same as input (indicating no individual file should be saved)
633
+ if is_folder_function:
634
+ # If the function returns the original image unchanged, it means it handled saving internally
635
+ if np.array_equal(processed_image, image):
636
+ print(
637
+ "Folder function returned unchanged image - skipping individual file save"
638
+ )
639
+ return None # Return None to indicate no file should be created
640
+ else:
641
+ print(
642
+ "Folder function returned different data - will save individual file"
643
+ )
644
+
621
645
  # Remove ALL singleton dimensions from the processed image
622
646
  # This will keep only dimensions with size > 1
623
647
  processed_image = np.squeeze(processed_image)
@@ -939,9 +963,49 @@ class FileResultsWidget(QWidget):
939
963
 
940
964
  # Update description
941
965
  description = function_info.get("description", "")
942
- self.function_description.setText(description)
943
966
 
944
- # Update parameters
967
+ # Check if this is a folder-processing function that needs single threading
968
+ is_folder_function = (
969
+ "folder" in function_name.lower()
970
+ or "timepoint" in function_name.lower()
971
+ or "merge" in function_name.lower()
972
+ or "folder" in description.lower()
973
+ or "cellpose" in description.lower()
974
+ or "careamics" in description.lower()
975
+ or "trackastra" in description.lower()
976
+ )
977
+
978
+ # Disable threading controls for folder functions
979
+ if is_folder_function:
980
+ self.thread_count.setValue(1)
981
+ self.thread_count.setEnabled(False)
982
+ self.thread_count.setToolTip(
983
+ "This function processes entire folders and must run with 1 thread only."
984
+ )
985
+
986
+ # Add warning to description if not already present
987
+ if (
988
+ "IMPORTANT:" not in description
989
+ and "WARNING:" not in description
990
+ ):
991
+ description += "\nThis function has to run single-threaded."
992
+
993
+ self.function_description.setText(description)
994
+
995
+ # Change the description color to make it more prominent
996
+ self.function_description.setStyleSheet(
997
+ "QLabel { color: #ff6b00; font-weight: bold; }"
998
+ )
999
+ else:
1000
+ # Re-enable threading controls for normal functions
1001
+ self.thread_count.setEnabled(True)
1002
+ self.thread_count.setToolTip(
1003
+ "Number of threads to use for parallel processing"
1004
+ )
1005
+ self.function_description.setStyleSheet("") # Reset styling
1006
+ self.function_description.setText(description)
1007
+
1008
+ # Get parameters
945
1009
  parameters = function_info.get("parameters", {})
946
1010
 
947
1011
  # Remove old parameters widget if it exists
@@ -1014,6 +1078,23 @@ class FileResultsWidget(QWidget):
1014
1078
  self.batch_button.setEnabled(False)
1015
1079
  self.cancel_button.setEnabled(True)
1016
1080
 
1081
+ # Set thread count based on function properties
1082
+ worker_thread_count = self.thread_count.value()
1083
+
1084
+ # Check if function should run single-threaded
1085
+ if (
1086
+ hasattr(processing_func, "thread_safe")
1087
+ and not processing_func.thread_safe
1088
+ ):
1089
+ worker_thread_count = 1
1090
+ self.viewer.status = (
1091
+ "Processing with a single thread (function is not thread-safe)"
1092
+ )
1093
+ else:
1094
+ self.viewer.status = (
1095
+ f"Processing with {worker_thread_count} threads"
1096
+ )
1097
+
1017
1098
  # Create and start the worker thread
1018
1099
  self.worker = ProcessingWorker(
1019
1100
  self.file_list,
@@ -1024,8 +1105,8 @@ class FileResultsWidget(QWidget):
1024
1105
  output_suffix,
1025
1106
  )
1026
1107
 
1027
- # Set the thread count from the UI
1028
- self.worker.thread_count = self.thread_count.value()
1108
+ # Set the thread count from the UI or function attribute
1109
+ self.worker.thread_count = worker_thread_count
1029
1110
 
1030
1111
  # Connect signals
1031
1112
  self.worker.progress_updated.connect(self.update_progress)
@@ -1037,7 +1118,7 @@ class FileResultsWidget(QWidget):
1037
1118
  self.worker.start()
1038
1119
 
1039
1120
  # Update status
1040
- self.viewer.status = f"Processing {len(self.file_list)} files with {selected_function_name} using {self.thread_count.value()} threads"
1121
+ self.viewer.status = f"Processing {len(self.file_list)} files with {selected_function_name} using {worker_thread_count} threads"
1041
1122
 
1042
1123
  def update_progress(self, value):
1043
1124
  """Update the progress bar"""
napari_tmidas/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.2.0'
21
- __version_tuple__ = version_tuple = (0, 2, 0)
20
+ __version__ = version = '0.2.1'
21
+ __version_tuple__ = version_tuple = (0, 2, 1)