-
-
Notifications
You must be signed in to change notification settings - Fork 9
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 subapps/subcommands #276
Comments
Is your project publicly available? I'd like to run a profiler on it. Lazy loading is one solution, but I wonder if something else is slow (and lazy loading would be a premature optimization that wouldn't help too much). |
Yes. Would be lovely. Thanks! |
@BrianPugh Thanks for profiling! It seems cyclopts itself is very efficient with loading subapps/commands, so the issue is mostly loading the 3rd party libs in those. I can move some of those imports into the commands themselves which helps. Maybe lazy loading was the wrong term. I looked into your documentation regarding Meta Apps - maybe that's what I'm looking for? I.e. launching the |
Hmmm sorry I still don't quite follow 😅. Can you explain in more detail/example about what you are trying to achieve? And I'll be merging in these optimizations and cutting a release later today 👍. |
I apologize. I might just be oblivious because I'm not that experienced with CLIs. The entrypoint application can have commands registered, and it can have applications registered as commands. If we look at the example from the post, I have a So I'm thinking that the main app only need to know about the two commands: If we instead run So if I for example run
In this example, we skipped over registering the following commands (marked with asterisk). If we could skip registing those when the main app is launched, I would imagine a great improvement which only increases, the more complex/nested command structure is. In the project I linked, I have over 200 commands, but they're spread across sub-applications, so if we could only register a subset of nested commands, I imagine it a great performance boost.
|
I see what you mean; currently I think Cyclopts is fast enough that it probably doesn't matter to much; I think we could only save a few dozens of milliseconds in very large applications from lazily importing/parsing subapplications. A potentially attractive option would be to register subapplications as a reference string (sort of how scripts work in python-packaging), where Cyclopts would dynamically import it if necessary: from cyclopts import App
app = App()
app.command("msfabricutils.cli.core.kql_database:create", name="create") # something like this The real benefit here would be if specific subapp's import modules that are relatively expensive to import, that it wouldn't be come additive over the entire app. I'll need to think about this a little more. Some minor clarification of how Cyclopts works internally: ideally, it would work as you describe (subcommands directly invoking subapps who subsequently invoke their own subapps; it would be beautifully recursive). Unfortunately, due to implementation details of how "help" works (e.g. you need the entire list of commands that lead up to the current subcommand), the root app actually directly invokes a subapp, no matter how far down the invocation chain it is. Second aside; I see you reaching in to the private |
Absolutely. That is evident from the profling you did.
Exactly. One specific subapp could have a really expensive import which would slow the entire app, so being able to optionally lazy load it would be helpful (I think). Either directly exposed like import time
from cyclopts import App
app = App()
def expensive_command():
time.sleep(2)
@app.command
def admin_command():
admin_app = App()
admin_app.command(expensive_command, name="expensive")
admin_app()
if __name__ == "__main__":
app()
Yes, a little hack to skip over the "core" command while maintaining the code-generated folder/file structure. Eventually, I would just not create the "core" app in the first place and register its commands directly on the main app. |
Hi - I love the ergonomics of this. It's really a breeze to work with.
I've built a CLI with a lot of nested subapps/subcommands, and since it goes through and registers everything on every invocation, it is a bit slow.
Is there any way to lazy load subapps and its subcommands? Here's an example.
When I run
mycli --help
only data-pipeline and environment subapps should be loaded, but not their subapps/commands.When I run
mycli environment
then only children of the environment subapp should be loaded.And this is how I do it currently:
The text was updated successfully, but these errors were encountered: