imap_processing.spice.kernels.ensure_spice#

imap_processing.spice.kernels.ensure_spice(__func: Callable[[...], Any]) Callable[[...], Any]#
imap_processing.spice.kernels.ensure_spice(*, time_kernels_only: bool = False) Callable[[Callable[[...], Any]], Callable[[...], Any]]

Decorator/wrapper that automatically furnishes SPICE kernels.

Parameters:
  • __func (Callable) – The function requiring SPICE that we are going to wrap if being used explicitly, otherwise None, in which case ensure_spice is being used, not as a function wrapper (see l2a_processing.py) but as a true decorator without an explicit function argument.

  • time_kernels_only (bool) – Specify that we only need to furnish time kernels (if SPICE_METAKERNEL is set, we still just furnish that metakernel and assume the time kernels are included.

Returns:

Decorated function, with spice error handling.

Return type:

Callable

Notes

Before trying to understand this piece of code, read this: https://stackoverflow.com/questions/5929107/decorators-with-parameters/60832711#60832711

Control flow overview:

  1. Try simply calling the wrapped function naively.
    • SUCCESS? Great! We’re done.

    • SpiceyError? Go to step 2.

  2. Furnish metakernel at SPICE_METAKERNEL
    • SUCCESS? Great, return the original function again (so it can be re-run).

    • KeyError? Seems like SPICE_METAKERNEL isn’t set, no problem. Go to step 3.

  3. Did we get the parameter time_kernels_only=True?
    • YES? We only need LSK and SCLK kernels to run this function. Go fetch those and furnish and return the original function (so it can be re-run).

    • NO? Dang. This is sort of the end of the line. Re-raise the error generated from the failed spiceypy function call but add a better message to it.

Examples

There are three ways to use this object

  1. A decorator with no arguments

    >>> @ensure_spice
    ... def my_spicey_func(a, b):
    ...     pass
    
  2. A decorator with parameters. This is useful if we only need the latest SCLK and LSK kernels for the function involved.

    >>> @ensure_spice(time_kernels_only=True)
    ... def my_spicey_time_func(a, b):
    ...     pass
    
  3. An explicit wrapper function, providing a dynamically set value for parameters, e.g. time_kernels_only

    >>> wrapped = ensure_spice(spicey_func, time_kernels_only=True)
    ... result = wrapped(args, kwargs)