The mesoscopy core module
Command loading
The root cli group lazy-loads commands through LazyGroup. Subcommands are listed in LAZY_SUBCOMMANDS, a table
of name -> ("module:attribute", summary), and a module is imported only when its subcommand runs.
The summary is what mesoscopy --help prints next to each command. It lives in the table rather than in the
command's docstring so that rendering help does not import every subcommand. The subcommand's own --help still
comes from its docstring.
To add a subcommand, define it with @click.command() or @click.group() in its module and add an entry to
LAZY_SUBCOMMANDS. Do not register it with cli.add_command(). mkdocs-click only walks lazy subcommands when
none are registered eagerly, so an eager command would drop the others from the CLI reference.
Import layers
The same idea applies to imports. Each stage's command module (mesoscopy/<stage>/__init__.py) and mesoscopy.io
import only cheap modules at the top, such as click, numpy, h5py, mesoscopy.io and mesoscopy.timer.
Expensive libraries (pynwb, dask, zarr, pandas, scipy, scikit-learn, pims, napari, plotly, matplotlib) and the
numerics modules that use them are imported inside the function that needs them.
The numerics modules themselves (preprocess.compute, preprocess.qa, process.region, process.regression,
register.transform, register.landmarks_gui, convert.video, and so on) keep conventional top-level imports.
banned-module-level-imports in pyproject.toml lists the expensive libraries, and per-file-ignores excludes
the numerics modules from that rule. Names needed only in annotations go in an if typing.TYPE_CHECKING: block at
the top of the module.
Main entry point to the mesoscopy CLI
LazyGroup
Bases: Group
Click group that imports a subcommand's module only when that subcommand is looked up.
Source code in src/mesoscopy/__init__.py
| class LazyGroup(click.Group):
"""Click group that imports a subcommand's module only when that subcommand is looked up."""
def __init__(
self, *args: typing.Any, lazy_subcommands: dict[str, tuple[str, str]] | None = None, **kwargs: typing.Any
) -> None:
"""Initialise the group.
Args:
*args: Passed to `click.Group`.
lazy_subcommands: Mapping of subcommand name to `("module:attribute", summary)` of its click command.
**kwargs: Passed to `click.Group`.
"""
super().__init__(*args, **kwargs)
self.lazy_subcommands = lazy_subcommands or {}
def list_commands(self, ctx: click.Context) -> list[str]:
"""List registered and lazy subcommand names without importing the lazy ones.
Args:
ctx: Click context.
Returns:
Sorted subcommand names.
"""
return sorted([*super().list_commands(ctx), *self.lazy_subcommands])
def get_command(self, ctx: click.Context, cmd_name: str) -> click.Command | None:
"""Return the subcommand, importing its module if it is lazy.
Args:
ctx: Click context.
cmd_name: Subcommand name.
Returns:
The click command, or `None` if no such subcommand exists.
"""
if cmd_name in self.lazy_subcommands:
return self._load_lazy_command(cmd_name)
return super().get_command(ctx, cmd_name)
def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
"""Write the subcommand listing, using stored summaries for lazy subcommands instead of importing them.
Args:
ctx: Click context.
formatter: Help formatter to write to.
"""
rows = []
for name in self.list_commands(ctx):
if name in self.lazy_subcommands:
rows.append((name, self.lazy_subcommands[name][1]))
continue
cmd = super().get_command(ctx, name)
if cmd is not None and not cmd.hidden:
rows.append((name, cmd.get_short_help_str(limit=formatter.width - 6 - len(name))))
if rows:
with formatter.section("Commands"):
formatter.write_dl(rows)
def _load_lazy_command(self, cmd_name: str) -> click.Command:
module_name, attr_name = self.lazy_subcommands[cmd_name][0].split(":")
cmd = getattr(importlib.import_module(module_name), attr_name)
if not isinstance(cmd, click.Command):
msg = f"Lazy subcommand {cmd_name!r} resolved to {cmd!r}, not a click command."
raise TypeError(msg)
return cmd
|
__init__(*args, lazy_subcommands=None, **kwargs)
Initialise the group.
Parameters:
-
*args
(Any, default:
()
)
–
-
lazy_subcommands
(dict[str, tuple[str, str]] | None, default:
None
)
–
Mapping of subcommand name to ("module:attribute", summary) of its click command.
-
**kwargs
(Any, default:
{}
)
–
Source code in src/mesoscopy/__init__.py
| def __init__(
self, *args: typing.Any, lazy_subcommands: dict[str, tuple[str, str]] | None = None, **kwargs: typing.Any
) -> None:
"""Initialise the group.
Args:
*args: Passed to `click.Group`.
lazy_subcommands: Mapping of subcommand name to `("module:attribute", summary)` of its click command.
**kwargs: Passed to `click.Group`.
"""
super().__init__(*args, **kwargs)
self.lazy_subcommands = lazy_subcommands or {}
|
list_commands(ctx)
List registered and lazy subcommand names without importing the lazy ones.
Parameters:
Returns:
Source code in src/mesoscopy/__init__.py
| def list_commands(self, ctx: click.Context) -> list[str]:
"""List registered and lazy subcommand names without importing the lazy ones.
Args:
ctx: Click context.
Returns:
Sorted subcommand names.
"""
return sorted([*super().list_commands(ctx), *self.lazy_subcommands])
|
get_command(ctx, cmd_name)
Return the subcommand, importing its module if it is lazy.
Parameters:
-
ctx
(Context)
–
-
cmd_name
(str)
–
Returns:
-
Command | None
–
The click command, or None if no such subcommand exists.
Source code in src/mesoscopy/__init__.py
| def get_command(self, ctx: click.Context, cmd_name: str) -> click.Command | None:
"""Return the subcommand, importing its module if it is lazy.
Args:
ctx: Click context.
cmd_name: Subcommand name.
Returns:
The click command, or `None` if no such subcommand exists.
"""
if cmd_name in self.lazy_subcommands:
return self._load_lazy_command(cmd_name)
return super().get_command(ctx, cmd_name)
|
Write the subcommand listing, using stored summaries for lazy subcommands instead of importing them.
Parameters:
-
ctx
(Context)
–
-
formatter
(HelpFormatter)
–
Help formatter to write to.
Source code in src/mesoscopy/__init__.py
| def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
"""Write the subcommand listing, using stored summaries for lazy subcommands instead of importing them.
Args:
ctx: Click context.
formatter: Help formatter to write to.
"""
rows = []
for name in self.list_commands(ctx):
if name in self.lazy_subcommands:
rows.append((name, self.lazy_subcommands[name][1]))
continue
cmd = super().get_command(ctx, name)
if cmd is not None and not cmd.hidden:
rows.append((name, cmd.get_short_help_str(limit=formatter.width - 6 - len(name))))
if rows:
with formatter.section("Commands"):
formatter.write_dl(rows)
|
cli()
Widefield calcium imaging analysis pipeline.
Source code in src/mesoscopy/__init__.py
| @click.group(cls=LazyGroup, lazy_subcommands=LAZY_SUBCOMMANDS)
@click.version_option(__version__)
def cli():
"""Widefield calcium imaging analysis pipeline."""
|
sample(path, out_dir, index, crop=0, vmin=0, vmax=255, key='frames')
Sample an image frame from an HDF5 file and export it as a PNG.
Source code in src/mesoscopy/__init__.py
| @click.command()
@click.argument("path", type=click.Path(exists=True))
@click.argument("out_dir", type=click.Path(dir_okay=True))
@click.option("--index", default=0, show_default=True, help="Index of frame to sample.")
@click.option("--crop", default=0)
@click.option("--vmin", type=float, default=0)
@click.option("--vmax", type=float, default=255)
@click.option("--key", type=str, default=None, help="Activity column")
def sample(path, out_dir, index, crop=0, vmin=0, vmax=255, key="frames"):
"""Sample an image frame from an HDF5 file and export it as a PNG."""
import h5py
from matplotlib import pyplot as plt
click.echo(f"Sampling {path} at index {index}.")
f = h5py.File(path)
d = f[f"/{key}"]
os.makedirs(out_dir, exist_ok=True)
outpath = out_dir + os.sep + path.split("/")[-1].replace(".h5", f"_sample-{index}.png")
if crop > 0:
plt.imsave(outpath, d[index, crop:-crop, crop:-crop], vmin=vmin, vmax=vmax)
else:
plt.imsave(outpath, d[index], vmin=vmin, vmax=vmax, cmap="jet")
click.echo(f"Saved sample at {outpath}")
|
start_time(path)
Print a recording's start time.
This is the first /timestamps entry of an HDF5 file, or the session_start_time of an NWB file, as stored.
Source code in src/mesoscopy/__init__.py
| @click.command("start-time")
@click.argument("path", type=click.Path(exists=True, dir_okay=False))
def start_time(path: str) -> None:
"""Print a recording's start time.
This is the first /timestamps entry of an HDF5 file, or the session_start_time of an NWB file, as stored.
""" # noqa: DOC501
from mesoscopy import io
try:
click.echo(io.read_start_time(path))
except ValueError as err:
raise click.ClickException(str(err)) from err
|