Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,42 @@ To build the documentation locally, use the following commands:

The built documentation should be available in ``docs/_build/html``.

.. _contrib_lazy_loading:

Lazy Loading and Adding New Modules
===================================

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
`__getattr__` function in `ultraplot/__init__.py`.

When adding a new submodule, you need to make sure it's compatible with the lazy
loader. Here's how to do it:

1. **Add the submodule to `_STAR_MODULES`:** In `ultraplot/__init__.py`, add the
name of your new submodule to the `_STAR_MODULES` tuple. This will make it
discoverable by the lazy loader.

2. **Add the submodule to `_MODULE_SOURCES`:** Also in `ultraplot/__init__.py`,
add an entry to the `_MODULE_SOURCES` dictionary that maps the name of your
submodule to its source file.

3. **Exposing Callables:** If you want to expose a function or class from your
submodule as a top-level attribute of the `ultraplot` package (e.g.,
`uplt.my_function`), you need to add an entry to the `_EXTRA_ATTRS`
dictionary.

* To expose a function or class `MyFunction` from `my_module.py` as
`uplt.my_function`, add the following to `_EXTRA_ATTRS`:
`"my_function": ("my_module", "MyFunction")`.
* If you want to expose the entire submodule as a top-level attribute
(e.g., `uplt.my_module`), you can add:
`"my_module": ("my_module", None)`.

By following these steps, you can ensure that your new module is correctly
integrated into the lazy loading system.


.. _contrib_pr:

Preparing pull requests
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ For more details, check the full :doc:`User guide <usage>` and :doc:`API Referen
:hidden:

api
lazy_loading
external-links
whats_new
contributing
Expand Down
54 changes: 54 additions & 0 deletions docs/lazy_loading.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.. _lazy_loading:

===================================
Lazy Loading and Adding New Modules
===================================

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:

1. **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 as ``uplt.my_module``. For example, since
:py:mod:`ultraplot.figure` has ``__all__ = ['Figure']``, you can access the `Figure`
class with ``uplt.figure``.

2. **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.
Loading
Loading