UltraPlot uses a lazy loading mechanism to improve import times. This means that submodules are not imported until they are actually used. This is controlled by the :py:func:`ultraplot.__getattr__` function in :py:mod:`ultraplot`.
The lazy loading system is mostly automated. It works by scanning the ultraplot directory for modules and exposing them based on conventions.
Convention-Based Loading
The automated system follows these rules:
- Single-Class Modules: If a module my_module.py has an
__all__variable with a single class or function MyCallable, it will be exposed at the top level asuplt.my_module. For example, since :py:mod:`ultraplot.figure` has__all__ = ['Figure'], you can access the Figure class withuplt.figure. - Multi-Content Modules: If a module has multiple items in
__all__or no__all__, the module itself will be exposed. For example, you can access the utils module with :py:mod:`ultraplot.utils`.
Adding New Modules
When adding a new submodule, you usually don't need to modify :py:mod:`ultraplot`. Simply follow these conventions:
- If you want to expose a single class or function from your module as a
top-level attribute, set the
__all__variable in your module to a list containing just that callable's name. - If you want to expose the entire module, you can either use an
__all__with multiple items, or no__all__at all.
Handling Exceptions
For cases that don't fit the conventions, there is an exception-based configuration. The _LAZY_LOADING_EXCEPTIONS dictionary in :py:mod:`ultraplot` is used to manually map top-level attributes to modules and their contents.
You should only need to edit this dictionary if you are:
- Creating an alias for a module (e.g., crs for proj).
- Exposing an internal variable (e.g., colormaps for _cmap_database).
- Exposing a submodule that doesn't follow the file/directory structure.
By following these guidelines, your new module will be correctly integrated into the lazy loading system.