-
Notifications
You must be signed in to change notification settings - Fork 909
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lazy load commands from plugins #3901
Conversation
Signed-off-by: Ankita Katiyar <[email protected]>
Signed-off-by: Ankita Katiyar <[email protected]>
Signed-off-by: Ankita Katiyar <[email protected]>
To note, as @ankatiyar noted internally, "bad" lookups will take a lot of time: for example, Going forward, is there a smarter way we can declare new CLI commands, so that we can look them up in entry points without actually importing anything? (Feel free to open a new issue about this) |
Signed-off-by: Ankita Katiyar <[email protected]>
Signed-off-by: Ankita Katiyar <[email protected]>
Signed-off-by: Ankita Katiyar <[email protected]>
The code coverage is not complete but opening this up for review anyway to gather feedback on the implementation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some suggestions/questions to the code, but I actually don't think it's a good idea that now the plugin commands aren't loaded when you do kedro --help
. I've built a small plugin myself following https://docs.kedro.org/en/stable/extend_kedro/plugins.html#example-of-a-simple-plugin and the problem you get here is that the commands belong to the kedro
group, but don't show at all. In this case there's no other top-level group you can call to see what sub-commands exist. On top of that the overwriting behaviour is changed, so if I now create my own micropkg
command inside this kedrojson
plugin it doesn't overwrite the original kedro micropkg
where in the non lazy-loading version it does do the overwriting.
While this solution does lead to performance gain, it also degrades the plugin command discoverability and therefore IMO usability of the plugins as a whole. Features like https://docs.kedro.org/en/stable/extend_kedro/plugins.html#global-and-project-commands will not exist anymore after this change.
All in all, I don't think the performance gains are worth losing the plugin features.
@@ -172,13 +174,19 @@ def main( | |||
click.echo(hint) | |||
sys.exit(exc.code) | |||
|
|||
@property | |||
def plugin_groups(self) -> dict[str, EntryPoint]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a docstring here to explain what the property is for?
"""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). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing this needs to be updated, because it's not loading the plugins anymore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also wondering whether the "overriding" behaviour mentioned here is changed with the lazy loading? Update: I tested this and the behaviour is indeed changed. With the lazy loading it seems like the overwritten version isn't called.
@@ -90,6 +90,13 @@ def wrapit(func: Any) -> Any: | |||
return wrapit | |||
|
|||
|
|||
def _partial_match(plugin_names: list[str], command_name: str) -> str | None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a docstring here as well?
Fair point @merelcht! 🤔 |
**extra: Any, | ||
) -> Any: | ||
# Load plugins if the command is not found in the current sources | ||
if args and args[0] not in self.list_commands(None): # type: ignore[arg-type] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does self.list_commands(None)
do? From the docs it seems like it expects a ctx
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be replaced with get_command
instead? https://click.palletsprojects.com/en/8.1.x/api/#click.MultiCommand.get_command
Unfortunately, I don't think the overriding behaviour of CLI is possible with lazy loading of plugins - i.e. if a plugin has overriding CLI commands for Kedro core commands such as |
The For retaining the current behavior while attaining much faster load times for all the rest of commands, I'd be 👍🏼 on force-triggering loading of all plugins in |
Moving this back to the drafts, will close it if no other comments come in. I'll focus on getting kedro-org/kedro-viz#1920 and #3883 ready for review first! |
Closing this in favour of the other solution! |
Description
Partly resolve #1476
As discussed in #1476, the initialisation of
KedroCLI
takes up a significant chunk of time. This is especially evident if you have a lot of kedro plugins installed in the environment asKedroCLI
which is aCommandCollection
, loads up all the commands from the plugins before the command is processed. This PR is to add a lazy way to load the commands from the plugins.Development notes
plugin_groups
which returns adict
ofentry_point_name
to theEntryPoint
object.CommandCollection
which is a custom version ofclick.CommandCollection
used by Kedro and defined inkedro/framework/cli/utils.py
Update to custom
CommandCollection
:main
function which receives the command to be run asargs
, eg[ "catalog", "list"]
or["airflow", "create"]
args
is not in the command, then load commands from pluginssuper().main()
Loading of plugins:
I tried to implement a sort of "smart" loading where if the command arg, i.e.
airflow
ormlflow
orviz
partially matches the entry point names in thelazy_group
dict keys, load the plugin, check if the command now exists and exit.Note: The entry point names are decided by the plugins, eg.
kedro-airflow
's ep name isairflow
which fully matches the command name too but forkedro-viz
andkedro-mlflow
the entry point names don't match the commands. eg. Command:viz
Entry point name:kedro-viz
Otherwise, load all plugins one by one, exit if the command exists after loading plugins.
TODO
Developer Certificate of Origin
We need all contributions to comply with the Developer Certificate of Origin (DCO). All commits must be signed off by including a
Signed-off-by
line in the commit message. See our wiki for guidance.If your PR is blocked due to unsigned commits, then you must follow the instructions under "Rebase the branch" on the GitHub Checks page for your PR. This will retroactively add the sign-off to all unsigned commits and allow the DCO check to pass.
Checklist
RELEASE.md
file