Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions orangecanvas/document/editlinksdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from ..registry import InputSignal, OutputSignal

from ..resources import icon_loader
from ..utils import type_str

if typing.TYPE_CHECKING:
from ..scheme import SchemeNode
Expand All @@ -42,9 +43,9 @@ class EditLinksDialog(QDialog):
A dialog for editing links.

>>> dlg = EditLinksDialog()
>>> dlg.setNodes(file_node, test_learners_node)
>>> dlg.setLinks([(file_node.output_channel("Data"),
... test_learners_node.input_channel("Data")])
>>> dlg.setNodes(source_node, sink_node)
>>> dlg.setLinks([(source_node.output_channel("Data"),
... sink_node.input_channel("Data"))])
>>> if dlg.exec_() == EditLinksDialog.Accepted:
... new_links = dlg.links()
...
Expand Down Expand Up @@ -662,7 +663,8 @@ def setSchemeNode(self, node):
text_item.setHtml(text)
text_item.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
text_item.setToolTip(
escape(getattr(channel, 'description', channel.type)))
escape(getattr(channel, 'description', type_str(channel.type)))
)

grid.addItem(text_item, i, label_row,
alignment=label_alignment)
Expand Down
2 changes: 1 addition & 1 deletion orangecanvas/registry/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
log = logging.getLogger(__name__)

# Registry hex version
VERSION_HEX = 0x000104
VERSION_HEX = 0x000105


class WidgetRegistry(object):
Expand Down
65 changes: 56 additions & 9 deletions orangecanvas/registry/description.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import warnings

import typing
from typing import Union, Optional, List, Iterable
from typing import Union, Optional, List, Tuple, Iterable

from orangecanvas.utils import qualified_name

Expand Down Expand Up @@ -72,10 +72,13 @@ class CategorySpecificationError(DescriptionError):

# Input/output signal (channel) description


if typing.TYPE_CHECKING:
#: A simple single type spec (a fully qualified name or a type instance)
TypeSpecSimple = Union[str, type]
#: A tuple of simple type specs indicating a union type.
TypeSpecUnion = Tuple[TypeSpecSimple, ...]
#: Specification of a input/output type
TypeSpec = Union[type, str]
TypeSpec = Union[TypeSpecSimple, TypeSpecUnion]


class InputSignal(object):
Expand All @@ -86,8 +89,13 @@ class InputSignal(object):
----------
name : str
Name of the channel.
type : str or `type`
Type of the accepted signals.
type : Union[str, type] or Tuple[Union[str, type]]
Specify the type of the accepted input. This can be a `type` instance,
a fully qualified type name or a tuple of such. If a tuple then the
input type is a union of the passed types.

.. versionchanged:: 0.1.5
Added `Union` type support.
handler : str
Name of the handler method for the signal.
flags : int
Expand Down Expand Up @@ -132,6 +140,19 @@ def __init__(self, name, type, handler, flags=Single + NonDefault,
self.explicit = bool(flags & Explicit)
self.flags = flags

@property
def types(self):
# type: () -> Tuple[str, ...]
"""
The normalized type specification. This is a tuple of qualified
type names that were passed to the constructor.

.. versionadded:: 0.1.5

:type: Tuple[str, ...]
"""
return normalize_type(self.type)

def __str__(self):
fmt = ("{0.__name__}(name={name!r}, type={type!r}, "
"handler={handler!r}, ...)")
Expand Down Expand Up @@ -160,8 +181,13 @@ class OutputSignal(object):
----------
name : str
Name of the channel.
type : str or `type`
Type of the output signals.
type : Union[str, type] or Tuple[Union[str, type]]
Specify the type of the output. This can be a `type` instance,
a fully qualified type name or a tuple of such. If a tuple then the
output type is a union of the passed types.

.. versionchanged:: 0.1.5
Added `Union` type support.
flags : int, optional
Channel flags.
id : str
Expand Down Expand Up @@ -209,6 +235,19 @@ def __init__(self, name, type, flags=Single + NonDefault,
"Output signal can not be 'Multiple' and 'Dynamic'."
)

@property
def types(self):
# type: () -> Tuple[str, ...]
"""
The normalized type specification. This is a tuple of qualified
type names that were passed to the constructor.

.. versionadded:: 0.1.5

:type: Tuple[str, ...]
"""
return normalize_type(self.type)

def __str__(self):
fmt = ("{0.__name__}(name={name!r}, type={type!r}, "
"...)")
Expand All @@ -230,8 +269,8 @@ def output_channel_from_args(args):
"(got {0!r})".format(type(args)))


def normalize_type(type_):
# type: (TypeSpec) -> str
def normalize_type_simple(type_):
# type: (TypeSpecSimple) -> str
if isinstance(type_, type):
return qualified_name(type_)
elif isinstance(type_, str):
Expand All @@ -240,6 +279,14 @@ def normalize_type(type_):
raise TypeError


def normalize_type(type_):
# type: (TypeSpec) -> Tuple[str, ...]
if isinstance(type_, (type, str)):
return (normalize_type_simple(type_), )
else:
return tuple(map(normalize_type_simple, type_))


class WidgetDescription(object):
"""
Description of a widget.
Expand Down
14 changes: 3 additions & 11 deletions orangecanvas/registry/qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from AnyQt.QtCore import QObject, Qt
from AnyQt.QtCore import pyqtSignal as Signal

from ..utils import type_str
from .discovery import WidgetDiscovery
from .description import WidgetDescription, CategoryDescription
from .base import WidgetRegistry
Expand Down Expand Up @@ -309,26 +310,17 @@ def tooltip_helper(desc):

inputs_fmt = "<li>{name} ({class_name})</li>"

def type_str(type_name):
# type: (Union[str, type]) -> str
if isinstance(type_name, type):
return type_str("{0.__module__}.{0.__qualname__}".format(type_name))
elif type_name.startswith("builtins."):
return type_name[len("builtins."):]
else:
return type_name

if desc.inputs:
inputs = "".join(inputs_fmt.format(name=inp.name,
class_name=type_str(inp.type))
class_name=type_str(inp.types))
for inp in desc.inputs)
tooltip.append("Inputs:<ul>{0}</ul>".format(inputs))
else:
tooltip.append("No inputs")

if desc.outputs:
outputs = "".join(inputs_fmt.format(name=out.name,
class_name=type_str(out.type))
class_name=type_str(out.types))
for out in desc.outputs)
tooltip.append("Outputs:<ul>{0}</ul>".format(outputs))
else:
Expand Down
22 changes: 22 additions & 0 deletions orangecanvas/registry/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from operator import attrgetter

import unittest
from orangecanvas.registry import InputSignal, OutputSignal

from ..base import WidgetRegistry
from .. import description
Expand Down Expand Up @@ -97,3 +98,24 @@ def test_registry_const(self):
for desc in [one_desc, zero_desc, sub_desc,
add_desc])
)

def test_input_signal(self):
isig_1 = InputSignal("A", str, "aa", id="sig-a")
isig_2 = InputSignal("A", 'builtins.str', "aa", id="sig-a")
self.assertTupleEqual(isig_1.types, isig_2.types)
self.assertTupleEqual(isig_1.types, ('builtins.str',))
isig_1 = InputSignal("A", (str, int), "aa", id="sig-a")
isig_2 = InputSignal("A", ('builtins.str', "builtins.int",), "aa",
id="sig-a")
self.assertTupleEqual(isig_1.types, isig_2.types)

def test_output_signal(self):
osig_1 = OutputSignal("A", str, id="sig-a")
osig_2 = OutputSignal("A", 'builtins.str', id="sig-a")
self.assertTupleEqual(osig_1.types, osig_2.types)
self.assertTupleEqual(osig_1.types, ('builtins.str',))
osig_1 = OutputSignal("A", (str, int), id="sig-a")
osig_2 = OutputSignal("A", ('builtins.str', "builtins.int",),
id="sig-a")
self.assertTupleEqual(osig_1.types, osig_2.types)
self.assertTupleEqual(osig_1.types, ('builtins.str', "builtins.int",))
Loading