summaryrefslogtreecommitdiff
path: root/grc/base
diff options
context:
space:
mode:
authorMatt Ettus2009-09-24 22:34:06 -0700
committerMatt Ettus2009-09-24 22:34:06 -0700
commit5c46578ba936de57e80594540804c964aa408f73 (patch)
treecf164f8e3d80b78971fb2987740b7d957ee1f306 /grc/base
parent35ada01aa8ae838d6d75bf063725218fa7e18f5f (diff)
parent16474a0adb44dc81a8338a9c4a9a6dcab6f6328f (diff)
downloadgnuradio-5c46578ba936de57e80594540804c964aa408f73.tar.gz
gnuradio-5c46578ba936de57e80594540804c964aa408f73.tar.bz2
gnuradio-5c46578ba936de57e80594540804c964aa408f73.zip
Merge commit 'origin' into new_eth
Conflicts: .gitignore
Diffstat (limited to 'grc/base')
-rw-r--r--grc/base/Block.py66
-rw-r--r--grc/base/Element.py68
-rw-r--r--grc/base/FlowGraph.py20
-rw-r--r--grc/base/Param.py134
-rw-r--r--grc/base/Platform.py5
-rw-r--r--grc/base/Port.py32
6 files changed, 121 insertions, 204 deletions
diff --git a/grc/base/Block.py b/grc/base/Block.py
index d5e104785..203e878e4 100644
--- a/grc/base/Block.py
+++ b/grc/base/Block.py
@@ -47,7 +47,9 @@ class TemplateArg(UserDict):
return self._param.get_evaluated()
def _get_keys(lst): return [elem.get_key() for elem in lst]
-def _get_elem(lst, key): return lst[_get_keys(lst).index(key)]
+def _get_elem(lst, key):
+ try: return lst[_get_keys(lst).index(key)]
+ except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
class Block(Element):
@@ -72,16 +74,16 @@ class Block(Element):
self._params = list()
#add the id param
self.get_params().append(self.get_parent().get_parent().Param(
- self,
- odict({
+ block=self,
+ n=odict({
'name': 'ID',
'key': 'id',
'type': 'id',
})
))
self.get_params().append(self.get_parent().get_parent().Param(
- self,
- odict({
+ block=self,
+ n=odict({
'name': 'Enabled',
'key': '_enabled',
'type': 'raw',
@@ -89,7 +91,7 @@ class Block(Element):
'hide': 'all',
})
))
- for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params):
+ for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params):
key = param.get_key()
#test against repeated keys
try: assert key not in self.get_param_keys()
@@ -98,7 +100,7 @@ class Block(Element):
self.get_params().append(param)
#create the source objects
self._sources = list()
- for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources):
+ for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources):
key = source.get_key()
#test against repeated keys
try: assert key not in self.get_source_keys()
@@ -107,21 +109,13 @@ class Block(Element):
self.get_sources().append(source)
#create the sink objects
self._sinks = list()
- for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), sinks):
+ for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks):
key = sink.get_key()
#test against repeated keys
try: assert key not in self.get_sink_keys()
except AssertionError: raise Exception, 'Key "%s" already exists in sinks'%key
#store the port
self.get_sinks().append(sink)
- #begin the testing
- self.test()
-
- def test(self):
- """
- Call test on all children.
- """
- map(lambda c: c.test(), self.get_params() + self.get_sinks() + self.get_sources())
def get_enabled(self):
"""
@@ -138,21 +132,6 @@ class Block(Element):
"""
self.get_param('_enabled').set_value(str(enabled))
- def validate(self):
- """
- Validate the block.
- All ports and params must be valid.
- All checks must evaluate to true.
- """
- Element.validate(self)
- for c in self.get_params() + self.get_ports() + self.get_connections():
- try:
- c.validate()
- assert c.is_valid()
- except AssertionError:
- for msg in c.get_error_messages():
- self.add_error_message('>>> %s:\n\t%s'%(c, msg))
-
def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
def get_id(self): return self.get_param('id').get_value()
@@ -162,6 +141,7 @@ class Block(Element):
def get_category(self): return self._category
def get_doc(self): return ''
def get_ports(self): return self.get_sources() + self.get_sinks()
+ def get_children(self): return self.get_ports() + self.get_params()
def get_block_wrapper_path(self): return self._block_wrapper_path
##############################################
@@ -253,12 +233,22 @@ class Block(Element):
"""
Import this block's params from nested data.
Any param keys that do not exist will be ignored.
+ Since params can be dynamically created based another param,
+ call rewrite, and repeat the load until the params stick.
+ This call to rewrite will also create any dynamic ports
+ that are needed for the connections creation phase.
@param n the nested data odict
"""
- params_n = n.findall('param')
- for param_n in params_n:
- key = param_n.find('key')
- value = param_n.find('value')
- #the key must exist in this block's params
- if key in self.get_param_keys():
- self.get_param(key).set_value(value)
+ get_hash = lambda: reduce(lambda x, y: x ^ y, [hash(param) for param in self.get_params()], 0)
+ my_hash = 0
+ while get_hash() != my_hash:
+ params_n = n.findall('param')
+ for param_n in params_n:
+ key = param_n.find('key')
+ value = param_n.find('value')
+ #the key must exist in this block's params
+ if key in self.get_param_keys():
+ self.get_param(key).set_value(value)
+ #store hash and call rewrite
+ my_hash = get_hash()
+ self.rewrite()
diff --git a/grc/base/Element.py b/grc/base/Element.py
index 16000c46c..a57090f3b 100644
--- a/grc/base/Element.py
+++ b/grc/base/Element.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -21,37 +21,59 @@ class Element(object):
def __init__(self, parent=None):
self._parent = parent
- self.flag()
-
- def test(self):
- """
- Test the element against failures.
- Overload this method in sub-classes.
- """
- pass
##################################################
# Element Validation API
##################################################
- def validate(self): self._error_messages = list()
- def is_valid(self): return not self.get_error_messages() or not self.get_enabled()
- def add_error_message(self, msg): self._error_messages.append(msg)
- def get_error_messages(self): return self._error_messages
+ def validate(self):
+ """
+ Validate this element and call validate on all children.
+ Call this base method before adding error messages in the subclass.
+ """
+ self._error_messages = list()
+ for child in self.get_children(): child.validate()
- def get_enabled(self): return True
+ def is_valid(self):
+ """
+ Is this element valid?
+ @return true when the element is enabled and has no error messages
+ """
+ return not self.get_error_messages() or not self.get_enabled()
- def get_parent(self): return self._parent
+ def add_error_message(self, msg):
+ """
+ Add an error message to the list of errors.
+ @param msg the error message string
+ """
+ self._error_messages.append(msg)
+
+ def get_error_messages(self):
+ """
+ Get the list of error messages from this element and all of its children.
+ Do not include the error messages from disabled children.
+ Cleverly indent the children error messages for printing purposes.
+ @return a list of error message strings
+ """
+ error_messages = list(self._error_messages) #make a copy
+ for child in filter(lambda c: c.get_enabled(), self.get_children()):
+ for msg in child.get_error_messages():
+ error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t")))
+ return error_messages
+
+ def rewrite(self):
+ """
+ Rewrite this element and call rewrite on all children.
+ Call this base method before rewriting the element.
+ """
+ for child in self.get_children(): child.rewrite()
+
+ def get_enabled(self): return True
##############################################
- ## Update flagging
+ ## Tree-like API
##############################################
- def is_flagged(self): return self._flag
- def flag(self):
- self._flag = True
- if self.get_parent(): self.get_parent().flag()
- def deflag(self):
- self._flag = False
- if self.get_parent(): self.get_parent().deflag()
+ def get_parent(self): return self._parent
+ def get_children(self): return list()
##############################################
## Type testing methods
diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py
index ea489e948..7c51ef42a 100644
--- a/grc/base/FlowGraph.py
+++ b/grc/base/FlowGraph.py
@@ -68,6 +68,7 @@ class FlowGraph(Element):
def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0]
def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements())
def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements())
+ def get_children(self): return self.get_elements()
def get_elements(self):
"""
Get a list of all the elements.
@@ -102,7 +103,6 @@ class FlowGraph(Element):
@param key the block key
@return the new block or None if not found
"""
- self.flag()
if key not in self.get_parent().get_block_keys(): return None
block = self.get_parent().get_new_block(self, key)
self.get_elements().append(block)
@@ -116,8 +116,7 @@ class FlowGraph(Element):
@throw Exception bad connection
@return the new connection
"""
- self.flag()
- connection = self.get_parent().Connection(self, porta, portb)
+ connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
self.get_elements().append(connection)
return connection
@@ -128,7 +127,6 @@ class FlowGraph(Element):
If the element is a block, remove its connections.
If the element is a connection, just remove the connection.
"""
- self.flag()
if element not in self.get_elements(): return
#found a port, set to parent signal block
if element.is_port():
@@ -147,18 +145,6 @@ class FlowGraph(Element):
"""
raise NotImplementedError
- def validate(self):
- """
- Validate the flow graph.
- All connections and blocks must be valid.
- """
- Element.validate(self)
- for c in self.get_elements():
- try:
- c.validate()
- assert c.is_valid()
- except AssertionError: self.add_error_message('Element "%s" is not valid.'%c)
-
##############################################
## Import/Export Methods
##############################################
@@ -198,7 +184,6 @@ class FlowGraph(Element):
#only load the block when the block key was valid
if block: block.import_data(block_n)
else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent()))
- self.validate() #validate all blocks before connections are made (in case of nports)
#build the connections
for connection_n in connections_n:
#try to make the connection
@@ -225,3 +210,4 @@ class FlowGraph(Element):
#build the connection
self.connect(source, sink)
except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key))
+ self.rewrite() #global rewrite
diff --git a/grc/base/Param.py b/grc/base/Param.py
index 93c1c52bd..e56eac36e 100644
--- a/grc/base/Param.py
+++ b/grc/base/Param.py
@@ -19,74 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from . import odict
from Element import Element
-import pygtk
-pygtk.require('2.0')
-import gtk
-class InputParam(gtk.HBox):
- """The base class for an input parameter inside the input parameters dialog."""
-
- def __init__(self, param, _handle_changed):
- gtk.HBox.__init__(self)
- self.param = param
- self._handle_changed = _handle_changed
- self.label = gtk.Label('') #no label, markup is added by set_markup
- self.label.set_size_request(150, -1)
- self.pack_start(self.label, False)
- self.set_markup = lambda m: self.label.set_markup(m)
- self.tp = None
- def set_color(self, color): pass
-
-class EntryParam(InputParam):
- """Provide an entry box for strings and numbers."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self.entry = input = gtk.Entry()
- input.set_text(self.param.get_value())
- input.connect('changed', self._handle_changed)
- self.pack_start(input, True)
- self.get_text = input.get_text
- #tool tip
- self.tp = gtk.Tooltips()
- self.tp.set_tip(self.entry, '')
- self.tp.enable()
- def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
-
-class EnumParam(InputParam):
- """Provide an entry box for Enum types with a drop down menu."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self._input = gtk.combo_box_new_text()
- for option in self.param.get_options(): self._input.append_text(option.get_name())
- self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
- self._input.connect('changed', self._handle_changed)
- self.pack_start(self._input, False)
- def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
-
-class EnumEntryParam(InputParam):
- """Provide an entry box and drop down menu for Raw Enum types."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self._input = gtk.combo_box_entry_new_text()
- for option in self.param.get_options(): self._input.append_text(option.get_name())
- try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
- except:
- self._input.set_active(-1)
- self._input.get_child().set_text(self.param.get_value())
- self._input.connect('changed', self._handle_changed)
- self._input.get_child().connect('changed', self._handle_changed)
- self.pack_start(self._input, False)
- def get_text(self):
- if self._input.get_active() == -1: return self._input.get_child().get_text()
- return self.param.get_option_keys()[self._input.get_active()]
- def set_color(self, color):
- if self._input.get_active() == -1: #custom entry, use color
- self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
- else: #from enum, make white background
- self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
+def _get_keys(lst): return [elem.get_key() for elem in lst]
+def _get_elem(lst, key):
+ try: return lst[_get_keys(lst).index(key)]
+ except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
class Option(Element):
@@ -123,15 +60,11 @@ class Option(Element):
class Param(Element):
- ##possible param types
- TYPES = ['enum', 'raw']
-
def __init__(self, block, n):
"""
Make a new param from nested data.
@param block the parent element
@param n the nested odict
- @return a new param
"""
#grab the data
self._name = n.find('name')
@@ -142,22 +75,22 @@ class Param(Element):
#build the param
Element.__init__(self, block)
#create the Option objects from the n data
- self._options = odict()
- for option in map(lambda o: Option(self, o), n.findall('option')):
+ self._options = list()
+ for option in map(lambda o: Option(param=self, n=o), n.findall('option')):
key = option.get_key()
#test against repeated keys
try: assert key not in self.get_option_keys()
except AssertionError: raise Exception, 'Key "%s" already exists in options'%key
#store the option
- self._options[key] = option
+ self.get_options().append(option)
#test the enum options
if self.is_enum():
#test against options with identical keys
- try: assert len(set(self.get_option_keys())) == len(self._options)
+ try: assert len(set(self.get_option_keys())) == len(self.get_options())
except AssertionError: raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys()
#test against inconsistent keys in options
- opt_keys = self._options.values()[0].get_opt_keys()
- for option in self._options.values():
+ opt_keys = self.get_options()[0].get_opt_keys()
+ for option in self.get_options():
try: assert set(opt_keys) == set(option.get_opt_keys())
except AssertionError: raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
#if a value is specified, it must be in the options keys
@@ -165,14 +98,6 @@ class Param(Element):
try: assert self.get_value() in self.get_option_keys()
except AssertionError: raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
else: self._value = value or ''
- #begin the testing
- self.test()
-
- def test(self):
- """
- call test on all children
- """
- map(lambda c: c.test(), self.get_options())
def validate(self):
"""
@@ -180,7 +105,7 @@ class Param(Element):
The value must be evaluated and type must a possible type.
"""
Element.validate(self)
- try: assert self.get_type() in self.TYPES
+ try: assert self.get_type() in self.get_types()
except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
def get_evaluated(self): raise NotImplementedError
@@ -192,12 +117,19 @@ class Param(Element):
"""
raise NotImplementedError
+ def get_types(self):
+ """
+ Get a list of all possible param types.
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
+
def get_color(self): return '#FFFFFF'
def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
def is_param(self): return True
def get_name(self): return self._name
def get_key(self): return self._key
- def get_hide(self): return self.get_parent().resolve_dependencies(self._hide)
+ def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
def get_value(self):
value = self._value
@@ -206,9 +138,7 @@ class Param(Element):
self.set_value(value)
return value
- def set_value(self, value):
- self.flag()
- self._value = str(value) #must be a string
+ def set_value(self, value): self._value = str(value) #must be a string
def get_type(self): return self.get_parent().resolve_dependencies(self._type)
def is_enum(self): return self._type == 'enum'
@@ -223,31 +153,19 @@ class Param(Element):
if self.is_enum(): return self.get_option(self.get_value()).get_name()
return self.get_value()
- def get_input_class(self):
- """
- Get the graphical gtk class to represent this parameter.
- An enum requires and combo parameter.
- A non-enum with options gets a combined entry/combo parameter.
- All others get a standard entry parameter.
- @return gtk input class
- """
- if self.is_enum(): return EnumParam
- if self.get_options(): return EnumEntryParam
- return EntryParam
-
##############################################
# Access Options
##############################################
- def get_option_keys(self): return self._options.keys()
- def get_option(self, key): return self._options[key]
- def get_options(self): return self._options.values()
+ def get_option_keys(self): return _get_keys(self.get_options())
+ def get_option(self, key): return _get_elem(self.get_options(), key)
+ def get_options(self): return self._options
##############################################
# Access Opts
##############################################
- def get_opt_keys(self): return self._options[self.get_value()].get_opt_keys()
- def get_opt(self, key): return self._options[self.get_value()].get_opt(key)
- def get_opts(self): return self._options[self.get_value()].get_opts()
+ def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys()
+ def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key)
+ def get_opts(self): return self.get_option(self.get_value()).get_opts()
##############################################
## Import/Export Methods
diff --git a/grc/base/Platform.py b/grc/base/Platform.py
index 02d6d2319..51a3b2f87 100644
--- a/grc/base/Platform.py
+++ b/grc/base/Platform.py
@@ -146,7 +146,7 @@ class Platform(_Element):
def is_platform(self): return True
- def get_new_flow_graph(self): return self.FlowGraph(self)
+ def get_new_flow_graph(self): return self.FlowGraph(platform=self)
def get_generator(self): return self._generator
@@ -171,6 +171,5 @@ class Platform(_Element):
FlowGraph = _FlowGraph
Connection = _Connection
Block = _Block
- Source = _Port
- Sink = _Port
+ Port = _Port
Param = _Param
diff --git a/grc/base/Port.py b/grc/base/Port.py
index f4e8e5e1f..494ea894f 100644
--- a/grc/base/Port.py
+++ b/grc/base/Port.py
@@ -21,25 +21,20 @@ from Element import Element
class Port(Element):
- ##possible port types
- TYPES = []
-
- def __init__(self, block, n):
+ def __init__(self, block, n, dir):
"""
Make a new port from nested data.
@param block the parent element
@param n the nested odict
- @return a new port
+ @param dir the direction source or sink
"""
- #grab the data
- name = n['name']
- key = n['key']
- type = n['type']
#build the port
Element.__init__(self, block)
- self._name = name
- self._key = key
- self._type = type
+ #grab the data
+ self._name = n['name']
+ self._key = n['key']
+ self._type = n['type']
+ self._dir = dir
def validate(self):
"""
@@ -47,7 +42,7 @@ class Port(Element):
The port must be non-empty and type must a possible type.
"""
Element.validate(self)
- try: assert self.get_type() in self.TYPES
+ try: assert self.get_type() in self.get_types()
except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
def __str__(self):
@@ -56,12 +51,19 @@ class Port(Element):
if self.is_sink():
return 'Sink - %s(%s)'%(self.get_name(), self.get_key())
+ def get_types(self):
+ """
+ Get a list of all possible port types.
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
+
def is_port(self): return True
def get_color(self): return '#FFFFFF'
def get_name(self): return self._name
def get_key(self): return self._key
- def is_sink(self): return self in self.get_parent().get_sinks()
- def is_source(self): return self in self.get_parent().get_sources()
+ def is_sink(self): return self._dir == 'sink'
+ def is_source(self): return self._dir == 'source'
def get_type(self): return self.get_parent().resolve_dependencies(self._type)
def get_connections(self):