# This module handles the definition of mixin 'handlers' which are functions # that given an arbitrary object (e.g. a dask array) will return an object that # can be used as a mixin column. This is useful because it means that users can # then add objects to tables that are not formally mixin columns and where # adding an info attribute is beyond our control. __all__ = ['MixinRegistryError', 'register_mixin_handler', 'get_mixin_handler'] # The internal dictionary of handlers maps fully qualified names of classes # to a function that can take an object and return a mixin-compatible object. _handlers = {} class MixinRegistryError(Exception): pass def register_mixin_handler(fully_qualified_name, handler, force=False): """ Register a mixin column 'handler'. A mixin column handler is a function that given an arbitrary Python object, will return an object with the .info attribute that can then be used as a mixin column (this can be e.g. a copy of the object with a new attribute, a subclass instance, or a wrapper class - this is left up to the handler). The handler will be used on classes that have an exactly matching fully qualified name. Parameters ---------- fully_qualified_name : str The fully qualified name of the class that the handler can operate on, such as e.g. ``dask.array.core.Array``. handler : func The handler function. force : bool, optional Whether to overwrite any previous handler if there is already one for the same fully qualified name. """ if fully_qualified_name not in _handlers or force: _handlers[fully_qualified_name] = handler else: raise MixinRegistryError(f"Handler for class {fully_qualified_name} is already defined") def get_mixin_handler(obj): """ Given an arbitrary object, return the matching mixin handler (if any). Parameters ---------- obj : object or str The object to find a mixin handler for, or a fully qualified name. Returns ------- handler : None or func Then matching handler, if found, or `None` """ if isinstance(obj, str): return _handlers.get(obj, None) else: return _handlers.get(obj.__class__.__module__ + '.' + obj.__class__.__name__, None) # Add built-in handlers to registry. Note that any third-party package imports # required by the handlers should go inside the handler function to delay # the imports until they are actually needed. def dask_handler(arr): from astropy.table.mixins.dask import as_dask_column return as_dask_column(arr) register_mixin_handler('dask.array.core.Array', dask_handler)