"""Each Orange3 add-on installs entry-points for widgets and tutorials.
Widget and example discovery is done from these entry-points.
"""
import logging
from typing import List, Optional
from . import pkg_meta
from .orange_version import ORANGE_VERSION
from .canvas.utils import get_orange_canvas
if ORANGE_VERSION == ORANGE_VERSION.oasys_fork:
from oasys.canvas.conf import WIDGETS_ENTRY # "oasys.widgets"
from orangewidget.canvas.discovery import WidgetDiscovery
from orangecanvas.registry.base import WidgetRegistry
from orangecanvas.registry.description import WidgetDescription
from orangecanvas.registry.description import InputSignal
from orangecanvas.registry.description import OutputSignal
from orangecanvas.registry import global_registry
from orangecanvas.registry.utils import category_from_package_globals
def _get_widget_description(widget_class) -> WidgetDescription:
widget_cls_name = widget_class.__name__
qualified_name = "%s.%s" % (widget_class.__module__, widget_cls_name)
inputs = [
InputSignal(s.name, s.type, s.handler, s.flags, s.id, s.doc)
for s in widget_class.inputs
]
outputs = [
OutputSignal(s.name, s.type, s.flags, s.id, s.doc)
for s in widget_class.outputs
]
# Convert all signal types into qualified names.
# This is to prevent any possible import problems when cached
# descriptions are unpickled (the relevant code using this lists
# should be able to handle missing types better).
for s in inputs + outputs:
if isinstance(s.type, type):
s.type = "%s.%s" % (s.type.__module__, s.type.__name__)
return WidgetDescription(
name=widget_class.name,
id=widget_class.id,
version=widget_class.version,
description=widget_class.description,
long_description=widget_class.long_description,
qualified_name=qualified_name,
inputs=inputs,
outputs=outputs,
author=widget_class.author,
author_email=widget_class.author_email,
maintainer=widget_class.maintainer,
maintainer_email=widget_class.maintainer_email,
help=widget_class.help,
help_ref=widget_class.help_ref,
url=widget_class.url,
keywords=widget_class.keywords,
priority=widget_class.priority,
icon=widget_class.icon,
background=widget_class.background,
replaces=widget_class.replaces,
)
NATIVE_WIDGETS_PROJECT = "oasys1"
else:
from orangewidget.workflow.discovery import WidgetDiscovery
from orangecanvas.registry.base import WidgetRegistry
from orangecanvas.registry import WidgetDescription
from orangecanvas.registry import global_registry
from orangecanvas.registry.utils import category_from_package_globals
from orangewidget.workflow.config import WIDGETS_ENTRY # "orange.widgets"
NATIVE_WIDGETS_PROJECT = "orange3"
NAMESPACE_PACKAGE = "orangecontrib"
logger = logging.getLogger(__name__)
def _iter_entry_points(group):
"""Do not include native orange entry points"""
for ep in pkg_meta.iter_entry_points(group):
if pkg_meta.get_distribution_name(ep.dist).lower() != NATIVE_WIDGETS_PROJECT:
yield ep
def _global_widget_discovery_objects() -> List[WidgetDiscovery]:
return [WidgetDiscovery(reg) for reg in _global_registry_objects()]
def _local_widget_discovery_object() -> WidgetDiscovery:
return WidgetDiscovery(WidgetRegistry())
def _global_registry_objects() -> List[WidgetRegistry]:
registry_objects = list()
scene = None
canvas = get_orange_canvas()
if canvas is not None:
scene = canvas.current_document()
reg = canvas.widget_registry
if reg is not None:
registry_objects.append(reg)
if ORANGE_VERSION != ORANGE_VERSION.oasys_fork and scene is not None:
reg = scene.registry()
if reg is not None:
registry_objects.append(reg)
if not registry_objects:
reg = global_registry()
if reg is not None:
registry_objects.append(reg)
return registry_objects
def _get_owwidget_description(
widget_class, package_name: str, category_name: str, project_name: str
):
if ORANGE_VERSION == ORANGE_VERSION.oasys_fork:
description = _get_widget_description(widget_class)
else:
kwargs = widget_class.get_widget_description()
description = WidgetDescription(**kwargs)
description.package = _orangecontrib_qualname(package_name)
description.category = widget_class.category or category_name
description.project_name = project_name
return description
def _get_owcategory_description(
package_name: str, category_name: str, project_name: str
):
description = category_from_package_globals(package_name)
description.name = category_name
description.project_name = project_name
return description
def _register_owcategory(
package_name: str,
category_name: str,
project_name: str,
discovery_object: Optional[WidgetDiscovery] = None,
):
description = _get_owcategory_description(package_name, category_name, project_name)
if discovery_object is None:
for discovery_object in _global_widget_discovery_objects():
discovery_object.handle_category(description)
else:
discovery_object.handle_category(description)
def _orangecontrib_qualname(qualname):
if f".{NAMESPACE_PACKAGE}." in qualname:
return (
f"{NAMESPACE_PACKAGE}." + qualname.partition(f".{NAMESPACE_PACKAGE}.")[-1]
)
return qualname