summaryrefslogtreecommitdiff
path: root/grc/core/Port.py
diff options
context:
space:
mode:
Diffstat (limited to 'grc/core/Port.py')
-rw-r--r--grc/core/Port.py261
1 files changed, 119 insertions, 142 deletions
diff --git a/grc/core/Port.py b/grc/core/Port.py
index 8549656c9b..9ca443efa1 100644
--- a/grc/core/Port.py
+++ b/grc/core/Port.py
@@ -17,11 +17,13 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
+from __future__ import absolute_import
+
from itertools import chain
-from .Constants import DEFAULT_DOMAIN, GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN
-from .Element import Element
+from six.moves import filter
+from .Element import Element, lazy_property
from . import Constants
@@ -43,7 +45,7 @@ def _sources_from_virtual_sink_port(sink_port, _traversed=None):
"""
source_ports_per_virtual_connection = (
# there can be multiple ports per virtual connection
- _sources_from_virtual_source_port(c.get_source(), _traversed) # type: list
+ _sources_from_virtual_source_port(c.source_port, _traversed) # type: list
for c in sink_port.get_enabled_connections()
)
return list(chain(*source_ports_per_virtual_connection)) # concatenate generated lists of ports
@@ -59,8 +61,8 @@ def _sources_from_virtual_source_port(source_port, _traversed=None):
raise LoopError('Loop found when resolving port type')
_traversed.add(source_port)
- block = source_port.get_parent()
- flow_graph = block.get_parent()
+ block = source_port.parent_block
+ flow_graph = source_port.parent_flow_graph
if not block.is_virtual_source():
return [source_port] # nothing to resolve, we're done
@@ -70,11 +72,11 @@ def _sources_from_virtual_source_port(source_port, _traversed=None):
# currently the validation does not allow multiple virtual sinks and one virtual source
# but in the future it may...
connected_virtual_sink_blocks = (
- b for b in flow_graph.get_enabled_blocks()
+ b for b in flow_graph.iter_enabled_blocks()
if b.is_virtual_sink() and b.get_param('stream_id').get_value() == stream_id
)
source_ports_per_virtual_connection = (
- _sources_from_virtual_sink_port(b.get_sinks()[0], _traversed) # type: list
+ _sources_from_virtual_sink_port(b.sinks[0], _traversed) # type: list
for b in connected_virtual_sink_blocks
)
return list(chain(*source_ports_per_virtual_connection)) # concatenate generated lists of ports
@@ -94,7 +96,7 @@ def _sinks_from_virtual_source_port(source_port, _traversed=None):
"""
sink_ports_per_virtual_connection = (
# there can be multiple ports per virtual connection
- _sinks_from_virtual_sink_port(c.get_sink(), _traversed) # type: list
+ _sinks_from_virtual_sink_port(c.sink_port, _traversed) # type: list
for c in source_port.get_enabled_connections()
)
return list(chain(*sink_ports_per_virtual_connection)) # concatenate generated lists of ports
@@ -110,8 +112,8 @@ def _sinks_from_virtual_sink_port(sink_port, _traversed=None):
raise LoopError('Loop found when resolving port type')
_traversed.add(sink_port)
- block = sink_port.get_parent()
- flow_graph = block.get_parent()
+ block = sink_port.parent_block
+ flow_graph = sink_port.parent_flow_graph
if not block.is_virtual_sink():
return [sink_port]
@@ -119,11 +121,11 @@ def _sinks_from_virtual_sink_port(sink_port, _traversed=None):
stream_id = block.get_param('stream_id').get_value()
connected_virtual_source_blocks = (
- b for b in flow_graph.get_enabled_blocks()
+ b for b in flow_graph.iter_enabled_blocks()
if b.is_virtual_source() and b.get_param('stream_id').get_value() == stream_id
)
sink_ports_per_virtual_connection = (
- _sinks_from_virtual_source_port(b.get_sources()[0], _traversed) # type: list
+ _sinks_from_virtual_source_port(b.sources[0], _traversed) # type: list
for b in connected_virtual_source_blocks
)
return list(chain(*sink_ports_per_virtual_connection)) # concatenate generated lists of ports
@@ -132,8 +134,9 @@ def _sinks_from_virtual_sink_port(sink_port, _traversed=None):
class Port(Element):
is_port = True
+ is_clone = False
- def __init__(self, block, n, dir):
+ def __init__(self, parent, direction, **n):
"""
Make a new port from nested data.
@@ -144,50 +147,44 @@ class Port(Element):
"""
self._n = n
if n['type'] == 'message':
- n['domain'] = GR_MESSAGE_DOMAIN
+ n['domain'] = Constants.GR_MESSAGE_DOMAIN
+
if 'domain' not in n:
- n['domain'] = DEFAULT_DOMAIN
- elif n['domain'] == GR_MESSAGE_DOMAIN:
+ n['domain'] = Constants.DEFAULT_DOMAIN
+ elif n['domain'] == Constants.GR_MESSAGE_DOMAIN:
n['key'] = n['name']
n['type'] = 'message' # For port color
- if not n.find('key'):
- n['key'] = str(next(block.port_counters[dir == 'source']))
# Build the port
- Element.__init__(self, block)
+ Element.__init__(self, parent)
# Grab the data
- self._name = n['name']
- self._key = n['key']
- self._type = n['type'] or ''
- self._domain = n['domain']
- self._hide = n.find('hide') or ''
- self._dir = dir
+ self.name = n['name']
+ self.key = n['key']
+ self.domain = n.get('domain')
+ self._type = n.get('type', '')
+ self.inherit_type = not self._type
+ self._hide = n.get('hide', '')
+ self._dir = direction
self._hide_evaluated = False # Updated on rewrite()
- self._nports = n.find('nports') or ''
- self._vlen = n.find('vlen') or ''
- self._optional = n.find('optional') or ''
+ self._nports = n.get('nports', '')
+ self._vlen = n.get('vlen', '')
+ self._optional = bool(n.get('optional'))
self._optional_evaluated = False # Updated on rewrite()
- self._clones = [] # References to cloned ports (for nports > 1)
+ self.clones = [] # References to cloned ports (for nports > 1)
def __str__(self):
if self.is_source:
- return 'Source - {}({})'.format(self.get_name(), self.get_key())
+ return 'Source - {}({})'.format(self.name, self.key)
if self.is_sink:
- return 'Sink - {}({})'.format(self.get_name(), self.get_key())
-
- def get_types(self):
- return Constants.TYPE_TO_SIZEOF.keys()
-
- def is_type_empty(self):
- return not self._n['type'] or not self.get_parent().resolve_dependencies(self._n['type'])
+ return 'Sink - {}({})'.format(self.name, self.key)
def validate(self):
- if self.get_type() not in self.get_types():
+ Element.validate(self)
+ if self.get_type() not in Constants.TYPE_TO_SIZEOF.keys():
self.add_error_message('Type "{}" is not a possible type.'.format(self.get_type()))
- platform = self.get_parent().get_parent().get_parent()
- if self.get_domain() not in platform.domains:
- self.add_error_message('Domain key "{}" is not registered.'.format(self.get_domain()))
+ if self.domain not in self.parent_platform.domains:
+ self.add_error_message('Domain key "{}" is not registered.'.format(self.domain))
if not self.get_enabled_connections() and not self.get_optional():
self.add_error_message('Port is not connected.')
@@ -196,22 +193,22 @@ class Port(Element):
Handle the port cloning for virtual blocks.
"""
del self._error_messages[:]
- if self.is_type_empty():
+ if self.inherit_type:
self.resolve_empty_type()
- hide = self.get_parent().resolve_dependencies(self._hide).strip().lower()
+ hide = self.parent_block.resolve_dependencies(self._hide).strip().lower()
self._hide_evaluated = False if hide in ('false', 'off', '0') else bool(hide)
- optional = self.get_parent().resolve_dependencies(self._optional).strip().lower()
+ optional = self.parent_block.resolve_dependencies(self._optional).strip().lower()
self._optional_evaluated = False if optional in ('false', 'off', '0') else bool(optional)
# Update domain if was deduced from (dynamic) port type
type_ = self.get_type()
- if self._domain == GR_STREAM_DOMAIN and type_ == "message":
- self._domain = GR_MESSAGE_DOMAIN
- self._key = self._name
- if self._domain == GR_MESSAGE_DOMAIN and type_ != "message":
- self._domain = GR_STREAM_DOMAIN
- self._key = '0' # Is rectified in rewrite()
+ if self.domain == Constants.GR_STREAM_DOMAIN and type_ == "message":
+ self.domain = Constants.GR_MESSAGE_DOMAIN
+ self.key = self.name
+ if self.domain == Constants.GR_MESSAGE_DOMAIN and type_ != "message":
+ self.domain = Constants.GR_STREAM_DOMAIN
+ self.key = '0' # Is rectified in rewrite()
def resolve_virtual_source(self):
"""Only used by Generator after validation is passed"""
@@ -220,7 +217,7 @@ class Port(Element):
def resolve_empty_type(self):
def find_port(finder):
try:
- return next((p for p in finder(self) if not p.is_type_empty()), None)
+ return next((p for p in finder(self) if not p.inherit_type), None)
except LoopError as error:
self.add_error_message(str(error))
except (StopIteration, Exception) as error:
@@ -242,9 +239,9 @@ class Port(Element):
Returns:
the vector length or 1
"""
- vlen = self.get_parent().resolve_dependencies(self._vlen)
+ vlen = self.parent_block.resolve_dependencies(self._vlen)
try:
- return int(self.get_parent().get_parent().evaluate(vlen))
+ return max(1, int(self.parent_flowgraph.evaluate(vlen)))
except:
return 1
@@ -258,52 +255,17 @@ class Port(Element):
the number of ports or 1
"""
if self._nports == '':
- return ''
+ return 1
- nports = self.get_parent().resolve_dependencies(self._nports)
+ nports = self.parent_block.resolve_dependencies(self._nports)
try:
- return max(1, int(self.get_parent().get_parent().evaluate(nports)))
+ return max(1, int(self.parent_flowgraph.evaluate(nports)))
except:
return 1
def get_optional(self):
return self._optional_evaluated
- def get_color(self):
- """
- Get the color that represents this port's type.
- Codes differ for ports where the vec length is 1 or greater than 1.
-
- Returns:
- a hex color code.
- """
- try:
- color = Constants.TYPE_TO_COLOR[self.get_type()]
- vlen = self.get_vlen()
- if vlen == 1:
- return color
- color_val = int(color[1:], 16)
- r = (color_val >> 16) & 0xff
- g = (color_val >> 8) & 0xff
- b = (color_val >> 0) & 0xff
- dark = (0, 0, 30, 50, 70)[min(4, vlen)]
- r = max(r-dark, 0)
- g = max(g-dark, 0)
- b = max(b-dark, 0)
- # TODO: Change this to .format()
- return '#%.2x%.2x%.2x' % (r, g, b)
- except:
- return '#FFFFFF'
-
- def get_clones(self):
- """
- Get the clones of this master port (nports > 1)
-
- Returns:
- a list of ports
- """
- return self._clones
-
def add_clone(self):
"""
Create a clone of this (master) port and store a reference in self._clones.
@@ -315,24 +277,23 @@ class Port(Element):
the cloned port
"""
# Add index to master port name if there are no clones yet
- if not self._clones:
- self._name = self._n['name'] + '0'
+ if not self.clones:
+ self.name = self._n['name'] + '0'
# Also update key for none stream ports
- if not self._key.isdigit():
- self._key = self._name
-
- # Prepare a copy of the odict for the clone
- n = self._n.copy()
- # Remove nports from the key so the copy cannot be a duplicator
- if 'nports' in n:
- n.pop('nports')
- n['name'] = self._n['name'] + str(len(self._clones) + 1)
+ if not self.key.isdigit():
+ self.key = self.name
+
+ name = self._n['name'] + str(len(self.clones) + 1)
# Dummy value 99999 will be fixed later
- n['key'] = '99999' if self._key.isdigit() else n['name']
+ key = '99999' if self.key.isdigit() else name
# Clone
- port = self.__class__(self.get_parent(), n, self._dir)
- self._clones.append(port)
+ port_factory = self.parent_platform.get_new_port
+ port = port_factory(self.parent, direction=self._dir,
+ name=name, key=key,
+ master=self, cls_key='clone')
+
+ self.clones.append(port)
return port
def remove_clone(self, port):
@@ -340,37 +301,24 @@ class Port(Element):
Remove a cloned port (from the list of clones only)
Remove the index 0 of the master port name (and key9 if there are no more clones left
"""
- self._clones.remove(port)
+ self.clones.remove(port)
# Remove index from master port name if there are no more clones
- if not self._clones:
- self._name = self._n['name']
+ if not self.clones:
+ self.name = self._n['name']
# Also update key for none stream ports
- if not self._key.isdigit():
- self._key = self._name
-
- def get_name(self):
- number = ''
- if self.get_type() == 'bus':
- busses = filter(lambda a: a._dir == self._dir, self.get_parent().get_ports_gui())
- number = str(busses.index(self)) + '#' + str(len(self.get_associated_ports()))
- return self._name + number
-
- def get_key(self):
- return self._key
+ if not self.key.isdigit():
+ self.key = self.name
- @property
+ @lazy_property
def is_sink(self):
return self._dir == 'sink'
- @property
+ @lazy_property
def is_source(self):
return self._dir == 'source'
def get_type(self):
- return self.get_parent().resolve_dependencies(self._type)
-
- def get_domain(self):
- return self._domain
+ return self.parent_block.resolve_dependencies(self._type)
def get_hide(self):
return self._hide_evaluated
@@ -382,8 +330,8 @@ class Port(Element):
Returns:
a list of connection objects
"""
- connections = self.get_parent().get_parent().connections
- connections = filter(lambda c: c.get_source() is self or c.get_sink() is self, connections)
+ connections = self.parent_flowgraph.connections
+ connections = [c for c in connections if c.source_port is self or c.sink_port is self]
return connections
def get_enabled_connections(self):
@@ -393,22 +341,51 @@ class Port(Element):
Returns:
a list of connection objects
"""
- return filter(lambda c: c.get_enabled(), self.get_connections())
+ return [c for c in self.get_connections() if c.enabled]
def get_associated_ports(self):
if not self.get_type() == 'bus':
return [self]
+
+ block = self.parent_block
+ if self.is_source:
+ block_ports = block.sources
+ bus_structure = block.current_bus_structure['source']
else:
- if self.is_source:
- get_ports = self.get_parent().get_sources
- bus_structure = self.get_parent().current_bus_structure['source']
- else:
- get_ports = self.get_parent().get_sinks
- bus_structure = self.get_parent().current_bus_structure['sink']
-
- ports = [i for i in get_ports() if not i.get_type() == 'bus']
- if bus_structure:
- busses = [i for i in get_ports() if i.get_type() == 'bus']
- bus_index = busses.index(self)
- ports = filter(lambda a: ports.index(a) in bus_structure[bus_index], ports)
- return ports
+ block_ports = block.sinks
+ bus_structure = block.current_bus_structure['sink']
+
+ ports = [i for i in block_ports if not i.get_type() == 'bus']
+ if bus_structure:
+ bus_index = [i for i in block_ports if i.get_type() == 'bus'].index(self)
+ ports = [p for i, p in enumerate(ports) if i in bus_structure[bus_index]]
+ return ports
+
+
+class PortClone(Port):
+
+ is_clone = True
+
+ def __init__(self, parent, direction, master, name, key):
+ """
+ Make a new port from nested data.
+
+ Args:
+ block: the parent element
+ n: the nested odict
+ dir: the direction
+ """
+ Element.__init__(self, parent)
+ self.master = master
+ self.name = name
+ self._key = key
+ self._nports = '1'
+
+ def __getattr__(self, item):
+ return getattr(self.master, item)
+
+ def add_clone(self):
+ raise NotImplementedError()
+
+ def remove_clone(self, port):
+ raise NotImplementedError()