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 29, 2024
1 parent 40306e3 commit 2931ac7
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 36 deletions.
58 changes: 22 additions & 36 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 .lazygroup import LazyGroup
from .common_click import EPILOG, common_options, main_options
from .common_nomad import namespace_option
from .aliasedgroup import AliasedGroup

clickforward.init()

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

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



@click.command(
"nomadtools",
cls=AliasedGroup,
cls=LazyGroup,
lazy_subcommands={cmd: f"{__package__}.entry_{cmd}.cli" for cmd in subcommands},
help="Collection of useful tools for HashiCorp Nomad.",
epilog=EPILOG,
)
Expand All @@ -74,23 +77,6 @@ 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
40 changes: 40 additions & 0 deletions src/nomad_tools/lazygroup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# https://click.palletsprojects.com/en/8.1.x/complex/#defining-the-lazy-group
import importlib
import click
from .aliasedgroup import AliasedGroup


class LazyGroup(AliasedGroup):
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 get_command(self, ctx, cmd_name):
if cmd_name in self.lazy_subcommands:
return self._lazy_load(cmd_name)
return super().get_command(ctx, cmd_name)

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.BaseCommand):
raise ValueError(
f"Lazy loading of {import_path} failed by returning "
"a non-command object"
)
return cmd_object

0 comments on commit 2931ac7

Please sign in to comment.