Skip to content

Commit

Permalink
☑️ Add mypy Checks in tiatoolbox/cli (#846)
Browse files Browse the repository at this point in the history
- ☑️ Add `mypy` Checks in `tiatoolbox/cli` 

---------

Co-authored-by: Shan E Ahmed Raza <[email protected]>
  • Loading branch information
Jiaqi-Lv and shaneahmed authored Sep 20, 2024
1 parent 6df8565 commit 6ef915d
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 49 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/mypy-type-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ jobs:
tiatoolbox/utils \
tiatoolbox/tools \
tiatoolbox/data \
tiatoolbox/annotation
tiatoolbox/annotation \
tiatoolbox/cli/common.py
98 changes: 50 additions & 48 deletions tiatoolbox/cli/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Callable

import click

Expand All @@ -13,7 +13,7 @@

def add_default_to_usage_help(
usage_help: str,
default: str or int or float or bool,
default: str | float | bool | None,
) -> str:
"""Adds default value to usage help string.
Expand All @@ -37,7 +37,7 @@ def add_default_to_usage_help(
def cli_img_input(
usage_help: str = "Path to WSI or directory containing WSIs.",
multiple: bool | None = None,
) -> callable:
) -> Callable:
"""Enables --img-input option for cli."""
if multiple is None:
multiple = False
Expand All @@ -50,7 +50,7 @@ def cli_img_input(
def cli_name(
usage_help: str = "User defined name to be used as an identifier.",
multiple: bool | None = None,
) -> callable:
) -> Callable:
"""Enable --name option for cli."""
if multiple is None:
multiple = False
Expand All @@ -63,7 +63,7 @@ def cli_name(
def cli_output_path(
usage_help: str = "Path to output directory to save the output.",
default: str | None = None,
) -> callable:
) -> Callable:
"""Enables --output-path option for cli."""
return click.option(
"--output-path",
Expand All @@ -76,7 +76,7 @@ def cli_output_path(
def cli_file_type(
usage_help: str = "File types to capture from directory.",
default: str = "*.ndpi, *.svs, *.mrxs, *.jp2",
) -> callable:
) -> Callable:
"""Enables --file-types option for cli."""
return click.option(
"--file-types",
Expand All @@ -90,7 +90,7 @@ def cli_mode(
usage_help: str = "Selected mode to show or save the required information.",
default: str = "save",
input_type: click.Choice | None = None,
) -> callable:
) -> Callable:
"""Enables --mode option for cli."""
if input_type is None:
input_type = click.Choice(["show", "save"], case_sensitive=False)
Expand All @@ -105,7 +105,7 @@ def cli_mode(
def cli_region(
usage_help: str = "Image region in the whole slide image to read from. "
"default=0 0 2000 2000",
) -> callable:
) -> Callable:
"""Enables --region option for cli."""
return click.option(
"--region",
Expand All @@ -119,7 +119,7 @@ def cli_units(
usage_help: str = "Image resolution units to read the image.",
default: str = "level",
input_type: click.Choice | None = None,
) -> callable:
) -> Callable:
"""Enables --units option for cli."""
if input_type is None:
input_type = click.Choice(
Expand All @@ -137,7 +137,7 @@ def cli_units(
def cli_resolution(
usage_help: str = "Image resolution to read the image.",
default: float = 0,
) -> callable:
) -> Callable:
"""Enables --resolution option for cli."""
return click.option(
"--resolution",
Expand All @@ -150,7 +150,7 @@ def cli_resolution(
def cli_tile_objective(
usage_help: str = "Objective value for the saved tiles.",
default: int = 20,
) -> callable:
) -> Callable:
"""Enables --tile-objective-value option for cli."""
return click.option(
"--tile-objective-value",
Expand All @@ -162,7 +162,7 @@ def cli_tile_objective(

def cli_tile_read_size(
usage_help: str = "Width and Height of saved tiles. default=5000 5000",
) -> callable:
) -> Callable:
"""Enables --tile-read-size option for cli."""
return click.option(
"--tile-read-size",
Expand All @@ -175,7 +175,7 @@ def cli_tile_read_size(

def cli_tile_format(
usage_help: str = "File format to save image tiles, defaults = '.jpg'",
) -> callable:
) -> Callable:
"""Enables --tile-format option for cli."""
return click.option(
"--tile-format",
Expand All @@ -189,7 +189,7 @@ def cli_method(
usage_help: str = "Select method of for tissue masking.",
default: str = "Otsu",
input_type: click.Choice | None = None,
) -> callable:
) -> Callable:
"""Enables --method option for cli."""
if input_type is None:
input_type = click.Choice(["Otsu", "Morphological"], case_sensitive=True)
Expand All @@ -212,7 +212,7 @@ def cli_pretrained_model(
"downloaded. However, you can override with your own set of weights"
"via the `pretrained_weights` argument. Argument is case insensitive.",
default: str = "resnet18-kather100k",
) -> callable:
) -> Callable:
"""Enables --pretrained-model option for cli."""
return click.option(
"--pretrained-model",
Expand All @@ -225,7 +225,7 @@ def cli_pretrained_weights(
usage_help: str = "Path to the model weight file. If not supplied, the default "
"pretrained weight will be used.",
default: str | None = None,
) -> callable:
) -> Callable:
"""Enables --pretrained-weights option for cli."""
return click.option(
"--pretrained-weights",
Expand All @@ -238,7 +238,7 @@ def cli_return_probabilities(
usage_help: str = "Whether to return raw model probabilities.",
*,
default: bool = False,
) -> callable:
) -> Callable:
"""Enables --return-probabilities option for cli."""
return click.option(
"--return-probabilities",
Expand All @@ -252,7 +252,7 @@ def cli_merge_predictions(
usage_help: str = "Whether to merge the predictions to form a 2-dimensional map.",
*,
default: bool = True,
) -> callable:
) -> Callable:
"""Enables --merge-predictions option for cli."""
return click.option(
"--merge-predictions",
Expand All @@ -266,7 +266,7 @@ def cli_return_labels(
usage_help: str = "Whether to return raw model output as labels.",
*,
default: bool = True,
) -> callable:
) -> Callable:
"""Enables --return-labels option for cli."""
return click.option(
"--return-labels",
Expand All @@ -279,7 +279,7 @@ def cli_return_labels(
def cli_batch_size(
usage_help: str = "Number of image patches to feed into the model each time.",
default: int = 1,
) -> callable:
) -> Callable:
"""Enables --batch-size option for cli."""
return click.option(
"--batch-size",
Expand All @@ -296,7 +296,7 @@ def cli_masks(
"automatically generated for whole-slide images or the entire image is "
"processed for image tiles. Supported file types are jpg, png and npy.",
default: str | None = None,
) -> callable:
) -> Callable:
"""Enables --masks option for cli."""
return click.option(
"--masks",
Expand All @@ -309,7 +309,7 @@ def cli_auto_generate_mask(
usage_help: str = "Automatically generate tile/WSI tissue mask.",
*,
default: bool = False,
) -> callable:
) -> Callable:
"""Enables --auto-generate-mask option for cli."""
return click.option(
"--auto-generate-mask",
Expand All @@ -324,7 +324,7 @@ def cli_yaml_config_path(
"tiatoolbox.data.pretrained_model.yaml. "
"if pretrained_model is used the ioconfig is automatically set.",
default: str | None = None,
) -> callable:
) -> Callable:
"""Enables --yaml-config-path option for cli."""
return click.option(
"--yaml-config-path",
Expand All @@ -337,7 +337,7 @@ def cli_on_gpu(
usage_help: str = "Run the model on GPU.",
*,
default: bool = False,
) -> callable:
) -> Callable:
"""Enables --on-gpu option for cli."""
return click.option(
"--on-gpu",
Expand All @@ -351,7 +351,7 @@ def cli_num_loader_workers(
usage_help: str = "Number of workers to load the data. Please note that they will "
"also perform preprocessing.",
default: int = 0,
) -> callable:
) -> Callable:
"""Enables --num-loader-workers option for cli."""
return click.option(
"--num-loader-workers",
Expand All @@ -364,7 +364,7 @@ def cli_num_loader_workers(
def cli_num_postproc_workers(
usage_help: str = "Number of workers to post-process the network output.",
default: int = 0,
) -> callable:
) -> Callable:
"""Enables --num-postproc-workers option for cli."""
return click.option(
"--num-postproc-workers",
Expand All @@ -378,7 +378,7 @@ def cli_verbose(
usage_help: str = "Prints the console output.",
*,
default: bool = True,
) -> callable:
) -> Callable:
"""Enables --verbose option for cli."""
return click.option(
"--verbose",
Expand All @@ -397,13 +397,13 @@ def __init__(
**kwargs: dict[str, Any],
) -> None:
"""Initialize TIAToolboxCLI."""
super().__init__(*args, **kwargs)
super().__init__(*args, **kwargs) # type: ignore[arg-type]
self.help = "Computational pathology toolbox by TIA Centre."
self.add_help_option = {"help_option_names": ["-h", "--help"]}
self.help_option_names = ["-h", "--help"]


def no_input_message(
input_file: (str or Path) | None = None,
input_file: str | Path | None = None,
message: str = "No image input provided.\n",
) -> Path:
"""This function is called if no input is provided.
Expand All @@ -419,18 +419,17 @@ def no_input_message(
"""
if input_file is None:
ctx = click.get_current_context()
ctx.fail(message=message)

return ctx.fail(message=message)
return Path(input_file)


def prepare_file_dir_cli(
img_input: str or Path,
output_path: str or Path,
img_input: str | Path,
output_path: str | Path,
file_types: str,
mode: str,
sub_dirname: str,
) -> [list, Path]:
) -> tuple[list, Path]:
"""Prepares CLI for running code on multiple files or a directory.
Checks for existing directories to run tests.
Expand All @@ -457,7 +456,7 @@ def prepare_file_dir_cli(
from tiatoolbox.utils.misc import grab_files_from_dir, string_to_tuple

img_input = no_input_message(input_file=img_input)
file_types = string_to_tuple(in_str=file_types)
file_types_tuple = string_to_tuple(in_str=file_types)

if isinstance(output_path, str):
output_path = Path(output_path)
Expand All @@ -470,7 +469,9 @@ def prepare_file_dir_cli(
]

if Path.is_dir(img_input):
files_all = grab_files_from_dir(input_path=img_input, file_types=file_types)
files_all = grab_files_from_dir(
input_path=img_input, file_types=file_types_tuple
)

if output_path is None and mode == "save":
input_dir = Path(img_input).parent
Expand All @@ -479,15 +480,15 @@ def prepare_file_dir_cli(
if mode == "save":
output_path.mkdir(parents=True, exist_ok=True)

return [files_all, output_path]
return (files_all, output_path)


def prepare_model_cli(
img_input: str or Path,
output_path: str or Path,
masks: str or Path,
img_input: str | Path,
output_path: str | Path,
masks: str | Path,
file_types: str,
) -> [list, list, Path]:
) -> tuple[list, list | None, Path]:
"""Prepares cli for running models.
Checks for existing directories to run tests.
Expand Down Expand Up @@ -517,7 +518,7 @@ def prepare_model_cli(

img_input = no_input_message(input_file=img_input)
output_path = Path(output_path)
file_types = string_to_tuple(in_str=file_types)
file_types_tuple = string_to_tuple(in_str=file_types)

if output_path.exists():
msg = "Path already exists."
Expand All @@ -543,17 +544,19 @@ def prepare_model_cli(
)

if Path.is_dir(img_input):
files_all = grab_files_from_dir(input_path=img_input, file_types=file_types)
files_all = grab_files_from_dir(
input_path=img_input, file_types=file_types_tuple
)

return [files_all, masks_all, output_path]
return (files_all, masks_all, output_path)


tiatoolbox_cli = TIAToolboxCLI()


def prepare_ioconfig_seg(
segment_config_class: IOConfigABC,
pretrained_weights: str | Path,
segment_config_class: type[IOConfigABC],
pretrained_weights: str | Path | None,
yaml_config_path: str | Path,
) -> IOConfigABC | None:
"""Prepare ioconfig for segmentation."""
Expand All @@ -562,7 +565,6 @@ def prepare_ioconfig_seg(
if pretrained_weights is not None:
with Path(yaml_config_path).open() as registry_handle:
ioconfig = yaml.safe_load(registry_handle)

return segment_config_class(**ioconfig)

return None

0 comments on commit 6ef915d

Please sign in to comment.