🔍 Code Extractor

class Callable

Maturity: 72

Callable is a wrapper class for callback functions used with DynamicMaps, providing memoization, stream management, and input/output tracking capabilities.

File:
/tf/active/vicechatdev/patches/spaces.py
Lines:
434 - 602
Complexity:
complex

Purpose

This class wraps callable functions to enable advanced features for dynamic visualizations in HoloViews. It manages memoization of function results based on arguments and stream states, tracks input dependencies for chaining operations, handles stream mappings for interactive visualizations, and provides introspection capabilities for the wrapped function. It's primarily used to create dynamic, interactive visualizations that can respond to user interactions and efficiently cache results.

Source Code

class Callable(param.Parameterized):
    """
    Callable allows wrapping callbacks on one or more DynamicMaps
    allowing their inputs (and in future outputs) to be defined.
    This makes it possible to wrap DynamicMaps with streams and
    makes it possible to traverse the graph of operations applied
    to a DynamicMap.

    Additionally, if the memoize attribute is True, a Callable will
    memoize the last returned value based on the arguments to the
    function and the state of all streams on its inputs, to avoid
    calling the function unnecessarily. Note that because memoization
    includes the streams found on the inputs it may be disabled if the
    stream requires it and is triggering.

    A Callable may also specify a stream_mapping which specifies the
    objects that are associated with interactive (i.e. linked) streams
    when composite objects such as Layouts are returned from the
    callback. This is required for building interactive, linked
    visualizations (for the backends that support them) when returning
    Layouts, NdLayouts or GridSpace objects. When chaining multiple
    DynamicMaps into a pipeline, the link_inputs parameter declares
    whether the visualization generated using this Callable will
    inherit the linked streams. This parameter is used as a hint by
    the applicable backend.

    The mapping should map from an appropriate key to a list of
    streams associated with the selected object. The appropriate key
    may be a type[.group][.label] specification for Layouts, an
    integer index or a suitable NdLayout/GridSpace key. For more
    information see the DynamicMap tutorial at holoviews.org.
    """

    callable = param.Callable(default=None, constant=True, doc="""
         The callable function being wrapped.""")

    inputs = param.List(default=[], constant=True, doc="""
         The list of inputs the callable function is wrapping. Used
         to allow deep access to streams in chained Callables.""")

    operation_kwargs = param.Dict(default={}, constant=True, doc="""
        Potential dynamic keyword arguments associated with the
        operation.""")

    link_inputs = param.Boolean(default=True, doc="""
         If the Callable wraps around other DynamicMaps in its inputs,
         determines whether linked streams attached to the inputs are
         transferred to the objects returned by the Callable.

         For example the Callable wraps a DynamicMap with an RangeXY
         stream, this switch determines whether the corresponding
         visualization should update this stream with range changes
         originating from the newly generated axes.""")

    memoize = param.Boolean(default=True, doc="""
         Whether the return value of the callable should be memoized
         based on the call arguments and any streams attached to the
         inputs.""")

    operation = param.Callable(default=None, doc="""
         The function being applied by the Callable. May be used
         to record the transform(s) being applied inside the
         callback function.""")

    stream_mapping = param.Dict(default={}, constant=True, doc="""
         Defines how streams should be mapped to objects returned by
         the Callable, e.g. when it returns a Layout.""")

    def __init__(self, callable, **params):
        super().__init__(callable=callable,
                         **dict(params, name=util.callable_name(callable)))
        self._memoized = {}
        self._is_overlay = False
        self.args = None
        self.kwargs = None
        self._stream_memoization = self.memoize

    @property
    def argspec(self):
        return util.argspec(self.callable)

    @property
    def noargs(self):
        "Returns True if the callable takes no arguments"
        noargs = FullArgSpec(args=[], varargs=None, varkw=None, defaults=None, kwonlyargs=None, kwonlydefaults=None, annotations=None)
        return self.argspec == noargs


    def clone(self, callable=None, **overrides):
        """Clones the Callable optionally with new settings

        Args:
            callable: New callable function to wrap
            **overrides: Parameter overrides to apply

        Returns:
            Cloned Callable object
        """
        old = {k: v for k, v in self.param.get_param_values()
               if k not in ['callable', 'name']}
        params = dict(old, **overrides)
        callable = self.callable if callable is None else callable
        return self.__class__(callable, **params)


    def __call__(self, *args, **kwargs):
        """Calls the callable function with supplied args and kwargs.

        If enabled uses memoization to avoid calling function
        unneccessarily.

        Args:
            *args: Arguments passed to the callable function
            **kwargs: Keyword arguments passed to the callable function

        Returns:
            Return value of the wrapped callable function
        """
        # Nothing to do for callbacks that accept no arguments
        kwarg_hash = kwargs.pop('_memoization_hash_', ())
        (self.args, self.kwargs) = (args, kwargs)
        if not args and not kwargs and not any(kwarg_hash): return self.callable()
        inputs = [i for i in self.inputs if isinstance(i, DynamicMap)]
        streams = []
        for stream in [s for i in inputs for s in get_nested_streams(i)]:
            if stream not in streams: streams.append(stream)

        memoize = self._stream_memoization and not any(s.transient and s._triggering for s in streams)
        values = tuple(tuple(sorted(s.hashkey.items())) for s in streams)
        key = args + kwarg_hash + values

        hashed_key = util.deephash(key) if self.memoize else None
        if hashed_key is not None and memoize and hashed_key in self._memoized:
            return self._memoized[hashed_key]

        if self.argspec.varargs is not None:
            # Missing information on positional argument names, cannot promote to keywords
            pass
        elif len(args) != 0: # Turn positional arguments into keyword arguments
            pos_kwargs = {k:v for k,v in zip(self.argspec.args, args)}
            ignored = range(len(self.argspec.args),len(args))
            if len(ignored):
                self.param.warning('Ignoring extra positional argument %s'
                                   % ', '.join('%s' % i for i in ignored))
            clashes = set(pos_kwargs.keys()) & set(kwargs.keys())
            if clashes:
                self.param.warning(
                    'Positional arguments %r overriden by keywords'
                    % list(clashes))
            args, kwargs = (), dict(pos_kwargs, **kwargs)

        try:
            ret = self.callable(*args, **kwargs)
        except KeyError:
            # KeyError is caught separately because it is used to signal
            # invalid keys on DynamicMap and should not warn
            raise
        except Exception as e:
            posstr = ', '.join(['%r' % el for el in self.args]) if self.args else ''
            kwstr = ', '.join('%s=%r' % (k,v) for k,v in self.kwargs.items())
            argstr = ', '.join([el for el in [posstr, kwstr] if el])
            message = ("Callable raised \"{e}\".\n"
                       "Invoked as {name}({argstr})")
            self.param.warning(message.format(name=self.name, argstr=argstr, e=repr(e)))
            raise

        if hashed_key is not None:
            self._memoized = {hashed_key : ret}
        return ret

Parameters

Name Type Default Kind
bases param.Parameterized -

Parameter Details

callable: The callable function to be wrapped. This is the core function that will be executed when the Callable instance is invoked. Must be a valid Python callable (function, lambda, method, etc.).

inputs: List of input objects (typically DynamicMaps) that this callable depends on. Used to traverse the graph of operations and access nested streams. Default is empty list.

operation_kwargs: Dictionary of dynamic keyword arguments associated with the operation. These are potential parameters that may be passed to the callable. Default is empty dict.

link_inputs: Boolean flag determining whether linked streams from input DynamicMaps should be transferred to objects returned by this Callable. When True, interactive streams (like RangeXY) are propagated. Default is True.

memoize: Boolean flag controlling whether the callable's return value should be cached based on call arguments and stream states. When True, avoids redundant function calls. Default is True.

operation: Optional callable representing the actual operation/transform being applied. Used for recording the transformation pipeline. Default is None.

stream_mapping: Dictionary defining how streams should be mapped to objects returned by the Callable (e.g., when returning Layouts). Keys can be type specifications, indices, or Layout keys. Default is empty dict.

**params: Additional parameters passed to the parent param.Parameterized class, including 'name' which is auto-generated from the callable if not provided.

Return Value

Instantiation returns a Callable object that wraps the provided function. When the instance is called (via __call__), it returns the result of executing the wrapped callable function with the provided arguments. The clone() method returns a new Callable instance with optionally modified settings. The argspec property returns a FullArgSpec object describing the callable's signature. The noargs property returns a boolean indicating if the callable takes no arguments.

Class Interface

Methods

__init__(self, callable, **params)

Purpose: Initialize the Callable wrapper with a function and configuration parameters

Parameters:

  • callable: The function to wrap
  • **params: Additional parameters including inputs, memoize, link_inputs, operation, stream_mapping, operation_kwargs

Returns: None - initializes the Callable instance

@property argspec(self) property

Purpose: Returns the argument specification of the wrapped callable function

Returns: FullArgSpec object containing args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, and annotations

@property noargs(self) property

Purpose: Checks if the wrapped callable takes no arguments

Returns: Boolean - True if the callable accepts no arguments, False otherwise

clone(self, callable=None, **overrides)

Purpose: Creates a copy of the Callable with optionally modified settings

Parameters:

  • callable: Optional new callable function to wrap in the clone. If None, uses the current callable
  • **overrides: Parameter overrides to apply to the cloned instance (e.g., memoize=False, link_inputs=False)

Returns: New Callable instance with the same or modified configuration

__call__(self, *args, **kwargs)

Purpose: Executes the wrapped callable function with memoization support

Parameters:

  • *args: Positional arguments to pass to the wrapped function
  • **kwargs: Keyword arguments to pass to the wrapped function. Special kwarg '_memoization_hash_' is used internally for cache key generation

Returns: The return value of the wrapped callable function, potentially retrieved from cache if memoization is enabled

Attributes

Name Type Description Scope
callable param.Callable The wrapped callable function. This is a constant parameter that cannot be changed after initialization. instance
inputs param.List List of input objects (typically DynamicMaps) that this callable depends on. Used for stream traversal and dependency tracking. Constant after initialization. instance
operation_kwargs param.Dict Dictionary of dynamic keyword arguments associated with the operation. Constant after initialization. instance
link_inputs param.Boolean Flag controlling whether linked streams from inputs are transferred to returned objects. Can be modified after initialization. instance
memoize param.Boolean Flag controlling whether return values should be cached based on arguments and stream states. Can be modified after initialization. instance
operation param.Callable Optional callable representing the operation being applied. Used for recording transformations in the pipeline. instance
stream_mapping param.Dict Dictionary mapping keys to lists of streams for composite return objects. Constant after initialization. instance
_memoized dict Internal cache storing the last memoized result. Key is a hash of arguments and stream states, value is the cached return value. instance
_is_overlay bool Internal flag indicating if the callable returns an overlay object. Initialized to False. instance
args tuple or None Stores the positional arguments from the last call to __call__. Used for debugging and error reporting. instance
kwargs dict or None Stores the keyword arguments from the last call to __call__. Used for debugging and error reporting. instance
_stream_memoization bool Internal copy of the memoize setting used for stream-aware memoization logic. Initialized from the memoize parameter. instance

Dependencies

  • param
  • numpy
  • holoviews.core.util
  • holoviews.core.traversal
  • holoviews.core.dimension
  • holoviews.core.layout
  • holoviews.core.ndmapping
  • holoviews.core.overlay
  • holoviews.core.options
  • holoviews.streams

Required Imports

import param
import numpy as np
from inspect import FullArgSpec
from holoviews.core import util
from holoviews.core.spaces import DynamicMap
from holoviews.streams import get_nested_streams

Conditional/Optional Imports

These imports are only needed under specific conditions:

from inspect import ArgSpec as FullArgSpec

Condition: Fallback for older Python versions that don't have FullArgSpec

Optional

Usage Example

import param
from holoviews.core.spaces import Callable, DynamicMap
import numpy as np

# Define a simple callback function
def my_callback(x, y):
    return x + y

# Create a Callable wrapper
callable_obj = Callable(my_callback, memoize=True, link_inputs=True)

# Call the wrapped function
result = callable_obj(5, 10)
print(result)  # Output: 15

# Clone with different settings
cloned = callable_obj.clone(memoize=False)

# Check if callable takes no arguments
print(callable_obj.noargs)  # Output: False

# Access the argument specification
print(callable_obj.argspec)

# Example with DynamicMap inputs
def process_data(data):
    return data * 2

dmap = DynamicMap(lambda: np.random.rand(10))
callable_with_inputs = Callable(process_data, inputs=[dmap])
result = callable_with_inputs(np.array([1, 2, 3]))

Best Practices

  • Enable memoization (memoize=True) for expensive computations to avoid redundant calls
  • Set link_inputs=False if you don't want interactive streams to propagate from inputs to outputs
  • Use stream_mapping when returning composite objects (Layouts, NdLayouts) to properly associate streams with sub-objects
  • The callable should handle exceptions gracefully as the wrapper will catch and log them with context
  • Memoization is automatically disabled for transient streams that are triggering to ensure fresh data
  • When chaining Callables, be aware that streams from inputs are collected and their states affect memoization
  • The _memoized cache only stores the last result, so it's not a full LRU cache
  • Positional arguments are automatically converted to keyword arguments when possible for better introspection
  • The args and kwargs attributes store the last call's arguments for debugging purposes
  • Use clone() to create variations of a Callable with different settings without modifying the original

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class DynamicMap 63.4% similar

    A DynamicMap is a type of HoloMap where the elements are dynamically generated by a callable. The callable is invoked with values associated with the key dimensions or with values supplied by stream parameters.

    From: /tf/active/vicechatdev/patches/spaces.py
  • function dynamicmap_memoization 62.3% similar

    A context manager that temporarily controls memoization behavior of a callable object based on the state of associated streams, disabling memoization when transient streams are triggering.

    From: /tf/active/vicechatdev/patches/spaces.py
  • class HoloMap 51.6% similar

    HoloMap is an n-dimensional mapping container that stores viewable elements or overlays indexed by tuple keys along declared key dimensions, enabling interactive exploration through widgets.

    From: /tf/active/vicechatdev/patches/spaces.py
  • function validate_dynamic_argspec 48.4% similar

    Validates that a callback function has an appropriate signature to work with DynamicMap by checking its arguments against key dimensions (kdims) and stream parameters.

    From: /tf/active/vicechatdev/patches/util.py
  • class periodic_v1 47.7% similar

    A utility class that manages periodic event updates for DynamicMap objects, allowing scheduled triggering of stream updates that can be started and stopped.

    From: /tf/active/vicechatdev/patches/spaces.py
← Back to Browse