Source code for orangecanvas.scheme.link

"""
===========
Scheme Link
===========

"""
import enum
import typing
from typing import List, Tuple, Union

from AnyQt.QtCore import QObject
from AnyQt.QtCore import pyqtSignal as Signal, pyqtProperty as Property

from ..utils import type_lookup, type_lookup_
from .errors import IncompatibleChannelTypeError

if typing.TYPE_CHECKING:
    from ..registry import OutputSignal as Output, InputSignal as Input
    from . import SchemeNode as Node


def compatible_channels(source_channel, sink_channel):
    # type: (Output, Input) -> bool
    """
    Do the channels in link have compatible types, i.e. can they be
    connected based on their type.
    """
    source_type = type_lookup_(source_channel.type)
    sink_type = type_lookup_(sink_channel.type)
    if source_type is None or sink_type is None:
        return False
    ret = issubclass(source_type, sink_type)
    if source_channel.dynamic:
        ret = ret or issubclass(sink_type, source_type)
    return ret


def can_connect(source_node, sink_node):
    # type: (Node, Node) -> bool
    """
    Return True if any output from `source_node` can be connected to
    any input of `sink_node`.

    """
    return bool(possible_links(source_node, sink_node))


def possible_links(source_node, sink_node):
    # type: (Node, Node) -> List[Tuple[Output, Input]]
    """
    Return a list of (OutputSignal, InputSignal) tuples, that
    can connect the two nodes.

    """
    possible = []
    for source in source_node.output_channels():
        for sink in sink_node.input_channels():
            if compatible_channels(source, sink):
                possible.append((source, sink))
    return possible


def _get_type(arg):
    # type: (Union[str, type]) -> type
    """get a type instance qualified name"""
    if isinstance(arg, type):
        return arg
    rv = type_lookup(arg)
    if rv is not None:
        return rv
    else:
        raise TypeError("{!r} does not resolve to a type")