import re
from glue.config import DictRegistry
from ipyvuetify import VuetifyTemplate
from ipywidgets import Widget
__all__ = ['convert', 'UniqueDictRegistry', 'ViewerRegistry', 'TrayRegistry',
'ToolRegistry', 'MenuRegistry', 'DataParserRegistry',
'viewer_registry', 'tray_registry', 'tool_registry', 'menu_registry',
'data_parser_registry']
def _to_snake(s):
"""Convert dashes in viewer category names to underscores for
use in class attributes, constructor kwargs, requirement kwargs.
"""
return s.replace("-", "_")
[docs]
def convert(name):
"""Converts camel-case strings to snake-case. Used when a user does not define
a specific name for a registry item.
Returns
-------
val : str
Name converted to snake-case.
"""
s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
[docs]
class UniqueDictRegistry(DictRegistry):
"""Base registry class that handles hashmap-like associations between a string
representation of a plugin and the class to be instantiated.
"""
[docs]
def add(self, name, cls, overwrite=False):
"""Add an item to the registry.
Parameters
----------
name : str
The name referencing the associated class in the registry.
cls : type
The class definition (not instance) associated with the name given
in the first parameter.
overwrite : bool, optional
Whether to overwrite an existing entry with the same ``label``.
"""
if name in self.members and not overwrite:
raise ValueError(f"Viewer with the name {name} already exists, "
f"please choose a different name or pass overwrite=True.")
else:
self.members[name] = cls
[docs]
class ViewerRegistry(UniqueDictRegistry):
"""Registry containing references to custom viewers."""
[docs]
def __call__(self, name=None, label=None, overwrite=False):
def decorator(cls):
self.add(name, cls, label, overwrite=overwrite)
return cls
return decorator
[docs]
def add(self, name, cls, label=None, overwrite=False):
"""Add an item to the registry.
Parameters
----------
name : str
The key referencing the associated class in the registry
dictionary.
cls : type
The class definition (not instance) associated with the name given
in the first parameter.
label : str, optional
The label displayed in the tooltip when hovering over the tray tab.
overwrite : bool, optional
Whether to overwrite an existing entry with the same ``label``.
"""
if name in self.members and not overwrite:
raise ValueError(f"Viewer with the name {name} already exists, "
f"please choose a different name or pass overwrite=True.")
else:
self.members[name] = {'label': label, 'cls': cls}
[docs]
class TrayRegistry(UniqueDictRegistry):
"""Registry containing references to plugins that will be added to the sidebar
tray tabs.
"""
default_viewer_category = [
"spectrum", "table", "image", "spectrum-2d", "flux", "uncert"
]
default_viewer_reqs = {
category: {
"cls_attr": f"_default_{_to_snake(category)}_viewer_reference_name",
"init_kwarg": f"{_to_snake(category)}_viewer_reference_name",
"require_kwargs": [f"require_{_to_snake(category)}_viewer"]
} for category in default_viewer_category
}
[docs]
def __call__(self, name=None, label=None, icon=None,
viewer_requirements=[], overwrite=False):
def decorator(cls):
# The class must inherit from `VuetifyTemplate` in order to be
# ingestible by the component initialization.
if not issubclass(cls, VuetifyTemplate):
raise ValueError(
f"Unrecognized superclass for {cls.__name__}. All "
f"registered components must inherit from "
f"`ipyvuetify.VuetifyTemplate`.")
self.add(name, cls, label, icon, viewer_requirements, overwrite)
return cls
return decorator
[docs]
def add(self, name, cls, label=None, icon=None,
viewer_requirements=[], overwrite=False):
"""Add an item to the registry.
Parameters
----------
name : str
The key referencing the associated class in the registry
dictionary.
cls : type
The class definition (not instance) associated with the name given
in the first parameter.
label : str, optional
The label displayed in the tooltip when hovering over the tray tab.
icon : str, optional
The name of the icon to render in the tray tab.
viewer_requirements : str, list of str
Required viewers for this plugin.
overwrite : bool, optional
Whether to overwrite an existing entry with the same ``label``.
"""
if name in self.members and not overwrite:
raise ValueError(f"Viewer with the name {name} already exists, "
f"please choose a different name or pass overwrite=True.")
else:
# store the registry name/label so we can access them from the instantiated
# objects (when determining if a specific plugin is open, for example)
viewer_reference_name_kwargs = {}
if not isinstance(viewer_requirements, list):
viewer_requirements = [viewer_requirements]
for category in viewer_requirements:
if category not in self.default_viewer_reqs:
raise ValueError(f'Viewer requirements not defined '
f'for viewer category: "{category}" '
f'in plugin "{cls.__class__.__name__}".')
req = self.default_viewer_reqs[category]
viewer_cls_attr = req['cls_attr']
viewer_specific_kwarg = req['init_kwarg']
requirements = req['require_kwargs']
viewer_reference_name_kwargs[viewer_cls_attr] = [
viewer_specific_kwarg, {
k: True for k in requirements
}
]
cls._registry_name = name
cls._registry_label = label
self.members[name] = {'label': label, 'icon': icon, 'cls': cls,
'viewer_reference_name_kwargs': viewer_reference_name_kwargs}
[docs]
class DataParserRegistry(UniqueDictRegistry):
"""Registry containing parsing functions for attempting to auto-populate the
application-defined initial viewers.
"""
[docs]
def __call__(self, name=None):
def decorator(func):
self.add(name, func)
return func
return decorator
viewer_registry = ViewerRegistry()
tray_registry = TrayRegistry()
tool_registry = ToolRegistry()
menu_registry = MenuRegistry()
data_parser_registry = DataParserRegistry()