-
Notifications
You must be signed in to change notification settings - Fork 1
huge diff: refactor to include utilities container and more settings #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
4827a03
huge diff: refactor to include utilities container and more settings
TimMonko a62da3c
lazy and speed for imports
TimMonko f2bdccc
update settings names
TimMonko 08315f4
speed up import time and clean up imports
TimMonko 9ef54bf
start moving over test_utilities_container
TimMonko b94b2e2
additional testing resources and format tests
TimMonko 8cf1d66
update lock files
TimMonko 7f2b238
no fail ci on codecov dc
TimMonko 5898ff7
fix flaky qtbot.waitUntil
TimMonko b590ce2
fix coverage percent
TimMonko e7c5b9a
more robust qtbotwaituntil
TimMonko File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| """ | ||
| Helper functions for file handling and image processing. | ||
|
|
||
| Functions | ||
| --------- | ||
| get_directory_and_files : Get the directory and files in the specified directory. | ||
| get_channel_names : Get the channel names from a BioImage object. | ||
| get_squeezed_dim_order : Return a string containing the squeezed dimensions of the given BioImage object. | ||
| create_id_string : Create an ID string for the given image. | ||
| check_for_missing_files : Check if the given files are missing in the specified directories. | ||
| elide_string : Elide a string if it exceeds the specified length. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from pathlib import Path | ||
| from typing import TYPE_CHECKING | ||
|
|
||
| if TYPE_CHECKING: | ||
| from bioio import BioImage | ||
|
|
||
| from ndevio import nImage | ||
|
|
||
| __all__ = [ | ||
| "check_for_missing_files", | ||
| "create_id_string", | ||
| "elide_string", | ||
| "get_channel_names", | ||
| "get_directory_and_files", | ||
| "get_squeezed_dim_order", | ||
| ] | ||
|
|
||
|
|
||
| def get_directory_and_files( | ||
| dir_path: str | Path | None = None, | ||
| pattern: list[str] | str | None = None, | ||
| ) -> tuple[Path | None, list[Path]]: | ||
| """ | ||
| Get the directory and files in the specified directory. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| dir_path : str or Path or None, optional | ||
| The directory path. | ||
| pattern : list of str or str or None, optional | ||
| The file pattern(s) to match. If a string is provided, it will be | ||
| treated as a single pattern. If a list is provided, each element | ||
| will be treated as a separate pattern. | ||
| Defaults to common image formats: tif, tiff, nd2, czi, lif, oib, png, | ||
| jpg, jpeg, bmp, gif. | ||
|
|
||
| Returns | ||
| ------- | ||
| tuple of (Path or None, list of Path) | ||
| A tuple containing the directory path and a list of file paths. | ||
|
|
||
| """ | ||
| if pattern is None: | ||
| pattern = [ | ||
| "tif", | ||
| "tiff", | ||
| "nd2", | ||
| "czi", | ||
| "lif", | ||
| "oib", | ||
| "png", | ||
| "jpg", | ||
| "jpeg", | ||
| "bmp", | ||
| "gif", | ||
| ] | ||
| if dir_path is None: | ||
| return None, [] | ||
|
|
||
| directory = Path(dir_path) | ||
|
|
||
| if dir_path is not None and not directory.exists(): | ||
| raise FileNotFoundError(f"Directory {dir_path} does not exist.") | ||
|
|
||
| pattern = [pattern] if isinstance(pattern, str) else pattern | ||
| # add *. to each pattern if it doesn't already have either | ||
| pattern_glob = [] | ||
| for pat in pattern: | ||
| if "." not in pat: | ||
| pat = f"*.{pat}" | ||
| if "*" not in pat: | ||
| pat = f"*{pat}" | ||
| pattern_glob.append(pat) | ||
|
|
||
| files = [] | ||
| for p_glob in pattern_glob: | ||
| for file in directory.glob(p_glob): | ||
| files.append(file) | ||
| return directory, files | ||
|
|
||
|
|
||
| def get_channel_names(img: nImage | BioImage) -> list[str]: | ||
| """ | ||
| Get the channel names from a BioImage object. | ||
|
|
||
| If the image has a dimension order that includes "S" (it is RGB), | ||
| return the default channel names ["red", "green", "blue"]. | ||
| Otherwise, return the channel names from the image. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| img : nImage or BioImage | ||
| The image object. | ||
|
|
||
| Returns | ||
| ------- | ||
| list of str | ||
| The channel names. | ||
|
|
||
| """ | ||
| if "S" in img.dims.order: | ||
| return ["red", "green", "blue"] | ||
| # Ensure we have plain Python strings, not numpy string types | ||
| return [str(c) for c in img.channel_names] | ||
|
|
||
|
|
||
| def get_squeezed_dim_order( | ||
| img: nImage | BioImage, | ||
| skip_dims: tuple[str, ...] | list[str] | str = ("C", "S"), | ||
| ) -> str: | ||
| """ | ||
| Return a string containing the squeezed dimensions of the given BioImage. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| img : nImage or BioImage | ||
| The image object. | ||
| skip_dims : tuple of str or list of str or str | ||
| Dimensions to skip. Defaults to ("C", "S"). | ||
|
|
||
| Returns | ||
| ------- | ||
| str | ||
| A string containing the squeezed dimensions. | ||
|
|
||
| """ | ||
| if isinstance(skip_dims, str): | ||
| skip_dims = (skip_dims,) | ||
| return "".join( | ||
| {k: v for k, v in img.dims.items() if v > 1 and k not in skip_dims} | ||
| ) | ||
|
|
||
|
|
||
| def create_id_string(img: nImage | BioImage, identifier: str) -> str: | ||
| """ | ||
| Create an ID string for the given image. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| img : nImage or BioImage | ||
| The image object. | ||
| identifier : str | ||
| The identifier string. | ||
|
|
||
| Returns | ||
| ------- | ||
| str | ||
| The ID string in format: '{identifier}__{scene_idx}__{scene_name}'. | ||
|
|
||
| Examples | ||
| -------- | ||
| >>> create_id_string(img, 'test') | ||
| 'test__0__Scene:0' | ||
|
|
||
| """ | ||
| scene_idx = img.current_scene_index | ||
| # Use ome_metadata.name because this gets saved with OmeTiffWriter | ||
| try: | ||
| if img.ome_metadata.images[scene_idx].name is None: | ||
| scene = img.current_scene | ||
| else: | ||
| scene = img.ome_metadata.images[scene_idx].name | ||
| except NotImplementedError: | ||
| scene = img.current_scene # not useful with OmeTiffReader, atm | ||
| id_string = f"{identifier}__{scene_idx}__{scene}" | ||
| return id_string | ||
|
|
||
|
|
||
| def check_for_missing_files( | ||
| files: list[Path] | list[str], *directories: Path | str | ||
| ) -> list[tuple[str, str]]: | ||
| """ | ||
| Check if the given files are missing in the specified directories. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| files : list of Path or list of str | ||
| List of files to check. | ||
| directories : Path or str | ||
| Directories to search for the files. | ||
|
|
||
| Returns | ||
| ------- | ||
| list of tuple | ||
| List of tuples containing (file_name, directory_name) for missing files. | ||
|
|
||
| """ | ||
| missing_files = [] | ||
| for file in files: | ||
| for directory in directories: | ||
| if isinstance(directory, str): | ||
| directory = Path(directory) | ||
| if isinstance(file, str): | ||
| file = Path(file) | ||
|
|
||
| file_loc = directory / file.name | ||
| if not file_loc.exists(): | ||
| missing_files.append((file.name, directory.name)) | ||
|
|
||
| return missing_files | ||
|
|
||
|
|
||
| def elide_string( | ||
| input_string: str, max_length: int = 15, location: str = "middle" | ||
| ) -> str: | ||
| """ | ||
| Elide a string if it exceeds the specified length. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| input_string : str | ||
| The input string. | ||
| max_length : int, optional | ||
| The maximum length of the string. Defaults to 15. | ||
| location : str, optional | ||
| The location to elide the string. Can be 'start', 'middle', or 'end'. | ||
| Defaults to 'middle'. | ||
|
|
||
| Returns | ||
| ------- | ||
| str | ||
| The elided string. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If location is not 'start', 'middle', or 'end'. | ||
|
|
||
| """ | ||
| # If the string is already shorter than the max length, return it | ||
| if len(input_string) <= max_length: | ||
| return input_string | ||
| # If max_length is too small, just truncate | ||
| if max_length <= 5: | ||
| return input_string[:max_length] | ||
| # Elide the string based on the location | ||
| if location == "start": | ||
| return "..." + input_string[-(max_length - 3) :] | ||
| if location == "end": | ||
| return input_string[: max_length - 3] + "..." | ||
| if location == "middle": | ||
| half_length = (max_length - 3) // 2 | ||
| return input_string[:half_length] + "..." + input_string[-half_length:] | ||
TimMonko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| raise ValueError('Invalid location. Must be "start", "middle", or "end".') | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.