Skip to content

Commit

Permalink
Merge pull request #123 from templateflow/enh/standalone-cli
Browse files Browse the repository at this point in the history
ENH: Add a command line interface
  • Loading branch information
oesteban authored Mar 15, 2024
2 parents ead040a + 6f27171 commit b9cfc2c
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ Information on specific functions, classes, and methods.

.. toctree::

api/templateflow.cli
api/templateflow.api
api/templateflow.conf
15 changes: 15 additions & 0 deletions docs/cli.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Using the client with the Command-line interface (CLI)
======================================================

.. click:: templateflow.cli:main
:prog: templateflow
:nested: full

Examples
--------
Listing all the compressed NIfTI files in ``fsaverage``::

$ templateflow ls fsaverage -x .nii.gz
~/.cache/templateflow/tpl-fsaverage/tpl-fsaverage_res-01_den-41k_T1w.nii.gz
~/.cache/templateflow/tpl-fsaverage/tpl-fsaverage_res-01_desc-brain_mask.nii.gz
~/.cache/templateflow/tpl-fsaverage/tpl-fsaverage_res-01_T1w.nii.gz
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# -- Project information -----------------------------------------------------
project = __packagename__
copyright = __copyright__
author = "The TemplateFlow Developers"
author = "The NiPreps Developers"

# The full version, including alpha/beta/rc tags
release = __version__
Expand All @@ -40,6 +40,7 @@
"sphinx.ext.viewcode",
"sphinxcontrib.apidoc",
"nbsphinx",
"sphinx_click",
]

autodoc_mock_imports = [
Expand Down
1 change: 1 addition & 0 deletions docs/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,4 @@ dependencies:
- hatchling
- hatch-vcs
- nipreps-versions
- sphinx-click
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Contents

installation
examples
cli
datalad
api
changes
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ doc = [
"packaging",
"pydot>=1.2.3",
"pydotplus",
"sphinx-argparse",
"sphinx-click",
"sphinx ~= 4.0",
"sphinx_rtd_theme >= 0.4.3",
"sphinxcontrib-apidoc",
Expand All @@ -61,6 +61,9 @@ tests = ["templateflow[test]"]
docs = ["templateflow[doc]"]
all = ["templateflow[datalad,doc,test]"]

[project.scripts]
templateflow = "templateflow.cli:main"

#
# Hatch configurations
#
Expand Down
155 changes: 155 additions & 0 deletions templateflow/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
#
# Copyright 2024 The NiPreps Developers <nipreps@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# We support and encourage derived works from this project, please read
# about our expectations at
#
# https://www.nipreps.org/community/licensing/
#
"""The TemplateFlow Python Client command-line interface (CLI)."""
from __future__ import annotations

import json
from pathlib import Path

import click
from click.decorators import FC, Option, _param_memo

from templateflow import __package__, api
from templateflow._loader import Loader as _Loader
from templateflow.conf import TF_HOME, TF_USE_DATALAD

load_data = _Loader(__package__)

ENTITY_SHORTHANDS = {
# 'template': ('--tpl', '-t'),
'resolution': ('--res', ),
'density': ('--den', ),
'atlas': ('-a', ),
'suffix': ('-s', ),
'desc': ('-d', '--description'),
'extension': ('--ext', '-x'),
'label': ('-l', ),
'segmentation': ('--seg', ),
}
ENTITY_EXCLUDE = {'template', 'description'}
TEMPLATE_LIST = api.get_templates()


def _nulls(s):
return None if s == 'null' else s


def entity_opts():
"""Attaches all entities as options to the command."""

entities = json.loads(
Path(load_data('conf/config.json')).read_text()
)['entities']

args = [
(
f"--{e['name']}",
*ENTITY_SHORTHANDS.get(e['name'], ())
)
for e in entities if e['name'] not in ENTITY_EXCLUDE
]

def decorator(f: FC) -> FC:
for arg in reversed(args):
_param_memo(f, Option(arg, type=str, default=[], multiple=True))
return f

return decorator


@click.group()
@click.version_option(message='TemplateFlow Python Client %(version)s')
def main():
"""The TemplateFlow Python Client command-line interface (CLI)."""
pass


@main.command()
def config():
"""Print-out configuration."""
click.echo(f"""Current TemplateFlow settings:
TEMPLATEFLOW_HOME={TF_HOME}
TEMPLATEFLOW_USE_DATALAD={'on' if TF_USE_DATALAD else 'off'}
""")


@main.command()
def wipe():
"""Wipe out a local S3 (direct-download) TemplateFlow Archive."""
click.echo(f'This will wipe out all data downloaded into {TF_HOME}.')

if click.confirm('Do you want to continue?'):
value = click.prompt(
f'Please write the path of your local archive ({TF_HOME})',
default='(abort)',
show_default=False,
)
if value.strip() == str(TF_HOME):
from templateflow.conf import wipe

wipe()
click.echo(f'{TF_HOME} was wiped out.')
return
click.echo(f'Aborted! {TF_HOME} WAS NOT wiped out.')


@main.command()
@click.option('--local', is_flag=True)
@click.option('--overwrite/--no-overwrite', default=True)
def update(local, overwrite):
"""Update the local TemplateFlow Archive."""
from templateflow.conf import update as _update

click.echo(
f'Successfully updated local TemplateFlow Archive: {TF_HOME}.'
if _update(local=local, overwrite=overwrite)
else 'TemplateFlow Archive not updated.'
)


@main.command()
@entity_opts()
@click.argument('template', type=click.Choice(TEMPLATE_LIST))
def ls(template, **kwargs):
"""List the assets corresponding to template and optional filters."""
entities = {k: _nulls(v) for k, v in kwargs.items() if v != ''}
click.echo(
'\n'.join(f'{match}' for match in api.ls(template, **entities))
)


@main.command()
@entity_opts()
@click.argument('template', type=click.Choice(TEMPLATE_LIST))
def get(template, **kwargs):
"""Fetch the assets corresponding to template and optional filters."""
entities = {k: _nulls(v) for k, v in kwargs.items() if v != ''}
click.echo(
'\n'.join(f'{match}' for match in api.get(template, **entities))
)


if __name__ == '__main__':
""" Install entry-point """
main()
2 changes: 1 addition & 1 deletion templateflow/conf/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"""Extending pyBIDS for querying TemplateFlow."""
from bids.layout import BIDSLayout, add_config_paths

from . import load_data
from templateflow.conf import load_data

add_config_paths(templateflow=load_data('config.json'))

Expand Down

0 comments on commit b9cfc2c

Please sign in to comment.