meta,api: lazy load fact and operation modules#1609
meta,api: lazy load fact and operation modules#1609Fizzadar merged 10 commits intopyinfra-dev:3.xfrom
Conversation
Lazy loading of modules from the init file, should keep the same functionalities as before.
|
this does fix this issue, as seen in the following files: pyinfra_fact_import_new.txt As it is possible to see, only the bare minimum for each of these was imported. I would still advise to try and lazify the imports to inside specific functions instead of importing everything in the start of the file, as this would heavily impact import startup. |
Fizzadar
left a comment
There was a problem hiding this comment.
The import improvements are 🔥, awesome stuff!
Other bits should be broken out or removed though please.
Points taken! I already fixed what was asked to be fixed (very simple shtuff altogether, so easy fix), however, I'm in an area that blocks port 22, so I'll take a while to push! all tests (except debian based ones) are passing, and the code is linted |
Its an honor to be a part of this! |


What
This PR introduces lazy loading inside of operations/init.py (including freebsd) and facts/init.py by leveraging PEP 562 module-level getattr.
Instead of eagerly globbing and importing all available facts and operations upfront, modules are now only imported on-demand when explicitly requested. To ensure compatibility with test runners like pytest and avoid ModuleNotFoundError during test discovery, the dynamic imports are properly anchored using package.
Note: I originally experimented with lazy loading api/init.py as well, but reverted it as it acts as the public contract for the library and making it lazy broke several downstream tests due to circular import complexities.
Why
The current implementation using glob and from . import * forces a massive I/O and CPU overhead whenever Pyinfra is used in API mode, loading dozens of modules that the user might never use.
By making this lazy:
The I/O from importing facts/operations only occurs for the specific modules actually utilized in a run.
Startup time and memory footprint are significantly reduced, especially for users wrapping Pyinfra as an execution engine.
IDE autocompletion and static type checkers are preserved because all is still dynamically generated without executing the module bodies.
Addition
Now tests/test_operations.py skips execution if not inside a debian based distro (I was having issues in Arch only to discover this was the issue)
Added: ansi_color in api/utils.py, this was made in order to remove the click dependency from inside the API.
It should be noted that this should futurally be refactored in order to separate lib and interface
3.xat this time)scripts/dev-test.sh)scripts/dev-lint.sh)