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
34 changes: 28 additions & 6 deletions docs/cli.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
# CLI Reference
# CLI reference

::: mkdocs-click
## Selecting input positions

`set-scale` and `compute-pyramid` accept position paths, plate roots, and glob
patterns with `-i` or `--input-position-dirpaths`. A plate root selects every
position in the plate. One `-i` accepts multiple paths, up to the next option.

```bash
# All positions in a plate
iohub compute-pyramid -i input.zarr --levels 4

# Positions matching a glob
iohub compute-pyramid -i 'input.zarr/A/*/*' --levels 4

# Two specific positions
iohub set-scale -i input.zarr/A/1/0 input.zarr/B/2/0 -z 2
```

iohub expands quoted globs. Your shell expands unquoted ones.

To use these options in another Typer CLI, see
[Options with multiple values](greedy-cli-options.md).

## Commands

::: mkdocs-typer2
:module: iohub.cli.cli
:command: cli
:prog_name: iohub
:depth: 1
:style: table
:name: iohub
:pretty: true
86 changes: 86 additions & 0 deletions docs/greedy-cli-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Options with multiple values

`OptionEatAll` lets a Typer list option accept several values after one flag.
It stops at the next option. For example, `-i a b c -v` passes `a`, `b`, and `c`
to `-i` and leaves `-v` as a separate option.

## Reuse iohub's position option

Save this as `positions.py`. The callback keeps the app a command group even
when it has only one command.

```python
import typer
from typer.main import get_command

from iohub.cli import InputPositionDirpaths, expand_position_dirpaths, install_eat_all_positions

app = typer.Typer()


@app.callback()
def main():
"""List OME-Zarr positions."""


@app.command()
def process(input_position_dirpaths: InputPositionDirpaths):
for position in expand_position_dirpaths(input_position_dirpaths):
typer.echo(position)


cli = get_command(app)
install_eat_all_positions(cli)

if __name__ == "__main__":
cli()
```

```bash
python positions.py process -i input.zarr
python positions.py process -i 'input.zarr/A/*/*'
```

`expand_position_dirpaths` expands plate roots and globs, skips file matches,
and raises `typer.BadParameter` if no directories match.
`install_eat_all_positions` updates the group's immediate commands. It looks
for the parameter name `input_position_dirpaths`, so keep that name in your
command.

## Define another option

Typer does not expose an option-class argument. Apply `OptionEatAll` after
`get_command` builds the command. Use it only with list options.

Save this single-command example as `files.py`:

```python
from typing import Annotated

import typer
from typer.core import TyperOption
from typer.main import get_command

from iohub.cli import OptionEatAll

app = typer.Typer()


@app.command()
def show(files: Annotated[list[str], typer.Option("-f", "--files")]):
typer.echo(files)


cli = get_command(app)
for param in cli.params:
if isinstance(param, TyperOption) and param.name == "files":
param.__class__ = OptionEatAll

if __name__ == "__main__":
cli()
```

```bash
python files.py -f a b c
# ['a', 'b', 'c']
```
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ dependencies = [
"xarray>=2024.1.1",
"dask[array]",
"zarrs>=0.2.3",
"typer>=0.27.2",
"lazy-loader>=0.4",
]
dynamic = ["version"]

Expand Down Expand Up @@ -77,10 +79,10 @@ acquire-zarr = [
doc = [
"zensical>=0.0.57",
"mkdocstrings-python>=2.0.8",
"mkdocs-click>=0.9.0",
"pymdown-extensions>=11.0.2",
"ruff>=0.16.5",
"mike",
"mkdocs-typer2[zensical]>=0.4.1",
]
dev = [
{ include-group = "test" },
Expand Down
7 changes: 4 additions & 3 deletions src/iohub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
import os
from importlib.metadata import version

from iohub.ngff import open_ome_zarr
from iohub.reader import read_images
import lazy_loader as lazy

__all__ = ["open_ome_zarr", "read_images"]
# Load exports from __init__.pyi on first access so CLI startup does not import
# xarray, pandas, and dask.
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)

__version__ = version(__name__)

Expand Down
4 changes: 4 additions & 0 deletions src/iohub/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .ngff import open_ome_zarr as open_ome_zarr
from .reader import read_images as read_images

__version__: str
15 changes: 15 additions & 0 deletions src/iohub/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""iohub command-line interface and reusable Typer options."""

from iohub.cli.parsing import (
InputPositionDirpaths,
OptionEatAll,
expand_position_dirpaths,
install_eat_all_positions,
)

__all__ = [
"InputPositionDirpaths",
"OptionEatAll",
"expand_position_dirpaths",
"install_eat_all_positions",
]
Loading
Loading