Skip to content

Commit

Permalink
entry: lazy load subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
Kamilcuk committed Sep 30, 2024
1 parent 30a6d5f commit 879dfa0
Show file tree
Hide file tree
Showing 18 changed files with 108 additions and 74 deletions.
51 changes: 51 additions & 0 deletions src/nomad_tools/aliasedlazygroup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# https://click.palletsprojects.com/en/8.1.x/complex/#defining-the-lazy-group
import importlib
import click


class AliasedLazyGroup(click.Group):
def __init__(self, *args, lazy_subcommands=None, **kwargs):
super().__init__(*args, **kwargs)
# lazy_subcommands is a map of the form:
#
# {command-name} -> {module-name}.{command-object-name}
#
self.lazy_subcommands = lazy_subcommands or {}

def list_commands(self, ctx):
base = super().list_commands(ctx)
lazy = sorted(self.lazy_subcommands.keys())
return base + lazy

def _lazy_load(self, cmd_name):
# lazily loading a command, first get the module name and attribute name
import_path = self.lazy_subcommands[cmd_name]
modname, cmd_object_name = import_path.rsplit(".", 1)
# do the import
mod = importlib.import_module(modname)
# get the Command object from that module
cmd_object = getattr(mod, cmd_object_name)
# check the result to make debugging easier
if not isinstance(cmd_object, click.Command):
raise ValueError(
f"Lazy loading of {import_path} failed by returning "
"a non-command object"
)
return cmd_object

def get_command(self, ctx, cmd_name):
rv = click.Group.get_command(self, ctx, cmd_name)
if rv is not None:
return rv
matches = [x for x in self.list_commands(ctx) if x.startswith(cmd_name)]
if not matches:
return None
elif len(matches) != 1:
ctx.fail(f"Too many matches: {', '.join(sorted(matches))}")
return self._lazy_load(matches[0])

def resolve_command(self, ctx, args):
# always return the full command name
_, cmd, args = super().resolve_command(ctx, args)
assert cmd
return cmd.name, cmd, args
6 changes: 2 additions & 4 deletions src/nomad_tools/common_click.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ def main_options():
)


def common_options():
return composed(
click.help_option("-h", "--help"),
)
def help_h_option():
return click.help_option("-h", "--help")


def verbose_option():
Expand Down
61 changes: 23 additions & 38 deletions src/nomad_tools/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,9 @@
import clickforward
from click.shell_completion import BashComplete

from . import (
entry_constrainteval,
entry_cp,
entry_dockers,
entry_downloadrelease,
entry_githubrunner,
entry_gitlab_runner,
entry_go,
entry_listattributes,
entry_listnodeattributes,
entry_nodenametoid,
entry_port,
entry_task,
entry_info,
entry_vardir,
entry_watch,
)
from .common_click import EPILOG, common_options, main_options
from .aliasedlazygroup import AliasedLazyGroup
from .common_click import EPILOG, help_h_option, main_options
from .common_nomad import namespace_option
from .aliasedgroup import AliasedGroup

clickforward.init()

Expand Down Expand Up @@ -60,37 +43,39 @@
%(complete_func)s_setup;
"""

subcommands = """
constrainteval
cp
dockers
downloadrelease
githubrunner
gitlab-runner
go
info
listattributes
listnodeattributes
nodenametoid
port
task
vardir
watch
""".split()


@click.command(
"nomadtools",
cls=AliasedGroup,
cls=AliasedLazyGroup,
lazy_subcommands={cmd: f"{__package__}.entry_{cmd.replace('-', '_')}.cli" for cmd in subcommands},
help="Collection of useful tools for HashiCorp Nomad.",
epilog=EPILOG,
)
@namespace_option()
@common_options()
@help_h_option()
@main_options()
def cli():
pass


cli.add_command(entry_constrainteval.cli)
cli.add_command(entry_cp.cli)
cli.add_command(entry_dockers.cli)
cli.add_command(entry_downloadrelease.cli)
cli.add_command(entry_githubrunner.cli)
cli.add_command(entry_gitlab_runner.cli)
cli.add_command(entry_go.cli)
cli.add_command(entry_listattributes.cli)
cli.add_command(entry_listnodeattributes.cli)
cli.add_command(entry_nodenametoid.cli)
cli.add_command(entry_port.cli)
cli.add_command(entry_info.cli)
cli.add_command(entry_task.cli)
cli.add_command(entry_vardir.cli)
cli.add_command(entry_watch.cli)


def main():
cli(max_content_width=9999)

Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_constrainteval.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from packaging.version import Version

from .common import mynomad
from .common_click import EPILOG, common_options, verbose_option
from .common_click import EPILOG, help_h_option, verbose_option
from .mytabulate import mytabulate

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -326,7 +326,7 @@ def grouper(thelist: List[str], count: int) -> List[List[str]]:
@clickdc.adddc("args", NodeCacheArgs)
@clickdc.adddc("constraintsargs", ConstraintArgs)
@verbose_option()
@common_options()
@help_h_option()
def cli(args: NodeCacheArgs, constraintsargs: ConstraintArgs):
return main(args, constraintsargs)

Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_cp.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from . import nomadlib, taskexec
from .common import (
cached_property,
common_options,
help_h_option,
mynomad,
namespace_option,
nomad_find_job,
Expand Down Expand Up @@ -814,7 +814,7 @@ class Args:
""",
)
@namespace_option()
@common_options()
@help_h_option()
@clickdc.adddc("args", Args)
def cli(args: Args):
global ARGS
Expand Down
2 changes: 1 addition & 1 deletion src/nomad_tools/entry_dockers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class Args:
`nomadtools dockers ./file.nomad.hcl | xargs docker pull`.
""",
)
@common.common_options()
@common.help_h_option()
@clickdc.adddc("args", Args)
def cli(args: Args):
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_downloadrelease.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import click
import requests

from .common_click import common_options
from .common_click import help_h_option

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -85,7 +85,7 @@ def get_arch() -> str:
is_flag=True,
help="Instead of downloading, only show the chosen version",
)
@common_options()
@help_h_option()
def cli(
pinversion: Optional[str],
arch: str,
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_githubrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from . import nomadlib
from .aliasedgroup import AliasedGroup
from .common import mynomad
from .common_click import common_options
from .common_click import help_h_option
from .nomadlib.connection import urlquote
from .nomadlib.datadict import DataDict

Expand Down Expand Up @@ -1182,7 +1182,7 @@ class Args:

@click.command("githubrunner", cls=AliasedGroup)
@clickdc.adddc("args", Args)
@common_options()
@help_h_option()
def cli(args: Args):
global ARGS
ARGS = args
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_gitlab_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from . import entry_watch, nomadlib, taskexec
from .aliasedgroup import AliasedGroup
from .common import (cached_property, common_options, get_package_file,
from .common import (cached_property, help_h_option, get_package_file,
get_version, mynomad, quotearr)
from .nomadlib.datadict import DataDict
from .nomadlib.types import Job, JobTask, JobTaskConfig
Expand Down Expand Up @@ -679,7 +679,7 @@ class BuildFailure(Exception):
envvar="CUSTOM_ENV_CI_RUNNER_ID",
show_default=True,
)
@common_options()
@help_h_option()
def cli(verbose: int, configpath: Path, runner_id: int):
# Read configuration
configcontent = configpath.read_text()
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from . import entry_watch, taskexec
from .common_base import NOMAD_NAMESPACE, quotearr
from .common_click import EPILOG, common_options
from .common_click import EPILOG, help_h_option
from .common_nomad import namespace_option

clickforward.init()
Expand Down Expand Up @@ -632,7 +632,7 @@ def __thread(self):
"""
f"{EPILOG}",
)
@common_options()
@help_h_option()
@namespace_option()
@clickdc.adddc("args", Args)
@clickdc.adddc("notifyargs", entry_watch.NotifyOptions)
Expand Down
2 changes: 1 addition & 1 deletion src/nomad_tools/entry_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
cls=AliasedGroup,
help="Get information about current Nomad state",
)
@common_click.common_options()
@common_click.help_h_option()
@common_click.verbose_option()
def cli():
pass
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_listattributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import clickdc

from . import entry_constrainteval
from .common import common_options, verbose_option
from .common import help_h_option, verbose_option
from .common_click import completor
from .entry_constrainteval import ConstraintArgs, NodeCacheArgs, NodesAttributes

Expand Down Expand Up @@ -37,7 +37,7 @@ def get_all_nodes_attributes(args: Optional[NodeCacheArgs] = None):
)
@clickdc.adddc("args", NodeCacheArgs)
@verbose_option()
@common_options()
@help_h_option()
def cli(args: NodeCacheArgs, attributes: Tuple[str, ...]):
logging.basicConfig()
if attributes:
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_listnodeattributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import click
import clickdc

from .common import common_options, mynomad, verbose_option
from .common import help_h_option, mynomad, verbose_option
from .common_click import completor
from .entry_constrainteval import NodeCacheArgs, NodesAttributes
from .mytabulate import mytabulate
Expand All @@ -32,7 +32,7 @@ def get_all_node_names():
)
@clickdc.adddc("args", NodeCacheArgs)
@verbose_option()
@common_options()
@help_h_option()
def cli(args: NodeCacheArgs, nodenameorid: Tuple[str, ...]):
logging.basicConfig()
nodesattributes = NodesAttributes.load(args)
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_nodenametoid.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import click

from .common import mynomad
from .common_click import common_options, completor
from .common_click import help_h_option, completor


def get_nodenametoid() -> Dict[str, str]:
Expand All @@ -29,7 +29,7 @@ def get_nodenametoid() -> Dict[str, str]:
required=True,
shell_complete=completor(lambda: list(get_nodenametoid().keys())),
)
@common_options()
@help_h_option()
def cli(prefix: bool, nodename: Tuple[str, ...]):
nodenametoid = get_nodenametoid()
for name in nodename:
Expand Down
4 changes: 2 additions & 2 deletions src/nomad_tools/entry_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from . import nomadlib
from .common import (
alias_option,
common_options,
help_h_option,
mynomad,
namespace_option,
nomad_find_job,
Expand Down Expand Up @@ -135,7 +135,7 @@ def id_completor(
type=re.compile,
help="Show only ports which name matches this regex.",
)
@common_options()
@help_h_option()
@namespace_option()
@click.argument("id", shell_complete=id_completor)
@click.argument("label", required=False)
Expand Down
Loading

0 comments on commit 879dfa0

Please sign in to comment.