Skip to content

Commit 0dfebe3

Browse files
authored
Refactor CLI with better type hinting (#127)
* Refactor CLI with better type hinting * Add gpu test flag * Remove shell completion (Slow and buggy - removing for now)
1 parent 74ab06c commit 0dfebe3

File tree

2 files changed

+134
-59
lines changed

2 files changed

+134
-59
lines changed

docs/cli.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ $ kom --help
1111
1212
Options
1313
--version -v
14-
--install-completion [bash|zsh|fish|powershell|pwsh] Install completion for the specified shell. [default: None]
15-
--show-completion [bash|zsh|fish|powershell|pwsh] Show completion for the specified shell, to copy it or customize the installation. [default: None]
1614
--help -h Show this message and exit.
1715
1816
Commands

kelp_o_matic/cli.py

Lines changed: 134 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from pathlib import Path
2-
from typing import Optional
2+
from typing import Annotated, Optional
33

4+
import torch
45
import typer
56

67
from kelp_o_matic import (
@@ -9,42 +10,71 @@
910
find_mussels as find_mussels_,
1011
)
1112

12-
cli = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
13+
cli = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]}, add_completion=False)
1314

1415

1516
@cli.command()
1617
def find_kelp(
17-
source: Path = typer.Argument(..., help="Input image with Byte data type."),
18-
dest: Path = typer.Argument(..., help="File path location to save output to."),
19-
species: bool = typer.Option(
20-
False,
21-
"--species/--presence",
22-
help="Segment to species or presence/absence level.",
23-
),
24-
crop_size: int = typer.Option(
25-
1024,
26-
help="The data window size to run through the segmentation model.",
27-
),
28-
use_nir: bool = typer.Option(
29-
False,
30-
"--rgbi/--rgb",
31-
help="Use RGB and NIR bands for classification. Assumes RGBI ordering.",
32-
),
33-
band_order: Optional[list[int]] = typer.Option(
34-
None,
35-
"-b",
36-
help="GDAL-style band re-ordering flag. Defaults to RGB or RGBI order. "
37-
"To e.g., reorder a BGRI image at runtime, pass flags `-b 3 -b 2 -b 1 -b 4`.",
38-
),
39-
use_gpu: bool = typer.Option(
40-
True, "--gpu/--no-gpu", help="Enable or disable GPU, if available."
41-
),
42-
use_tta: bool = typer.Option(
43-
False,
44-
"--tta/--no-tta",
45-
help="Use test time augmentation to improve accuracy at the cost of "
46-
"processing time.",
47-
),
18+
source: Annotated[
19+
Path,
20+
typer.Argument(
21+
exists=True,
22+
dir_okay=False,
23+
file_okay=True,
24+
readable=True,
25+
help="Input image with Byte data type.",
26+
),
27+
],
28+
dest: Annotated[
29+
Path,
30+
typer.Argument(
31+
exists=True,
32+
dir_okay=False,
33+
file_okay=True,
34+
writable=True,
35+
help="File path location to save output to.",
36+
),
37+
],
38+
species: Annotated[
39+
bool,
40+
typer.Option(
41+
"--species/--presence",
42+
help="Segment to species or presence/absence level.",
43+
),
44+
] = False,
45+
crop_size: Annotated[
46+
int,
47+
typer.Option(
48+
help="The data window size to run through the segmentation model.",
49+
),
50+
] = 1024,
51+
use_nir: Annotated[
52+
bool,
53+
typer.Option(
54+
"--rgbi/--rgb",
55+
help="Use RGB and NIR bands for classification. Assumes RGBI ordering.",
56+
),
57+
] = False,
58+
band_order: Annotated[
59+
Optional[list[int]],
60+
typer.Option(
61+
"-b",
62+
help="GDAL-style band re-ordering flag. Defaults to RGB or RGBI order. "
63+
"To e.g., reorder a BGRI image at runtime, pass flags `-b 3 -b 2 -b 1 -b 4`.",
64+
),
65+
] = None,
66+
use_gpu: Annotated[
67+
bool,
68+
typer.Option("--gpu/--no-gpu", help="Enable or disable GPU, if available."),
69+
] = True,
70+
use_tta: Annotated[
71+
bool,
72+
typer.Option(
73+
"--tta/--no-tta",
74+
help="Use test time augmentation to improve accuracy at the cost of "
75+
"processing time.",
76+
),
77+
] = False,
4878
):
4979
"""
5080
Detect kelp in image at path SOURCE and output the resulting classification raster
@@ -55,27 +85,52 @@ def find_kelp(
5585

5686
@cli.command()
5787
def find_mussels(
58-
source: Path = typer.Argument(..., help="Input image with Byte data type."),
59-
dest: Path = typer.Argument(..., help="File path location to save output to."),
60-
crop_size: int = typer.Option(
61-
1024,
62-
help="The data window size to run through the segmentation model.",
63-
),
64-
band_order: Optional[list[int]] = typer.Option(
65-
None,
66-
"-b",
67-
help="GDAL-style band re-ordering flag. Defaults to RGB order. "
68-
"To e.g., reorder a BGR image at runtime, pass flags `-b 3 -b 2 -b 1`.",
69-
),
70-
use_gpu: bool = typer.Option(
71-
True, "--gpu/--no-gpu", help="Enable or disable GPU, if available."
72-
),
73-
use_tta: bool = typer.Option(
74-
False,
75-
"--tta/--no-tta",
76-
help="Use test time augmentation to improve accuracy at the cost of "
77-
"processing time.",
78-
),
88+
source: Annotated[
89+
Path,
90+
typer.Argument(
91+
exists=True,
92+
dir_okay=False,
93+
file_okay=True,
94+
readable=True,
95+
help="Input image with Byte data type.",
96+
),
97+
],
98+
dest: Annotated[
99+
Path,
100+
typer.Argument(
101+
exists=True,
102+
dir_okay=False,
103+
file_okay=True,
104+
writable=True,
105+
help="File path location to save output to.",
106+
),
107+
],
108+
crop_size: Annotated[
109+
int,
110+
typer.Option(
111+
help="The data window size to run through the segmentation model.",
112+
),
113+
] = 1024,
114+
band_order: Annotated[
115+
Optional[list[int]],
116+
typer.Option(
117+
"-b",
118+
help="GDAL-style band re-ordering flag. Defaults to RGB or RGBI order. "
119+
"To e.g., reorder a BGRI image at runtime, pass flags `-b 3 -b 2 -b 1 -b 4`.",
120+
),
121+
] = None,
122+
use_gpu: Annotated[
123+
bool,
124+
typer.Option("--gpu/--no-gpu", help="Enable or disable GPU, if available."),
125+
] = True,
126+
use_tta: Annotated[
127+
bool,
128+
typer.Option(
129+
"--tta/--no-tta",
130+
help="Use test time augmentation to improve accuracy at the cost of "
131+
"processing time.",
132+
),
133+
] = False,
79134
):
80135
"""
81136
Detect mussels in image at path SOURCE and output the resulting classification
@@ -90,11 +145,33 @@ def version_callback(value: bool) -> None:
90145
raise typer.Exit()
91146

92147

148+
def gpu_callback(value: bool) -> None:
149+
if value:
150+
typer.echo(f"GPU detected: {torch.cuda.is_available()}")
151+
raise typer.Exit()
152+
153+
93154
@cli.callback()
94155
def main(
95-
version: bool = typer.Option(
96-
None, "--version", "-v", callback=version_callback, is_eager=True
97-
),
156+
version: Annotated[
157+
bool,
158+
typer.Option(
159+
"--version",
160+
"-v",
161+
callback=version_callback,
162+
is_eager=True,
163+
help="Show version and exit.",
164+
),
165+
] = False,
166+
gpu_test: Annotated[
167+
bool,
168+
typer.Option(
169+
"--gpu-test",
170+
callback=gpu_callback,
171+
is_eager=True,
172+
help="Test if GPU is detected and exit.",
173+
),
174+
] = False,
98175
):
99176
return
100177

0 commit comments

Comments
 (0)