Skip to content

Commit

Permalink
Lazy load commands from plugins
Browse files Browse the repository at this point in the history
Signed-off-by: Ankita Katiyar <[email protected]>
  • Loading branch information
ankatiyar committed May 30, 2024
1 parent 27f5405 commit 81ee250
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 6 deletions.
19 changes: 15 additions & 4 deletions kedro/framework/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def __init__(self, project_path: Path):
super().__init__(
("Global commands", self.global_groups),
("Project specific commands", self.project_groups),
lazy_groups=list(self.lazy_global_groups) + list(self.lazy_project_groups),
)

def main(
Expand Down Expand Up @@ -172,13 +173,23 @@ def main(
click.echo(hint)
sys.exit(exc.code)

@property
def lazy_global_groups(self):
eps = _get_entry_points("global")
return eps

@property
def lazy_project_groups(self):
eps = _get_entry_points("project")
return eps

@property
def global_groups(self) -> Sequence[click.MultiCommand]:
"""Property which loads all global command groups from plugins and
combines them with the built-in ones (eventually overriding the
built-in ones if they are redefined by plugins).
"""
return [cli, create_cli, *load_entry_points("global")]
return [cli, create_cli]

@property
def project_groups(self) -> Sequence[click.MultiCommand]:
Expand All @@ -201,15 +212,15 @@ def project_groups(self) -> Sequence[click.MultiCommand]:
registry_cli,
]

plugins = load_entry_points("project")
# plugins = load_entry_points("project")

try:
project_cli = importlib.import_module(f"{self._metadata.package_name}.cli")
# fail gracefully if cli.py does not exist
except ModuleNotFoundError:
# return only built-in commands and commands from plugins
# (plugins can override built-in commands)
return [*built_in, *plugins]
return [*built_in]

# fail badly if cli.py exists, but has no `cli` in it
if not hasattr(project_cli, "cli"):
Expand All @@ -219,7 +230,7 @@ def project_groups(self) -> Sequence[click.MultiCommand]:
user_defined = project_cli.cli
# return built-in commands, plugin commands and user defined commands
# (overriding happens as follows built-in < plugins < cli.py)
return [*built_in, *plugins, user_defined]
return [*built_in, user_defined]


def main() -> None: # pragma: no cover
Expand Down
29 changes: 27 additions & 2 deletions kedro/framework/cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,16 @@ def _suggest_cli_command(
class CommandCollection(click.CommandCollection):
"""Modified from the Click one to still run the source groups function."""

def __init__(self, *groups: tuple[str, Sequence[click.MultiCommand]]):
def __init__(
self, *groups: tuple[str, Sequence[click.MultiCommand]], lazy_groups=None
):
# print("GROUPS", groups)
self.groups = [
(title, self._merge_same_name_collections(cli_list))
for title, cli_list in groups
]
self.lazy_group = lazy_groups
sources = list(chain.from_iterable(cli_list for _, cli_list in self.groups))

help_texts = [
cli.help
for cli_collection in sources
Expand Down Expand Up @@ -179,6 +182,28 @@ def _merge_same_name_collections(
if cli_list
]

def main(
self,
args,
prog_name,
complete_var,
standalone_mode,
**extra,
):
i = 0
while args[0] not in self.list_commands(None) and i < len(self.lazy_group):
loaded_ep = _safe_load_entry_point(self.lazy_group[i])
self.add_source(loaded_ep)
i += 1

return super().main(
args=args,
prog_name=prog_name,
complete_var=complete_var,
standalone_mode=standalone_mode,
**extra,
)

def resolve_command(
self, ctx: click.core.Context, args: list
) -> tuple[str | None, click.Command | None, list[str]]:
Expand Down

0 comments on commit 81ee250

Please sign in to comment.