Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions openhcs/core/steps/function_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,12 @@ def _process_single_pattern_group(
)

if not matching_files:
logger.warning(f"No matching files for pattern group {pattern_repr} in {step_input_dir}")
return
raise ValueError(
f"No matching files found for pattern group {pattern_repr} in {step_input_dir}. "
f"This indicates either: (1) no image files exist in the directory, "
f"(2) files don't match the pattern, or (3) pattern parsing failed. "
f"Check that input files exist and match the expected naming convention."
)

logger.debug(f"🔥 PATTERN: Found {len(matching_files)} files: {[Path(f).name for f in matching_files]}")

Expand All @@ -532,8 +536,12 @@ def _process_single_pattern_group(
raw_slices = []

if not raw_slices:
logger.warning(f"No valid images loaded for pattern group {pattern_repr} in {step_input_dir}")
return
raise ValueError(
f"No valid images loaded for pattern group {pattern_repr} in {step_input_dir}. "
f"Found {len(matching_files)} matching files but failed to load any valid images. "
f"This indicates corrupted image files, unsupported formats, or I/O errors. "
f"Check file integrity and format compatibility."
)

# 🔍 DEBUG: Log stacking operation
logger.debug(f"🔍 STACKING: {len(raw_slices)} slices → memory_type: {input_memory_type_from_plan}")
Expand Down Expand Up @@ -840,14 +848,21 @@ def process(self, context: 'ProcessingContext') -> None:

logger.info(f"🔥 STEP: Starting processing for '{step_name}' well {well_id} (group_by={group_by.name}, variable_components={[vc.name for vc in variable_components]})")

if well_id in patterns_by_well:
if isinstance(patterns_by_well[well_id], dict):
# Grouped patterns (when group_by is set)
for comp_val, pattern_list in patterns_by_well[well_id].items():
logger.debug(f"🔥 STEP: Component '{comp_val}' has {len(pattern_list)} patterns: {pattern_list}")
else:
# Ungrouped patterns (when group_by is None)
logger.debug(f"🔥 STEP: Found {len(patterns_by_well[well_id])} ungrouped patterns: {patterns_by_well[well_id]}")
if well_id not in patterns_by_well:
raise ValueError(
f"No patterns detected for well '{well_id}' in step '{step_name}' (ID: {step_id}). "
f"This indicates either: (1) no image files found for this well, "
f"(2) image files don't match the expected naming pattern, or "
f"(3) pattern detection failed. Check input directory: {step_input_dir}"
)

if isinstance(patterns_by_well[well_id], dict):
# Grouped patterns (when group_by is set)
for comp_val, pattern_list in patterns_by_well[well_id].items():
logger.debug(f"🔥 STEP: Component '{comp_val}' has {len(pattern_list)} patterns: {pattern_list}")
else:
# Ungrouped patterns (when group_by is None)
logger.debug(f"🔥 STEP: Found {len(patterns_by_well[well_id])} ungrouped patterns: {patterns_by_well[well_id]}")

if func_from_plan is None:
raise ValueError(f"Step plan missing 'func' for step: {step_plan.get('step_name', 'Unknown')} (ID: {step_id})")
Expand Down
8 changes: 7 additions & 1 deletion openhcs/formats/pattern/pattern_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,12 @@ def _generate_patterns_for_files(
# 🔒 Clause 92 — Structural Validation First
# Validate the final pattern list
if not patterns:
logger.warning("No patterns generated from files")
raise ValueError(
"No patterns generated from files. This indicates either: "
"(1) no image files found in the directory, "
"(2) files don't match the expected naming convention, or "
"(3) pattern generation logic failed. "
"Check that image files exist and follow the expected naming pattern."
)

return patterns
4 changes: 2 additions & 2 deletions openhcs/io/zarr.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def load_batch(self, file_paths: List[Union[str, Path]], **kwargs) -> List[Any]:

# Check which requested files are in this well
for i, path in enumerate(file_paths):
filename = str(path) # Use full path for matching
filename = Path(path).name # Use filename only for matching
if filename in filename_map:
if well_name not in well_to_files:
well_to_files[well_name] = []
Expand Down Expand Up @@ -410,7 +410,7 @@ def save_batch(self, data_list: List[Any], output_paths: List[Union[str, Path]],
z_idx = remaining % n_z

# Store as tuple (field, channel, z) - y,x are full slices
filename_map[str(path)] = (field_idx, channel_idx, z_idx)
filename_map[Path(path).name] = (field_idx, channel_idx, z_idx)

field_array = field_group['0']
field_array.attrs["openhcs_filename_map"] = filename_map
Expand Down
4 changes: 2 additions & 2 deletions openhcs/pyqt_gui/windows/help_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def show_docstring_help(cls, target: Union[Callable, type], title: Optional[str]
cls._docstring_window = None

# Create new window
cls._docstring_window = DocstringHelpWindow(target, title, parent)
cls._docstring_window = DocstringHelpWindow(target, title=title, parent=parent)
cls._docstring_window.show()

except Exception as e:
Expand All @@ -257,7 +257,7 @@ def show_parameter_help(cls, param_name: str, param_description: str, param_type
cls._parameter_window = None

# Create new window
cls._parameter_window = ParameterHelpWindow(param_name, param_description, param_type, parent)
cls._parameter_window = ParameterHelpWindow(param_name, param_description, param_type, parent=parent)
cls._parameter_window.show()

except Exception as e:
Expand Down