-
Notifications
You must be signed in to change notification settings - Fork 200
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 pydantic import #6275
Lazy pydantic import #6275
Conversation
Some benchmarks using main $ hyperfine -w 5 'verdi --version'
Benchmark 1: verdi --version
Time (mean ± σ): 101.4 ms ± 2.3 ms [User: 83.6 ms, System: 16.5 ms]
Range (min … max): 97.6 ms … 105.6 ms 30 runs this PR Benchmark 1: verdi --version
Time (mean ± σ): 65.2 ms ± 2.1 ms [User: 50.9 ms, System: 13.2 ms]
Range (min … max): 62.2 ms … 69.8 ms 45 runs |
Thank you @danielhollas for addressing this. I have a question - how much does |
@edan-bainglass it is not, since pydantic was used by aiida-core only since version 2.5, and we haven't even released an aiidalab image with that version. That being said, version 2.5 contains a lot of work that improved import time so it should result in noticeable improvement. I'll let you know once we release the image, but it might take some time since we need to resolve some package version incompatibilities. |
I'll also note that this particular PR will not help with most of aiida operations (or AiiDAlab load times) since we will need to load pydantic as soon as we load the AiiDA profile. CC @sphuber this is ready for review. Happy to hear your thoughts. This PR kind of assumes that the use of pydantic will stay somewhat localized to |
Well, it already is used outside of
And it is in
but I made sure to keep imports inside methods whenever possible. But I am not a 100% sure if this is not still evaluated during tab-completion, because one of the main motivations for adopting pydantic is to have verdi add subcommands dynamically based on which plugins are installed. See #6190
In #6255 we go even further and essentially use
Maybe not users, but third-party applications may very well be using it directly. For example, would AiiDAlab maybe not be affected? Surely they will operate on the |
Thanks for taking a look @sphuber!
Right, but I indeed double checked that in those cases the imports are inlined so I assumed it will be fine.
We already verify that
Indeed we can, that's what So instead I've added a regression test that calls tab-completion internally.
I don't think so? In
Not sure how to answer this. 😅 The |
Quoting from https://docs.python.org/3/library/sys.html [sys.modules] is a dictionary that maps module names to modules which have already been loaded. This can be manipulated to force reloading of modules and other tricks. However, replacing the dictionary will not necessarily work, as expected and deleting essential items from the dictionary may cause Python to fail... Let's just ignore the last sentence :-)
By the way, I've just found out about |
It's not the only easter egg in |
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.
Thanks @danielhollas
Not sure how to answer this. 😅 The Config class is derived from the pydantic BaseClass, and so pydantic needs to be imported when the Config class itself (not its instances) is built. I don't see a way how to make the class Config available in aiida.manage while also not importing pydantic.
I now remember looking into this and trying but coming up short. I think indeed that it is not possible. So I guess your solution is the best we can do for now.
Also think the breaking of the import is acceptable, so let's continue with these changes.
Indeed we can, that's what verdi devel check-undesired-imports is for! Unfortunately, it does not work in this case, because actually running verdi devel loads the configuration. In the tab-completion case, we have a special monkey-patch that prevents evaluation of dynamic default values that I added in #6144. So instead I've added a regression test that calls tab-completion internally.
Very nice. I am wondering if the verdi devel check-undesired-imports
is now superfluous as it is a subset of the unit test you added? I think technically there is still a difference in code path between merely tab-completing, and actually invoking a command. As you say, some of the command parameters were changed to lazily evaluate their default value, such that they are only executed when the command is actually called. What we are really interested in is that the tab-complete is responsive. So I think we can just add the modules from verdi devel check-undesired-imports
to your unit test and get rid of that command (and invocation in the CI scripts). Right?
Co-authored-by: Sebastiaan Huber <[email protected]>
for more information, see https://pre-commit.ci
I've been thinking about this as well. As you mention, |
pydantic
adds a lot of time to aiida startup, which is especially detrimental to tab completion.Here I test the approach of deferring import of
aiida.manage.configuration.config
until really needed, which in turn defers pydantic.Upcoming usage of pydantic from #6255 seems to be centered in
aiida.orm
which is not imported by default inverdi
so this PR still seems worth it.This is in principle a breaking change since we no longer export
Config
inaiida.manage.configuration
module. But I guess it is not meant to be manipulated directly by users anyway.