Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENH] Input/output signal replacement declarations #1810

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
2 changes: 1 addition & 1 deletion Orange/canvas/registry/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
log = logging.getLogger(__name__)

# Registry hex version
VERSION_HEX = 0x000102
VERSION_HEX = 0x000103


class WidgetRegistry(object):
Expand Down
12 changes: 8 additions & 4 deletions Orange/canvas/registry/description.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ class InputSignal(object):
A unique id of the input signal.
doc : str, optional
A docstring documenting the channel.
replaces : List[str]
A list of names this input replaces.
"""
def __init__(self, name, type, handler, flags=Single + NonDefault,
id=None, doc=None):
id=None, doc=None, replaces=[]):
self.name = name
self.type = type
self.handler = handler
self.id = id
self.doc = doc
self.replaces = list(replaces)

if isinstance(flags, str):
# flags are stored as strings
Expand Down Expand Up @@ -130,14 +132,16 @@ class OutputSignal(object):
A unique id of the output signal.
doc : str, optional
A docstring documenting the channel.
replaces : List[str]
A list of names this output replaces.
"""
def __init__(self, name, type, flags=Single + NonDefault,
id=None, doc=None):
id=None, doc=None, replaces=[]):
self.name = name
self.type = type
self.id = id
self.doc = doc
self.replaces = list(replaces)

if isinstance(flags, str):
# flags are stored as strings
Expand Down
41 changes: 38 additions & 3 deletions Orange/canvas/scheme/readwrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from .errors import IncompatibleChannelTypeError

from ..registry import global_registry
from ..registry import WidgetDescription, InputSignal, OutputSignal

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -607,12 +608,26 @@ def resolve_1_0(scheme_desc, registry):

def resolve_replaced(scheme_desc, registry):
widgets = registry.widgets()
nodes_by_id = {} # type: Dict[str, _node]
replacements = {}
for desc in widgets:
replacements_channels = {} # type: Dict[str, Tuple[dict, dict]]
# collect all the replacement mappings
for desc in widgets: # type: WidgetDescription
if desc.replaces:
for repl_qname in desc.replaces:
replacements[repl_qname] = desc.qualified_name

input_repl = {}
for idesc in desc.inputs or []: # type: InputSignal
for repl_qname in idesc.replaces or []: # type: str
input_repl[repl_qname] = idesc.name
output_repl = {}
for odesc in desc.outputs: # type: OutputSignal
for repl_qname in odesc.replaces or []: # type: str
output_repl[repl_qname] = odesc.name
replacements_channels[desc.qualified_name] = (input_repl, output_repl)

# replace the nodes
nodes = scheme_desc.nodes
for i, node in list(enumerate(nodes)):
if not registry.has_widget(node.qualified_name) and \
Expand All @@ -621,8 +636,28 @@ def resolve_replaced(scheme_desc, registry):
desc = registry.widget(qname)
nodes[i] = node._replace(qualified_name=desc.qualified_name,
project_name=desc.project_name)

return scheme_desc._replace(nodes=nodes)
nodes_by_id[node.id] = nodes[i]

# replace links
links = scheme_desc.links
for i, link in list(enumerate(links)): # type: _link
nsource = nodes_by_id[link.source_node_id]
nsink = nodes_by_id[link.sink_node_id]

_, source_rep = replacements_channels.get(
nsource.qualified_name, ({}, {}))
sink_rep, _ = replacements_channels.get(
nsink.qualified_name, ({}, {}))

if link.source_channel in source_rep:
link = link._replace(
source_channel=source_rep[link.source_channel])
if link.sink_channel in sink_rep:
link = link._replace(
sink_channel=sink_rep[link.sink_channel])
links[i] = link

return scheme_desc._replace(nodes=nodes, links=links)


def scheme_load(scheme, stream, registry=None, error_handler=None):
Expand Down
18 changes: 15 additions & 3 deletions Orange/widgets/visualize/owtreeviewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,21 @@ class OWTreeGraph(OWTreeViewer2D):
name = "Tree Viewer"
icon = "icons/TreeViewer.svg"
priority = 35
inputs = [("Tree", TreeModel, "ctree")]
outputs = [("Selected Data", Table, widget.Default),
(ANNOTATED_DATA_SIGNAL_NAME, Table)]
inputs = [
widget.InputSignal(
"Tree", TreeModel, "ctree",
# Had different input names before merging from
# Classification/Regression tree variants
replaces=["Classification Tree", "Regression Tree"])
]
outputs = [
widget.OutputSignal(
"Selected Data", Table, widget.Default, id="selected-data",
),
widget.OutputSignal(
ANNOTATED_DATA_SIGNAL_NAME, Table, id="annotated-data")
]


settingsHandler = ClassValuesContextHandler()
target_class_index = ContextSetting(0)
Expand Down