diff options
-rw-r--r-- | grc/model/Block.py | 329 | ||||
-rw-r--r-- | grc/model/Connection.py | 53 | ||||
-rw-r--r-- | grc/model/Constants.py | 38 | ||||
-rw-r--r-- | grc/model/Element.py | 10 | ||||
-rw-r--r-- | grc/model/FlowGraph.py | 153 | ||||
-rw-r--r-- | grc/model/Generator.py | 55 | ||||
-rw-r--r-- | grc/model/Param.py | 487 | ||||
-rw-r--r-- | grc/model/ParseXML.py | 19 | ||||
-rw-r--r-- | grc/model/Platform.py | 149 | ||||
-rw-r--r-- | grc/model/Port.py | 207 | ||||
-rw-r--r-- | grc/model/expr_utils.py | 57 | ||||
-rw-r--r-- | grc/model/extract_docs.py | 45 | ||||
-rw-r--r-- | grc/model/odict.py | 18 |
13 files changed, 963 insertions, 657 deletions
diff --git a/grc/model/Block.py b/grc/model/Block.py index 9cd740c1f0..ae3169c44a 100644 --- a/grc/model/Block.py +++ b/grc/model/Block.py @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import collections import itertools +from Cheetah.Template import Template from UserDict import UserDict from . Constants import ( @@ -33,7 +34,6 @@ from . import epy_block_io from . odict import odict from . FlowGraph import _variable_matcher from . Element import Element -from Cheetah.Template import Template class TemplateArg(UserDict): @@ -63,8 +63,10 @@ def _get_keys(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)) + try: + return lst[_get_keys(lst).index(key)] + except ValueError: + raise ValueError('Key "{}" not found in {}.'.format(key, _get_keys(lst))) class Block(Element): @@ -94,7 +96,7 @@ class Block(Element): # Build the block Element.__init__(self, flow_graph) - #grab the data + # Grab the data params = n.findall('param') sources = n.findall('source') sinks = n.findall('sink') @@ -111,13 +113,14 @@ class Block(Element): self._bussify_source = n.find('bus_source') self._var_value = n.find('var_value') or '$value' - # get list of param tabs + # Get list of param tabs n_tabs = n.find('param_tab_order') or None self._param_tab_labels = n_tabs.findall('tab') if n_tabs is not None else [DEFAULT_PARAM_TAB] - #create the param objects + # Create the param objects self._params = list() - #add the id param + + # Add the id param self.get_params().append(self.get_parent().get_parent().Param( block=self, n=odict({ @@ -138,32 +141,32 @@ class Block(Element): )) for param in itertools.imap(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params): key = param.get_key() - #test against repeated keys + # Test against repeated keys if key in self.get_param_keys(): - raise Exception, 'Key "%s" already exists in params'%key - #store the param + raise Exception('Key "{}" already exists in params'.format(key)) + # Store the param self.get_params().append(param) - #create the source objects + # Create the source objects self._sources = list() 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 + # Test against repeated keys if key in self.get_source_keys(): - raise Exception, 'Key "%s" already exists in sources'%key - #store the port + raise Exception('Key "{}" already exists in sources'.format(key)) + # Store the port self.get_sources().append(source) self.back_ofthe_bus(self.get_sources()) - #create the sink objects + # Create the sink objects self._sinks = list() 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 + # Test against repeated keys if key in self.get_sink_keys(): - raise Exception, 'Key "%s" already exists in sinks'%key - #store the port + raise Exception('Key "{}" already exists in sinks'.format(key)) + # Store the port self.get_sinks().append(sink) self.back_ofthe_bus(self.get_sinks()) - self.current_bus_structure = {'source':'','sink':''}; + self.current_bus_structure = {'source': '', 'sink': ''} # Virtual source/sink and pad source/sink blocks are # indistinguishable from normal GR blocks. Make explicit @@ -185,7 +188,7 @@ class Block(Element): 'type': 'string', 'hide': 'part', 'tab': ADVANCED_PARAM_TAB - }) + }) )) if (len(sources) or len(sinks)) and not is_virtual_or_pad: @@ -231,24 +234,25 @@ class Block(Element): }) )) - self._epy_source_hash = -1 # for epy blocks self._epy_reload_error = None def get_bus_structure(self, direction): if direction == 'source': - bus_structure = self._bus_structure_source; + bus_structure = self._bus_structure_source else: - bus_structure = self._bus_structure_sink; + bus_structure = self._bus_structure_sink - bus_structure = self.resolve_dependencies(bus_structure); + bus_structure = self.resolve_dependencies(bus_structure) + + if not bus_structure: + return '' # TODO: Don't like empty strings. should change this to None eventually - if not bus_structure: return '' try: clean_bus_structure = self.get_parent().evaluate(bus_structure) return clean_bus_structure - - except: return '' + except: + return '' def validate(self): """ @@ -257,21 +261,23 @@ class Block(Element): Evaluate the checks: each check must evaluate to True. """ Element.validate(self) - #evaluate the checks + # Evaluate the checks for check in self._checks: check_res = self.resolve_dependencies(check) try: if not self.get_parent().evaluate(check_res): - self.add_error_message('Check "%s" failed.'%check) - except: self.add_error_message('Check "%s" did not evaluate.'%check) - # for variables check the value (only if var_value is used + self.add_error_message('Check "{}" failed.'.format(check)) + except: + self.add_error_message('Check "{}" did not evaluate.'.format(check)) + + # For variables check the value (only if var_value is used if _variable_matcher.match(self.get_key()) and self._var_value != '$value': value = self._var_value try: value = self.get_var_value() self.get_parent().evaluate(value) except Exception as err: - self.add_error_message('Value "%s" cannot be evaluated:\n%s' % (value, err)) + self.add_error_message('Value "{}" cannot be evaluated:\n{}'.format(value, err)) # check if this is a GUI block and matches the selected generate option current_generate_option = self.get_parent().get_option('generate_options') @@ -282,8 +288,8 @@ class Block(Element): self.get_name().upper().startswith(label) ) if block_requires_mode and current_generate_option not in valid_options: - self.add_error_message("Can't generate this block in mode " + - repr(current_generate_option)) + self.add_error_message("Can't generate this block in mode: {} ".format( + repr(current_generate_option))) check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',)) check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui')) @@ -297,7 +303,7 @@ class Block(Element): # Check and run any custom rewrite function for this block getattr(self, 'rewrite_' + self._key, lambda: None)() - # adjust nports, disconnect hidden ports + # Adjust nports, disconnect hidden ports for ports in (self.get_sources(), self.get_sinks()): for i, master_port in enumerate(ports): nports = master_port.get_nports() or 1 @@ -305,22 +311,22 @@ class Block(Element): if master_port.get_hide(): for connection in master_port.get_connections(): self.get_parent().remove_element(connection) - if not nports and num_ports == 1: # not a master port and no left-over clones + if not nports and num_ports == 1: # Not a master port and no left-over clones continue - # remove excess cloned ports + # Remove excess cloned ports for port in master_port.get_clones()[nports-1:]: - # remove excess connections + # Remove excess connections for connection in port.get_connections(): self.get_parent().remove_element(connection) master_port.remove_clone(port) ports.remove(port) - # add more cloned ports + # Add more cloned ports for j in range(num_ports, nports): port = master_port.add_clone() ports.insert(ports.index(master_port) + j, port) self.back_ofthe_bus(ports) - # renumber non-message/-msg ports + # Renumber non-message/message ports domain_specific_port_index = collections.defaultdict(int) for port in filter(lambda p: p.get_key().isdigit(), ports): domain = port.get_domain() @@ -338,19 +344,21 @@ class Block(Element): true for change """ changed = False - #concat the nports string from the private nports settings of all ports + # Concat the nports string from the private nports settings of all ports nports_str = ' '.join([port._nports for port in self.get_ports()]) - #modify all params whose keys appear in the nports string + # Modify all params whose keys appear in the nports string for param in self.get_params(): - if param.is_enum() or param.get_key() not in nports_str: continue - #try to increment the port controller by direction + if param.is_enum() or param.get_key() not in nports_str: + continue + # Try to increment the port controller by direction try: value = param.get_evaluated() value = value + direction if 0 < value: param.set_value(value) changed = True - except: pass + except: + pass return changed def get_doc(self): @@ -395,8 +403,9 @@ class Block(Element): """ def make_callback(callback): callback = self.resolve_dependencies(callback) - if 'self.' in callback: return callback - return 'self.%s.%s'%(self.get_id(), callback) + if 'self.' in callback: + return callback + return 'self.{}.{}'.format(self.get_id(), callback) return map(make_callback, self._callbacks) def is_virtual_sink(self): @@ -425,12 +434,12 @@ class Block(Element): except Exception as e: self._epy_reload_error = ValueError(str(e)) - try: # load last working block io + try: # Load last working block io blk_io = epy_block_io.BlockIO(*eval(param_blk.get_value())) except: return else: - self._epy_reload_error = None # clear previous errors + self._epy_reload_error = None # Clear previous errors param_blk.set_value(repr(tuple(blk_io))) # print "Rewriting embedded python block {!r}".format(self.get_id()) @@ -493,7 +502,6 @@ class Block(Element): update_ports('out', self.get_sources(), blk_io.sources, 'source') self.rewrite() - def back_ofthe_bus(self, portlist): portlist.sort(key=lambda p: p._type == 'bus') @@ -512,8 +520,10 @@ class Block(Element): BYPASSED - 1 DISABLED - 2 """ - try: return int(eval(self.get_param('_enabled').get_value())) - except: return BLOCK_ENABLED + try: + return int(eval(self.get_param('_enabled').get_value())) + except: + return BLOCK_ENABLED def set_state(self, state): """ @@ -585,55 +595,105 @@ class Block(Element): return False return True - 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() - def is_block(self): return True - def get_name(self): return self._name - def get_key(self): return self._key - def get_category(self): return self._category - def set_category(self, cat): self._category = cat - #def get_doc(self): return '' - def get_ports(self): return self.get_sources() + self.get_sinks() - def get_ports_gui(self): return self.filter_bus_port(self.get_sources()) + self.filter_bus_port(self.get_sinks()); - def get_children(self): return self.get_ports() + self.get_params() - def get_children_gui(self): return self.get_ports_gui() + self.get_params() - def get_block_wrapper_path(self): return self._block_wrapper_path - def get_comment(self): return self.get_param('comment').get_value() - - def get_flags(self): return self._flags - def throtteling(self): return BLOCK_FLAG_THROTTLE in self._flags - def bypass_disabled(self): return BLOCK_FLAG_DISABLE_BYPASS in self._flags + def __str__(self): + return 'Block - {} - {}({})'.format(self.get_id(), self.get_name(), self.get_key()) + + def get_id(self): + return self.get_param('id').get_value() + + def is_block(self): + return True + + def get_name(self): + return self._name + + def get_key(self): + return self._key + + def get_category(self): + return self._category + + def set_category(self, cat): + self._category = cat + + def get_ports(self): + return self.get_sources() + self.get_sinks() + + def get_ports_gui(self): + return self.filter_bus_port(self.get_sources()) + self.filter_bus_port(self.get_sinks()) + + def get_children(self): + return self.get_ports() + self.get_params() + + def get_children_gui(self): + return self.get_ports_gui() + self.get_params() + + def get_block_wrapper_path(self): + return self._block_wrapper_path + + def get_comment(self): + return self.get_param('comment').get_value() + + def get_flags(self): + return self._flags + + def throtteling(self): + return BLOCK_FLAG_THROTTLE in self._flags + + def bypass_disabled(self): + return BLOCK_FLAG_DISABLE_BYPASS in self._flags ############################################## # Access Params ############################################## - def get_param_tab_labels(self): return self._param_tab_labels - def get_param_keys(self): return _get_keys(self._params) - def get_param(self, key): return _get_elem(self._params, key) - def get_params(self): return self._params + def get_param_tab_labels(self): + return self._param_tab_labels + + def get_param_keys(self): + return _get_keys(self._params) + + def get_param(self, key): + return _get_elem(self._params, key) + + def get_params(self): + return self._params + def has_param(self, key): try: - _get_elem(self._params, key); - return True; + _get_elem(self._params, key) + return True except: - return False; + return False ############################################## # Access Sinks ############################################## - def get_sink_keys(self): return _get_keys(self._sinks) - def get_sink(self, key): return _get_elem(self._sinks, key) - def get_sinks(self): return self._sinks - def get_sinks_gui(self): return self.filter_bus_port(self.get_sinks()) + def get_sink_keys(self): + return _get_keys(self._sinks) + + def get_sink(self, key): + return _get_elem(self._sinks, key) + + def get_sinks(self): + return self._sinks + + def get_sinks_gui(self): + return self.filter_bus_port(self.get_sinks()) ############################################## # Access Sources ############################################## - def get_source_keys(self): return _get_keys(self._sources) - def get_source(self, key): return _get_elem(self._sources, key) - def get_sources(self): return self._sources - def get_sources_gui(self): return self.filter_bus_port(self.get_sources()); + def get_source_keys(self): + return _get_keys(self._sources) + + def get_source(self, key): + return _get_elem(self._sources, key) + + def get_sources(self): + return self._sources + + def get_sources_gui(self): + return self.filter_bus_port(self.get_sources()) def get_connections(self): return sum([port.get_connections() for port in self.get_ports()], []) @@ -649,12 +709,13 @@ class Block(Element): the resolved value """ tmpl = str(tmpl) - if '$' not in tmpl: return tmpl + if '$' not in tmpl: + return tmpl n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params()) try: return str(Template(tmpl, n)) except Exception as err: - return "Template error: %s\n %s" % (tmpl, err) + return "Template error: {}\n {}".format(tmpl, err) ############################################## # Controller Modify @@ -673,19 +734,21 @@ class Block(Element): type_param = None for param in filter(lambda p: p.is_enum(), self.get_params()): children = self.get_ports() + self.get_params() - #priority to the type controller + # Priority to the type controller if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param - #use param if type param is unset - if not type_param: type_param = param + # Use param if type param is unset + if not type_param: + type_param = param if type_param: - #try to increment the enum by direction + # Try to increment the enum by direction try: keys = type_param.get_option_keys() old_index = keys.index(type_param.get_value()) - new_index = (old_index + direction + len(keys))%len(keys) + new_index = (old_index + direction + len(keys)) % len(keys) type_param.set_value(keys[new_index]) changed = True - except: pass + except: + pass return changed def form_bus_structure(self, direc): @@ -700,10 +763,8 @@ class Block(Element): struct = [range(len(get_p()))] if True in map(lambda a: isinstance(a.get_nports(), int), get_p()): - - - structlet = []; - last = 0; + structlet = [] + last = 0 for j in [i.get_nports() for i in get_p() if isinstance(i.get_nports(), int)]: structlet.extend(map(lambda a: a+last, range(j))) last = structlet[-1] + 1 @@ -717,42 +778,36 @@ class Block(Element): def bussify(self, n, direc): if direc == 'source': - get_p = self.get_sources; - get_p_gui = self.get_sources_gui; - bus_structure = self.get_bus_structure('source'); + get_p = self.get_sources + get_p_gui = self.get_sources_gui + bus_structure = self.get_bus_structure('source') else: - get_p = self.get_sinks; + get_p = self.get_sinks get_p_gui = self.get_sinks_gui - bus_structure = self.get_bus_structure('sink'); - + bus_structure = self.get_bus_structure('sink') for elt in get_p(): for connect in elt.get_connections(): - self.get_parent().remove_element(connect); - + self.get_parent().remove_element(connect) - - - - - if (not 'bus' in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0: - - struct = self.form_bus_structure(direc); - self.current_bus_structure[direc] = struct; + if ('bus' not in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0: + struct = self.form_bus_structure(direc) + self.current_bus_structure[direc] = struct if get_p()[0].get_nports(): - n['nports'] = str(1); + n['nports'] = str(1) for i in range(len(struct)): - n['key'] = str(len(get_p())); - n = odict(n); - port = self.get_parent().get_parent().Port(block=self, n=n, dir=direc); - get_p().append(port); + n['key'] = str(len(get_p())) + n = odict(n) + port = self.get_parent().get_parent().Port(block=self, n=n, dir=direc) + get_p().append(port) elif 'bus' in map(lambda a: a.get_type(), get_p()): for elt in get_p_gui(): - get_p().remove(elt); + get_p().remove(elt) self.current_bus_structure[direc] = '' + ############################################## - ## Import/Export Methods + # Import/Export Methods ############################################## def export_data(self): """ @@ -765,11 +820,14 @@ class Block(Element): n['key'] = self.get_key() n['param'] = map(lambda p: p.export_data(), sorted(self.get_params(), key=str)) if 'bus' in map(lambda a: a.get_type(), self.get_sinks()): - n['bus_sink'] = str(1); + n['bus_sink'] = str(1) if 'bus' in map(lambda a: a.get_type(), self.get_sources()): - n['bus_source'] = str(1); + n['bus_source'] = str(1) return n + def get_hash(self): + return hash(tuple(map(hash, self.get_params()))) + def import_data(self, n): """ Import this block's params from nested data. @@ -782,28 +840,27 @@ class Block(Element): Args: n: the nested data odict """ - get_hash = lambda: hash(tuple(map(hash, self.get_params()))) my_hash = 0 - while get_hash() != my_hash: + while self.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 + # 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() + # Store hash and call rewrite + my_hash = self.get_hash() self.rewrite() - bussinks = n.findall('bus_sink'); + bussinks = n.findall('bus_sink') if len(bussinks) > 0 and not self._bussify_sink: - self.bussify({'name':'bus','type':'bus'}, 'sink') + self.bussify({'name': 'bus', 'type': 'bus'}, 'sink') elif len(bussinks) > 0: - self.bussify({'name':'bus','type':'bus'}, 'sink') - self.bussify({'name':'bus','type':'bus'}, 'sink') - bussrcs = n.findall('bus_source'); + self.bussify({'name': 'bus', 'type': 'bus'}, 'sink') + self.bussify({'name': 'bus', 'type': 'bus'}, 'sink') + bussrcs = n.findall('bus_source') if len(bussrcs) > 0 and not self._bussify_source: - self.bussify({'name':'bus','type':'bus'}, 'source') + self.bussify({'name': 'bus', 'type': 'bus'}, 'source') elif len(bussrcs) > 0: - self.bussify({'name':'bus','type':'bus'}, 'source') - self.bussify({'name':'bus','type':'bus'}, 'source') + self.bussify({'name': 'bus', 'type': 'bus'}, 'source') + self.bussify({'name': 'bus', 'type': 'bus'}, 'source') diff --git a/grc/model/Connection.py b/grc/model/Connection.py index 4404308731..7cef4ad2b7 100644 --- a/grc/model/Connection.py +++ b/grc/model/Connection.py @@ -22,6 +22,7 @@ from . import Constants from .Element import Element from .odict import odict + class Connection(Element): def __init__(self, flow_graph, porta, portb): @@ -39,18 +40,23 @@ class Connection(Element): """ Element.__init__(self, flow_graph) source = sink = None - #separate the source and sink + # Separate the source and sink for port in (porta, portb): - if port.is_source(): source = port - if port.is_sink(): sink = port - if not source: raise ValueError('Connection could not isolate source') - if not sink: raise ValueError('Connection could not isolate sink') - busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink]))%2 - if not busses == 0: raise ValueError('busses must get with busses') + if port.is_source(): + source = port + if port.is_sink(): + sink = port + if not source: + raise ValueError('Connection could not isolate source') + if not sink: + raise ValueError('Connection could not isolate sink') + busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink])) % 2 + if not busses == 0: + raise ValueError('busses must get with busses') if not len(source.get_associated_ports()) == len(sink.get_associated_ports()): - raise ValueError('port connections must have same cardinality'); - #ensure that this connection (source -> sink) is unique + raise ValueError('port connections must have same cardinality') + # Ensure that this connection (source -> sink) is unique for connection in self.get_parent().get_connections(): if connection.get_source() is source and connection.get_sink() is sink: raise LookupError('This connection between source and sink is not unique.') @@ -58,18 +64,17 @@ class Connection(Element): self._sink = sink if source.get_type() == 'bus': - sources = source.get_associated_ports(); - sinks = sink.get_associated_ports(); + sources = source.get_associated_ports() + sinks = sink.get_associated_ports() for i in range(len(sources)): try: - flow_graph.connect(sources[i], sinks[i]); + flow_graph.connect(sources[i], sinks[i]) except: pass - def __str__(self): - return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%( + return 'Connection (\n\t{}\n\t\t{}\n\t{}\n\t\t{}\n)'.format( self.get_source().get_parent(), self.get_source(), self.get_sink().get_parent(), @@ -98,8 +103,8 @@ class Connection(Element): source_domain = self.get_source().get_domain() sink_domain = self.get_sink().get_domain() if (source_domain, sink_domain) not in platform.get_connection_templates(): - self.add_error_message('No connection known for domains "%s", "%s"' - % (source_domain, sink_domain)) + self.add_error_message('No connection known for domains "{}", "{}"'.format( + source_domain, sink_domain)) too_many_other_sinks = ( source_domain in platform.get_domains() and not platform.get_domain(key=source_domain)['multiple_sinks'] and @@ -112,16 +117,15 @@ class Connection(Element): ) if too_many_other_sinks: self.add_error_message( - 'Domain "%s" can have only one downstream block' % source_domain) + 'Domain "{}" can have only one downstream block'.format(source_domain)) if too_many_other_sources: self.add_error_message( - 'Domain "%s" can have only one upstream block' % sink_domain) + 'Domain "{}" can have only one upstream block'.format(sink_domain)) source_size = Constants.TYPE_TO_SIZEOF[self.get_source().get_type()] * self.get_source().get_vlen() sink_size = Constants.TYPE_TO_SIZEOF[self.get_sink().get_type()] * self.get_sink().get_vlen() if source_size != sink_size: - self.add_error_message('Source IO size "%s" does not match sink IO size "%s".'%(source_size, sink_size)) - + self.add_error_message('Source IO size "{}" does not match sink IO size "{}".'.format(source_size, sink_size)) def get_enabled(self): """ @@ -136,11 +140,14 @@ class Connection(Element): ############################# # Access Ports ############################# - def get_sink(self): return self._sink - def get_source(self): return self._source + def get_sink(self): + return self._sink + + def get_source(self): + return self._source ############################################## - ## Import/Export Methods + # Import/Export Methods ############################################## def export_data(self): """ diff --git a/grc/model/Constants.py b/grc/model/Constants.py index 9336a9f642..d77dffcd5e 100644 --- a/grc/model/Constants.py +++ b/grc/model/Constants.py @@ -25,7 +25,7 @@ from gnuradio import gr _gr_prefs = gr.prefs() -# setup paths +# Setup paths PATH_SEP = {'/': ':', '\\': ';'}[os.path.sep] HIER_BLOCKS_LIB_DIR = os.environ.get('GRC_HIER_PATH', expanduser('~/.grc_gnuradio')) @@ -41,13 +41,12 @@ BLOCKS_DIRS = filter( # filter blank strings ]).split(PATH_SEP), ) + [HIER_BLOCKS_LIB_DIR] - -#data files +# Data files DATA_DIR = os.path.dirname(__file__) FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd') BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd') -# file format versions: +# File format versions: # 0: undefined / legacy # 1: non-numeric message port keys (label is used instead) FLOW_GRAPH_FILE_FORMAT_VERSION = 1 @@ -72,27 +71,27 @@ BLOCK_DISABLED = 0 BLOCK_ENABLED = 1 BLOCK_BYPASSED = 2 - -# user settings +# User settings XTERM_EXECUTABLE = _gr_prefs.get_string('grc', 'xterm_executable', 'xterm') -# file creation modes -TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH +# File creation modes +TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | \ + stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH -# data files +# Data files DATA_DIR = os.path.dirname(__file__) FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl') BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd') DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc') -#define types, native python + numpy +# Define types, native python + numpy VECTOR_TYPES = (tuple, list, set, numpy.ndarray) COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128] REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64] INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64, - numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64] -#cast to tuple for isinstance, concat subtypes + numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64] +# Cast to tuple for isinstance, concat subtypes COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES) REAL_TYPES = tuple(REAL_TYPES + INT_TYPES) INT_TYPES = tuple(INT_TYPES) @@ -119,7 +118,6 @@ GRC_COLOR_DARK_GREY = '#72706F' GRC_COLOR_GREY = '#BDBDBD' GRC_COLOR_WHITE = '#FFFFFF' - CORE_TYPES = ( # name, key, sizeof, color ('Complex Float 64', 'fc64', 16, GRC_COLOR_BROWN), ('Complex Float 32', 'fc32', 8, GRC_COLOR_BLUE), @@ -140,23 +138,25 @@ CORE_TYPES = ( # name, key, sizeof, color ) ALIAS_TYPES = { - 'complex' : (8, GRC_COLOR_BLUE), - 'float' : (4, GRC_COLOR_ORANGE), - 'int' : (4, GRC_COLOR_TEAL), - 'short' : (2, GRC_COLOR_YELLOW), - 'byte' : (1, GRC_COLOR_LIGHT_PURPLE), + 'complex': (8, GRC_COLOR_BLUE), + 'float': (4, GRC_COLOR_ORANGE), + 'int': (4, GRC_COLOR_TEAL), + 'short': (2, GRC_COLOR_YELLOW), + 'byte': (1, GRC_COLOR_LIGHT_PURPLE), } TYPE_TO_COLOR = dict() TYPE_TO_SIZEOF = dict() + for name, key, sizeof, color in CORE_TYPES: TYPE_TO_COLOR[key] = color TYPE_TO_SIZEOF[key] = sizeof + for key, (sizeof, color) in ALIAS_TYPES.iteritems(): TYPE_TO_COLOR[key] = color TYPE_TO_SIZEOF[key] = sizeof -#coloring +# Coloring COMPLEX_COLOR_SPEC = '#3399FF' FLOAT_COLOR_SPEC = '#FF8C69' INT_COLOR_SPEC = '#00FF99' diff --git a/grc/model/Element.py b/grc/model/Element.py index 351445fdbc..6716cd619c 100644 --- a/grc/model/Element.py +++ b/grc/model/Element.py @@ -63,10 +63,10 @@ class Element(object): Returns: a list of error message strings """ - error_messages = list(self._error_messages) #make a copy + 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"))) + error_messages.append("{}:\n\t{}".format(child, msg.replace("\n", "\n\t"))) return error_messages def rewrite(self): @@ -81,15 +81,16 @@ class Element(object): return True ############################################## - ## Tree-like API + # Tree-like API ############################################## def get_parent(self): return self._parent + def get_children(self): return list() ############################################## - ## Type testing methods + # Type testing methods ############################################## def is_element(self): return True @@ -105,6 +106,7 @@ class Element(object): def is_block(self): return False + def is_dummy_block(self): return False diff --git a/grc/model/FlowGraph.py b/grc/model/FlowGraph.py index 484c3fdb85..0aea1457cb 100644 --- a/grc/model/FlowGraph.py +++ b/grc/model/FlowGraph.py @@ -39,10 +39,11 @@ _bus_struct_src_searcher = re.compile('^(bus_structure_source)$') def _initialize_dummy_block(block, block_n): - """This is so ugly... dummy-fy a block - + """ + This is so ugly... dummy-fy a block Modify block object to get the behaviour for a missing block """ + block._key = block_n.find('key') block.is_dummy_block = lambda: True block.is_valid = lambda: False @@ -50,11 +51,12 @@ def _initialize_dummy_block(block, block_n): for param_n in block_n.findall('param'): if param_n['key'] not in block.get_param_keys(): new_param_n = odict({'key': param_n['key'], 'name': param_n['key'], 'type': 'string'}) - block.get_params().append(block.get_parent().get_parent().Param(block=block, n=new_param_n)) + params = block.get_parent().get_parent().Param(block=block, n=new_param_n) + block.get_params().append(params) def _dummy_block_add_port(block, key, dir): - """This is so ugly... Add a port to a dummy-field block""" + """ This is so ugly... Add a port to a dummy-field block """ port_n = odict({'name': '?', 'key': key, 'type': ''}) port = block.get_parent().get_parent().Port(block=block, n=port_n, dir=dir) if port.is_source(): @@ -67,7 +69,6 @@ def _dummy_block_add_port(block, key, dir): class FlowGraph(Element): def __init__(self, platform): - self.grc_file_path = '' """ Make a flow graph from the arguments. @@ -77,11 +78,12 @@ class FlowGraph(Element): Returns: the flow graph object """ - #initialize + self.grc_file_path = '' + # Initialize Element.__init__(self, platform) self._elements = [] self._timestamp = time.ctime() - #inital blank import + # Inital blank import self.import_data() self.n = {} @@ -101,18 +103,16 @@ class FlowGraph(Element): """ index = 0 while True: - id = '%s_%d' % (base_id, index) + id = '{}_{}'.format(base_id, index) index += 1 - #make sure that the id is not used by another block + # Make sure that the id is not used by another block if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id def __str__(self): - return 'FlowGraph - %s(%s)' % (self.get_option('title'), self.get_option('id')) + return 'FlowGraph - {}({})'.format(self.get_option('title'), self.get_option('id')) def get_complexity(self): - """ - Determines the complexity of a flowgraph - """ + """ Determines the complexity of a flowgraph """ dbal = 0 block_list = self.get_blocks() for block in block_list: @@ -173,12 +173,14 @@ class FlowGraph(Element): Returns: the resultant object """ - if not code: raise Exception, 'Cannot evaluate empty statement.' + if not code: + raise Exception('Cannot evaluate empty statement.') my_hash = hash(code) ^ namespace_hash - #cache if does not exist - if not self._eval_cache.has_key(my_hash): + + # Cache if does not exist + if my_hash not in self._eval_cache: self._eval_cache[my_hash] = eval(code, namespace, namespace) - #return from cache + # Return from cache return self._eval_cache[my_hash] def get_hier_block_stream_io(self, direction): @@ -336,8 +338,7 @@ class FlowGraph(Element): for i in bussink: for j in i.get_params(): if j.get_name() == 'On/Off' and j.get_value() == 'on': - return True; - + return True return False def get_bussrc(self): @@ -346,18 +347,15 @@ class FlowGraph(Element): for i in bussrc: for j in i.get_params(): if j.get_name() == 'On/Off' and j.get_value() == 'on': - return True; - + return True return False def get_bus_structure_sink(self): bussink = filter(lambda b: _bus_struct_sink_searcher.search(b.get_key()), self.get_enabled_blocks()) - return bussink def get_bus_structure_src(self): bussrc = filter(lambda b: _bus_struct_src_searcher.search(b.get_key()), self.get_enabled_blocks()) - return bussrc def iter_enabled_blocks(self): @@ -404,14 +402,15 @@ class FlowGraph(Element): Returns: the new block or None if not found """ - if key not in self.get_parent().get_block_keys(): return None + 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); + self.get_elements().append(block) if block._bussify_sink: - block.bussify({'name':'bus','type':'bus'}, 'sink') + block.bussify({'name': 'bus', 'type': 'bus'}, 'sink') if block._bussify_source: - block.bussify({'name':'bus','type':'bus'}, 'source') - return block; + block.bussify({'name': 'bus', 'type': 'bus'}, 'source') + return block def connect(self, porta, portb): """ @@ -436,11 +435,12 @@ class FlowGraph(Element): If the element is a block, remove its connections. If the element is a connection, just remove the connection. """ - if element not in self.get_elements(): return - #found a port, set to parent signal block + if element not in self.get_elements(): + return + # Found a port, set to parent signal block if element.is_port(): element = element.get_parent() - #remove block, remove all involved connections + # Remove block, remove all involved connections if element.is_block(): for port in element.get_ports(): map(self.remove_element, port.get_connections()) @@ -448,8 +448,8 @@ class FlowGraph(Element): if element.is_bus(): cons_list = [] for i in map(lambda a: a.get_connections(), element.get_source().get_associated_ports()): - cons_list.extend(i); - map(self.remove_element, cons_list); + cons_list.extend(i) + map(self.remove_element, cons_list) self.get_elements().remove(element) def get_option(self, key): @@ -465,10 +465,11 @@ class FlowGraph(Element): """ return self._options_block.get_param(key).get_evaluated() - def is_flow_graph(self): return True + def is_flow_graph(self): + return True ############################################## - ## Access Elements + # Access Elements ############################################## def get_block(self, id): for block in self.iter_blocks(): @@ -505,7 +506,7 @@ class FlowGraph(Element): get_children = get_elements - ### TODO >>> THIS SUCKS ### + # TODO >>> THIS SUCKS # def rewrite(self): """ Flag the namespace to be renewed. @@ -514,21 +515,17 @@ class FlowGraph(Element): for block in self.get_blocks(): if 'bus' in map(lambda a: a.get_type(), block.get_sources_gui()): - - for i in range(len(block.get_sources_gui())): if len(block.get_sources_gui()[i].get_connections()) > 0: source = block.get_sources_gui()[i] sink = [] for j in range(len(source.get_connections())): - sink.append(source.get_connections()[j].get_sink()); - - + sink.append(source.get_connections()[j].get_sink()) for elt in source.get_connections(): - self.remove_element(elt); + self.remove_element(elt) for j in sink: - self.connect(source, j); + self.connect(source, j) self._renew_eval_ns = True def refactor_bus_structure(): @@ -536,38 +533,39 @@ class FlowGraph(Element): for block in self.get_blocks(): for direc in ['source', 'sink']: if direc == 'source': - get_p = block.get_sources; - get_p_gui = block.get_sources_gui; - bus_structure = block.form_bus_structure('source'); + get_p = block.get_sources + get_p_gui = block.get_sources_gui + bus_structure = block.form_bus_structure('source') else: - get_p = block.get_sinks; + get_p = block.get_sinks get_p_gui = block.get_sinks_gui - bus_structure = block.form_bus_structure('sink'); + bus_structure = block.form_bus_structure('sink') if 'bus' in map(lambda a: a.get_type(), get_p_gui()): if len(get_p_gui()) > len(bus_structure): - times = range(len(bus_structure), len(get_p_gui())); + times = range(len(bus_structure), len(get_p_gui())) for i in times: for connect in get_p_gui()[-1].get_connections(): - block.get_parent().remove_element(connect); - get_p().remove(get_p_gui()[-1]); + block.get_parent().remove_element(connect) + get_p().remove(get_p_gui()[-1]) elif len(get_p_gui()) < len(bus_structure): - n = {'name':'bus','type':'bus'}; + n = {'name': 'bus', 'type': 'bus'} if True in map(lambda a: isinstance(a.get_nports(), int), get_p()): - n['nports'] = str(1); + n['nports'] = str(1) - times = range(len(get_p_gui()), len(bus_structure)); + times = range(len(get_p_gui()), len(bus_structure)) for i in times: - n['key'] = str(len(get_p())); - n = odict(n); - port = block.get_parent().get_parent().Port(block=block, n=n, dir=direc); - get_p().append(port); + n['key'] = str(len(get_p())) + n = odict(n) + port = block.get_parent().get_parent().Port(block=block, n=n, dir=direc) + get_p().append(port) - for child in self.get_children(): child.rewrite() + for child in self.get_children(): + child.rewrite() refactor_bus_structure() - reconnect_bus_blocks(); + reconnect_bus_blocks() def evaluate(self, expr): """ @@ -582,12 +580,14 @@ class FlowGraph(Element): """ if self._renew_eval_ns: self._renew_eval_ns = False - #reload namespace + # Reload namespace n = dict() - #load imports + # Load imports for code in self.get_imports(): - try: exec code in n - except: pass + try: + exec code in n + except: + pass for id, code in self.get_python_modules(): try: @@ -597,24 +597,26 @@ class FlowGraph(Element): except: pass - #load parameters + # Load parameters np = dict() for parameter in self.get_parameters(): try: e = eval(parameter.get_param('value').to_code(), n, n) np[parameter.get_id()] = e - except: pass - n.update(np) #merge param namespace - #load variables + except: + pass + n.update(np) # Merge param namespace + # Load variables for variable in self.get_variables(): try: e = eval(variable.get_var_value(), n, n) n[variable.get_id()] = e - except: pass - #make namespace public + except: + pass + # Make namespace public self.n = n self.n_hash = hash(str(n)) - #evaluate + # Evaluate e = self._eval(expr, self.n, self.n_hash) return e @@ -637,7 +639,7 @@ class FlowGraph(Element): return block ############################################## - ## Import/Export Methods + # Import/Export Methods ############################################## def export_data(self): """ @@ -736,7 +738,7 @@ class FlowGraph(Element): self.connect(source_port, sink_port) except LookupError as e: Messages.send_error_load( - 'Connection between %s(%s) and %s(%s) could not be made.\n\t%s' % ( + 'Connection between {}({}) and {}({}) could not be made.\n\t{}'.format( source_block_id, source_key, sink_block_id, sink_key, e)) errors = True @@ -745,7 +747,8 @@ class FlowGraph(Element): @staticmethod def _update_old_message_port_keys(source_key, sink_key, source_block, sink_block): - """Backward compatibility for message port keys + """ + Backward compatibility for message port keys Message ports use their names as key (like in the 'connect' method). Flowgraph files from former versions still have numeric keys stored for @@ -768,7 +771,7 @@ class FlowGraph(Element): @staticmethod def _guess_file_format_1(n): - """Try to guess the file format for flow-graph files without version tag""" + """ Try to guess the file format for flow-graph files without version tag """ try: has_non_numeric_message_keys = any(not ( connection_n.find('source_key').isdigit() and diff --git a/grc/model/Generator.py b/grc/model/Generator.py index c61900e7bf..f11766f910 100644 --- a/grc/model/Generator.py +++ b/grc/model/Generator.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2011 Free Software Foundation, Inc. +Copyright 2008-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -85,8 +85,8 @@ class TopBlockGenerator(object): self._generate_options = self._flow_graph.get_option('generate_options') self._mode = TOP_BLOCK_FILE_MODE dirname = self._dirname = os.path.dirname(file_path) - # handle the case where the directory is read-only - # in this case, use the system's temp directory + # Handle the case where the directory is read-only + # In this case, use the system's temp directory if not os.access(dirname, os.W_OK): dirname = tempfile.gettempdir() filename = self._flow_graph.get_option('id') + '.py' @@ -97,7 +97,7 @@ class TopBlockGenerator(object): def write(self): """generate output and write it to files""" - # do throttle warning + # Do throttle warning throttling_blocks = filter(lambda b: b.throtteling(), self._flow_graph.get_enabled_blocks()) if not throttling_blocks and not self._generate_options.startswith('hb'): Messages.send_warning("This flow graph may not have flow control: " @@ -112,7 +112,7 @@ class TopBlockGenerator(object): "e.g. a hardware source or sink. " "This is usually undesired. Consider " "removing the throttle block.") - # generate + # Generate for filename, data in self._build_python_code_from_template(): with codecs.open(filename, 'w', encoding='utf-8') as fp: fp.write(data) @@ -138,7 +138,7 @@ class TopBlockGenerator(object): except Exception as e: raise ValueError("Can't parse run command {!r}: {}".format(run_command, e)) - # when in no gui mode on linux, use a graphical terminal (looks nice) + # When in no gui mode on linux, use a graphical terminal (looks nice) xterm_executable = find_executable(XTERM_EXECUTABLE) if self._generate_options == 'no_gui' and xterm_executable: run_command_args = [xterm_executable, '-e', run_command] @@ -170,15 +170,15 @@ class TopBlockGenerator(object): parameters = fg.get_parameters() monitors = fg.get_monitors() - # list of blocks not including variables and imports and parameters and disabled + # List of blocks not including variables and imports and parameters and disabled def _get_block_sort_text(block): code = block.get_make().replace(block.get_id(), ' ') try: - code += block.get_param('notebook').get_value() # older gui markup w/ wxgui + code += block.get_param('notebook').get_value() # Older gui markup w/ wxgui except: pass try: - code += block.get_param('gui_hint').get_value() # newer gui markup w/ qtgui + code += block.get_param('gui_hint').get_value() # Newer gui markup w/ qtgui except: pass return code @@ -201,7 +201,8 @@ class TopBlockGenerator(object): output.append((file_path, src)) # Filter out virtual sink connections - cf = lambda c: not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink()) + def cf(c): + return not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink()) connections = filter(cf, fg.get_enabled_connections()) # Get the virtual blocks and resolve their connections @@ -223,8 +224,7 @@ class TopBlockGenerator(object): for block in bypassed_blocks: # Get the upstream connection (off of the sink ports) # Use *connections* not get_connections() - get_source_connection = lambda c: c.get_sink() == block.get_sinks()[0] - source_connection = filter(get_source_connection, connections) + source_connection = filter(lambda c: c.get_sink() == block.get_sinks()[0], connections) # The source connection should never have more than one element. assert (len(source_connection) == 1) @@ -232,8 +232,7 @@ class TopBlockGenerator(object): source_port = source_connection[0].get_source() # Loop through all the downstream connections - get_sink_connections = lambda c: c.get_source() == block.get_sources()[0] - for sink in filter(get_sink_connections, connections): + for sink in filter(lambda c: c.get_source() == block.get_sources()[0], connections): if not sink.get_enabled(): # Ignore disabled connections continue @@ -253,21 +252,21 @@ class TopBlockGenerator(object): connection_templates = fg.get_parent().get_connection_templates() msgs = filter(lambda c: c.is_msg(), fg.get_enabled_connections()) - # list of variable names + # List of variable names var_ids = [var.get_id() for var in parameters + variables] - # prepend self. + # Prepend self. replace_dict = dict([(var_id, 'self.%s' % var_id) for var_id in var_ids]) - # list of callbacks + # List of callbacks callbacks = [ expr_utils.expr_replace(cb, replace_dict) for cb in sum([block.get_callbacks() for block in fg.get_enabled_blocks()], []) ] - # map var id to callbacks + # Map var id to callbacks var_id2cbs = dict([ (var_id, filter(lambda c: expr_utils.get_variable_dependencies(c, [var_id]), callbacks)) for var_id in var_ids ]) - # load the namespace + # Load the namespace namespace = { 'title': title, 'imports': imports, @@ -282,7 +281,7 @@ class TopBlockGenerator(object): 'generate_options': self._generate_options, 'var_id2cbs': var_id2cbs, } - # build the template + # Build the template t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace) output.append((self.get_file_path(), str(t))) return output @@ -325,7 +324,7 @@ class HierBlockGenerator(TopBlockGenerator): Returns: a xml node tree """ - # extract info from the flow graph + # Extract info from the flow graph block_key = self._flow_graph.get_option('id') parameters = self._flow_graph.get_parameters() @@ -334,7 +333,7 @@ class HierBlockGenerator(TopBlockGenerator): return "$"+name return name - # build the nested data + # Build the nested data block_n = odict() block_n['name'] = self._flow_graph.get_option('title') or \ self._flow_graph.get_option('id').replace('_', ' ').title() @@ -342,7 +341,7 @@ class HierBlockGenerator(TopBlockGenerator): block_n['category'] = self._flow_graph.get_option('category') block_n['import'] = "from {0} import {0} # grc-generated hier_block".format( self._flow_graph.get_option('id')) - # make data + # Make data if parameters: block_n['make'] = '{cls}(\n {kwargs},\n)'.format( cls=block_key, @@ -352,7 +351,7 @@ class HierBlockGenerator(TopBlockGenerator): ) else: block_n['make'] = '{cls}()'.format(cls=block_key) - # callback data + # Callback data block_n['callback'] = [ 'set_{key}(${key})'.format(key=param.get_id()) for param in parameters ] @@ -367,13 +366,13 @@ class HierBlockGenerator(TopBlockGenerator): param_n['type'] = 'raw' block_n['param'].append(param_n) - # bus stuff + # Bus stuff if self._flow_graph.get_bussink(): block_n['bus_sink'] = '1' if self._flow_graph.get_bussrc(): block_n['bus_source'] = '1' - # sink/source ports + # Sink/source ports for direction in ('sink', 'source'): block_n[direction] = list() for port in self._flow_graph.get_hier_block_io(direction): @@ -386,7 +385,7 @@ class HierBlockGenerator(TopBlockGenerator): port_n['optional'] = '1' block_n[direction].append(port_n) - # more bus stuff + # More bus stuff bus_struct_sink = self._flow_graph.get_bus_structure_sink() if bus_struct_sink: block_n['bus_structure_sink'] = bus_struct_sink[0].get_param('struct').get_value() @@ -394,7 +393,7 @@ class HierBlockGenerator(TopBlockGenerator): if bus_struct_src: block_n['bus_structure_source'] = bus_struct_src[0].get_param('struct').get_value() - # documentation + # Documentation block_n['doc'] = "\n".join(field for field in ( self._flow_graph.get_option('author'), self._flow_graph.get_option('description'), diff --git a/grc/model/Param.py b/grc/model/Param.py index c8da6a5b58..e00be7e203 100644 --- a/grc/model/Param.py +++ b/grc/model/Param.py @@ -26,33 +26,52 @@ from gnuradio import gr import Constants from Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES - -_check_id_matcher = re.compile('^[a-z|A-Z]\w*$') -_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook|epy_module)$') - from .odict import odict from .Element import Element -#blacklist certain ids, its not complete, but should help +# Blacklist certain ids, its not complete, but should help import __builtin__ + + ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + \ filter(lambda x: not x.startswith('_'), dir(gr.top_block())) + dir(__builtin__) -def _get_keys(lst): return [elem.get_key() for elem in lst] +_check_id_matcher = re.compile('^[a-z|A-Z]\w*$') +_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook)$') + + +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)) + try: + return lst[_get_keys(lst).index(key)] + except ValueError: + raise ValueError('Key "{}" not found in {}.'.format(key, _get_keys(lst))) + def num_to_str(num): """ Display logic for numbers """ if isinstance(num, COMPLEX_TYPES): - num = complex(num) #cast to python complex - if num == 0: return '0' #value is zero - elif num.imag == 0: return '%s'%eng_notation.num_to_str(num.real) #value is real - elif num.real == 0: return '%sj'%eng_notation.num_to_str(num.imag) #value is imaginary - elif num.imag < 0: return '%s-%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(abs(num.imag))) - else: return '%s+%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(num.imag)) - else: return str(num) + num = complex(num) # Cast to python complex + if num == 0: + return '0' + elif num.imag == 0: + # Value is real + return '{}'.format(eng_notation.num_to_str(num.real)) + elif num.real == 0: + # Value is imaginary + return '{}j'.format(eng_notation.num_to_str(num.imag)) + elif num.imag < 0: + return '{}-{}j'.format(eng_notation.num_to_str(num.real), + eng_notation.num_to_str(abs(num.imag))) + else: + return '{}+{}j'.format(eng_notation.num_to_str(num.real), + eng_notation.num_to_str(num.imag)) + else: + return str(num) + class Option(Element): @@ -62,30 +81,42 @@ class Option(Element): self._key = n.find('key') self._opts = dict() opts = n.findall('opt') - #test against opts when non enum + # Test against opts when non enum if not self.get_parent().is_enum() and opts: - raise Exception, 'Options for non-enum types cannot have sub-options' - #extract opts + raise Exception('Options for non-enum types cannot have sub-options') + # Extract opts for opt in opts: - #separate the key:value - try: key, value = opt.split(':') - except: raise Exception, 'Error separating "%s" into key:value'%opt - #test against repeated keys - if self._opts.has_key(key): - raise Exception, 'Key "%s" already exists in option'%key - #store the option + # Separate the key:value + try: + key, value = opt.split(':') + except: + raise Exception('Error separating "{}" into key:value'.format(opt)) + # Test against repeated keys + if key in self._opts: + raise Exception('Key "{}" already exists in option'.format(key)) + # Store the option self._opts[key] = value - def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key()) - def get_name(self): return self._name - def get_key(self): return self._key + def __str__(self): + return 'Option {}({})'.format(self.get_name(), self.get_key()) + + def get_name(self): + return self._name + + def get_key(self): + return self._key ############################################## # Access Opts ############################################## - def get_opt_keys(self): return self._opts.keys() - def get_opt(self, key): return self._opts[key] - def get_opts(self): return self._opts.values() + def get_opt_keys(self): + return self._opts.keys() + + def get_opt(self, key): + return self._opts[key] + + def get_opts(self): + return self._opts.values() class Param(Element): @@ -98,49 +129,52 @@ class Param(Element): block: the parent element n: the nested odict """ - # if the base key is a valid param key, copy its data and overlay this params data + # If the base key is a valid param key, copy its data and overlay this params data base_key = n.find('base_key') if base_key and base_key in block.get_param_keys(): n_expanded = block.get_param(base_key)._n.copy() n_expanded.update(n) n = n_expanded - # save odict in case this param will be base for another + # Save odict in case this param will be base for another self._n = n - # parse the data + # Parse the data self._name = n.find('name') self._key = n.find('key') value = n.find('value') or '' self._type = n.find('type') or 'raw' self._hide = n.find('hide') or '' self._tab_label = n.find('tab') or block.get_param_tab_labels()[0] - if not self._tab_label in block.get_param_tab_labels(): + if self._tab_label not in block.get_param_tab_labels(): block.get_param_tab_labels().append(self._tab_label) - #build the param + # Build the param Element.__init__(self, block) - #create the Option objects from the n data + # Create the Option objects from the n data self._options = list() self._evaluated = None for option in map(lambda o: Option(param=self, n=o), n.findall('option')): key = option.get_key() - #test against repeated keys + # Test against repeated keys if key in self.get_option_keys(): - raise Exception, 'Key "%s" already exists in options'%key - #store the option + raise Exception('Key "{}" already exists in options'.format(key)) + # Store the option self.get_options().append(option) - #test the enum options + # Test the enum options if self.is_enum(): - #test against options with identical keys + # Test against options with identical keys if len(set(self.get_option_keys())) != len(self.get_options()): - raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys() - #test against inconsistent keys in options + raise Exception('Options keys "{}" are not unique.'.format(self.get_option_keys())) + # Test against inconsistent keys in options opt_keys = self.get_options()[0].get_opt_keys() for option in self.get_options(): if set(opt_keys) != set(option.get_opt_keys()): - 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 - self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0] + raise Exception('Opt keys "{}" are not identical across all options.'.format(opt_keys)) + # If a value is specified, it must be in the options keys + if value or value in self.get_option_keys(): + self._value = value + else: + self._value = self.get_option_keys()[0] if self.get_value() not in self.get_option_keys(): - raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys()) + raise Exception('The value "{}" is not in the possible values of "{}".'.format(self.get_value(), self.get_option_keys())) else: self._value = value or '' self._default = value @@ -167,44 +201,55 @@ class Param(Element): the string representation """ ################################################## - # truncate helper method + # Truncate helper method ################################################## def _truncate(string, style=0): max_len = max(27 - len(self.get_name()), 3) if len(string) > max_len: - if style < 0: #front truncate + if style < 0: # Front truncate string = '...' + string[3-max_len:] - elif style == 0: #center truncate - string = string[:max_len/2 -3] + '...' + string[-max_len/2:] - elif style > 0: #rear truncate + elif style == 0: # Center truncate + string = string[:max_len/2 - 3] + '...' + string[-max_len/2:] + elif style > 0: # Rear truncate string = string[:max_len-3] + '...' return string + ################################################## - # simple conditions + # Simple conditions ################################################## - if not self.is_valid(): return _truncate(self.get_value()) - if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name() + if not self.is_valid(): + return _truncate(self.get_value()) + if self.get_value() in self.get_option_keys(): + return self.get_option(self.get_value()).get_name() ################################################## - # split up formatting by type + # Split up formatting by type ################################################## - truncate = 0 #default center truncate + # Default center truncate + truncate = 0 e = self.get_evaluated() t = self.get_type() - if isinstance(e, bool): return str(e) - elif isinstance(e, COMPLEX_TYPES): dt_str = num_to_str(e) - elif isinstance(e, VECTOR_TYPES): #vector types + if isinstance(e, bool): + return str(e) + elif isinstance(e, COMPLEX_TYPES): + dt_str = num_to_str(e) + elif isinstance(e, VECTOR_TYPES): + # Vector types if len(e) > 8: - dt_str = self.get_value() #large vectors use code + # Large vectors use code + dt_str = self.get_value() truncate = 1 - else: dt_str = ', '.join(map(num_to_str, e)) #small vectors use eval + else: + # Small vectors use eval + dt_str = ', '.join(map(num_to_str, e)) elif t in ('file_open', 'file_save'): dt_str = self.get_value() truncate = -1 - else: dt_str = str(e) #other types - ################################################## - # done - ################################################## + else: + # Other types + dt_str = str(e) + + # Done return _truncate(dt_str, truncate) def __repr2__(self): @@ -218,7 +263,8 @@ class Param(Element): return self.get_option(self.get_value()).get_name() return self.get_value() - def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key()) + def __str__(self): + return 'Param - {}({})'.format(self.get_name(), self.get_key()) def get_color(self): """ @@ -229,17 +275,17 @@ class Param(Element): """ try: return { - #number types + # Number types 'complex': Constants.COMPLEX_COLOR_SPEC, 'real': Constants.FLOAT_COLOR_SPEC, 'float': Constants.FLOAT_COLOR_SPEC, 'int': Constants.INT_COLOR_SPEC, - #vector types + # Vector types 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC, 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, - 'float_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, + 'float_vector': Constants.FLOAT_VECTOR_COLOR_SPEC, 'int_vector': Constants.INT_VECTOR_COLOR_SPEC, - #special + # Special 'bool': Constants.INT_COLOR_SPEC, 'hex': Constants.INT_COLOR_SPEC, 'string': Constants.BYTE_VECTOR_COLOR_SPEC, @@ -264,22 +310,27 @@ class Param(Element): hide the hide property string """ hide = self.get_parent().resolve_dependencies(self._hide).strip() - if hide: return hide - #hide ID in non variable blocks - if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): return 'part' - #hide port controllers for type and nports - if self.get_key() in ' '.join(map( - lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports()) - ): return 'part' - #hide port controllers for vlen, when == 1 + if hide: + return hide + # Hide ID in non variable blocks + if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): + return 'part' + # Hide port controllers for type and nports + if self.get_key() in ' '.join(map(lambda p: ' '.join([p._type, p._nports]), + self.get_parent().get_ports())): + return 'part' + # Hide port controllers for vlen, when == 1 if self.get_key() in ' '.join(map( lambda p: p._vlen, self.get_parent().get_ports()) ): try: - if int(self.get_evaluated()) == 1: return 'part' - except: pass - #hide empty grid positions - if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): return 'part' + if int(self.get_evaluated()) == 1: + return 'part' + except: + pass + # Hide empty grid positions + if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): + return 'part' return hide def validate(self): @@ -289,13 +340,16 @@ class Param(Element): """ Element.validate(self) if self.get_type() not in self.get_types(): - self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) + self.add_error_message('Type "{}" is not a possible type.'.format(self.get_type())) self._evaluated = None - try: self._evaluated = self.evaluate() - except Exception, e: self.add_error_message(str(e)) + try: + self._evaluated = self.evaluate() + except Exception, e: + self.add_error_message(str(e)) - def get_evaluated(self): return self._evaluated + def get_evaluated(self): + return self._evaluated def evaluate(self): """ @@ -310,72 +364,84 @@ class Param(Element): self._hostage_cells = list() t = self.get_type() v = self.get_value() + ######################### # Enum Type ######################### - if self.is_enum(): return v + if self.is_enum(): + return v + ######################### # Numeric Types ######################### elif t in ('raw', 'complex', 'real', 'float', 'int', 'hex', 'bool'): - #raise exception if python cannot evaluate this value - try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e) - #raise an exception if the data is invalid - if t == 'raw': return e + # Raise exception if python cannot evaluate this value + try: + e = self.get_parent().get_parent().evaluate(v) + except Exception, e: + raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) + # Raise an exception if the data is invalid + if t == 'raw': + return e elif t == 'complex': if not isinstance(e, COMPLEX_TYPES): - raise Exception, 'Expression "%s" is invalid for type complex.'%str(e) + raise Exception('Expression "{}" is invalid for type complex.'.format(str(e))) return e elif t == 'real' or t == 'float': if not isinstance(e, REAL_TYPES): - raise Exception, 'Expression "%s" is invalid for type float.'%str(e) + raise Exception('Expression "{}" is invalid for type float.'.format(str(e))) return e elif t == 'int': if not isinstance(e, INT_TYPES): - raise Exception, 'Expression "%s" is invalid for type integer.'%str(e) + raise Exception('Expression "{}" is invalid for type integer.'.format(str(e))) return e - elif t == 'hex': return hex(e) + elif t == 'hex': + return hex(e) elif t == 'bool': if not isinstance(e, bool): - raise Exception, 'Expression "%s" is invalid for type bool.'%str(e) + raise Exception('Expression "{}" is invalid for type bool.'.format(str(e))) return e - else: raise TypeError, 'Type "%s" not handled'%t + else: + raise TypeError('Type "{}" not handled'.format(t)) ######################### # Numeric Vector Types ######################### elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): - if not v: v = '()' #turn a blank string into an empty list, so it will eval - #raise exception if python cannot evaluate this value - try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e) - #raise an exception if the data is invalid + if not v: + # Turn a blank string into an empty list, so it will eval + v = '()' + # Raise exception if python cannot evaluate this value + try: + e = self.get_parent().get_parent().evaluate(v) + except Exception, e: + raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) + # Raise an exception if the data is invalid if t == 'complex_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]): - raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e) + raise Exception('Expression "{}" is invalid for type complex vector.'.format(str(e))) return e elif t == 'real_vector' or t == 'float_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] if not all([isinstance(ei, REAL_TYPES) for ei in e]): - raise Exception, 'Expression "%s" is invalid for type float vector.'%str(e) + raise Exception('Expression "{}" is invalid for type float vector.'.format(str(e))) return e elif t == 'int_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] if not all([isinstance(ei, INT_TYPES) for ei in e]): - raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e) + raise Exception('Expression "{}" is invalid for type integer vector.'.format(str(e))) return e ######################### # String Types ######################### elif t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): - #do not check if file/directory exists, that is a runtime issue + # Do not check if file/directory exists, that is a runtime issue try: e = self.get_parent().get_parent().evaluate(v) if not isinstance(e, str): @@ -384,58 +450,70 @@ class Param(Element): self._stringify_flag = True e = str(v) if t == '_multiline_python_external': - ast.parse(e) # raises SyntaxError + ast.parse(e) # Raises SyntaxError return e ######################### # Unique ID Type ######################### elif t == 'id': - #can python use this as a variable? + # Can python use this as a variable? if not _check_id_matcher.match(v): - raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v + raise Exception('ID "{}" must begin with a letter and may contain letters, numbers, and underscores.'.format(v)) ids = [param.get_value() for param in self.get_all_params(t)] - if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled - raise Exception, 'ID "%s" is not unique.'%v + + # Id should only appear once, or zero times if block is disabled + if ids.count(v) > 1: + raise Exception('ID "{}" is not unique.'.format(v)) if v in ID_BLACKLIST: - raise Exception, 'ID "%s" is blacklisted.'%v + raise Exception('ID "{}" is blacklisted.'.format(v)) return v + ######################### # Stream ID Type ######################### elif t == 'stream_id': - #get a list of all stream ids used in the virtual sinks + # Get a list of all stream ids used in the virtual sinks ids = [param.get_value() for param in filter( lambda p: p.get_parent().is_virtual_sink(), self.get_all_params(t), )] - #check that the virtual sink's stream id is unique + # Check that the virtual sink's stream id is unique if self.get_parent().is_virtual_sink(): - if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled - raise Exception, 'Stream ID "%s" is not unique.'%v - #check that the virtual source's steam id is found + # Id should only appear once, or zero times if block is disabled + if ids.count(v) > 1: + raise Exception('Stream ID "{}" is not unique.'.format(v)) + # Check that the virtual source's steam id is found if self.get_parent().is_virtual_source(): if v not in ids: - raise Exception, 'Stream ID "%s" is not found.'%v + raise Exception('Stream ID "{}" is not found.'.format(v)) return v + ######################### # GUI Position/Hint ######################### elif t == 'gui_hint': - if ':' in v: tab, pos = v.split(':') - elif '@' in v: tab, pos = v, '' - else: tab, pos = '', v - - if '@' in tab: tab, index = tab.split('@') - else: index = '?' - + if ':' in v: + tab, pos = v.split(':') + elif '@' in v: + tab, pos = v, '' + else: + tab, pos = '', v + + if '@' in tab: + tab, index = tab.split('@') + else: + index = '?' + + # TODO: Problem with this code. Produces bad tabs widget_str = ({ (True, True): 'self.%(tab)s_grid_layout_%(index)s.addWidget(%(widget)s, %(pos)s)', (True, False): 'self.%(tab)s_layout_%(index)s.addWidget(%(widget)s)', (False, True): 'self.top_grid_layout.addWidget(%(widget)s, %(pos)s)', (False, False): 'self.top_layout.addWidget(%(widget)s)', - }[bool(tab), bool(pos)])%{'tab': tab, 'index': index, 'widget': '%s', 'pos': pos} + }[bool(tab), bool(pos)]) % {'tab': tab, 'index': index, 'widget': '%s', 'pos': pos} - # FIXME: Move replace(...) into the make template of the qtgui blocks and return a string here + # FIXME: Move replace(...) into the make template of the qtgui blocks + # Return a string here class GuiHint(object): def __init__(self, ws): self._ws = ws @@ -450,59 +528,78 @@ class Param(Element): # Grid Position Type ######################### elif t == 'grid_pos': - if not v: return '' #allow for empty grid pos + if not v: + # Allow for empty grid pos + return '' e = self.get_parent().get_parent().evaluate(v) if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]): - raise Exception, 'A grid position must be a list of 4 integers.' + raise Exception('A grid position must be a list of 4 integers.') row, col, row_span, col_span = e - #check row, col + # Check row, col if row < 0 or col < 0: - raise Exception, 'Row and column must be non-negative.' - #check row span, col span + raise Exception('Row and column must be non-negative.') + # Check row span, col span if row_span <= 0 or col_span <= 0: - raise Exception, 'Row and column span must be greater than zero.' - #get hostage cell parent - try: my_parent = self.get_parent().get_param('notebook').evaluate() - except: my_parent = '' - #calculate hostage cells + raise Exception('Row and column span must be greater than zero.') + # Get hostage cell parent + try: + my_parent = self.get_parent().get_param('notebook').evaluate() + except: + my_parent = '' + # Calculate hostage cells for r in range(row_span): for c in range(col_span): self._hostage_cells.append((my_parent, (row+r, col+c))) - #avoid collisions + # Avoid collisions params = filter(lambda p: p is not self, self.get_all_params('grid_pos')) for param in params: for parent, cell in param._hostage_cells: if (parent, cell) in self._hostage_cells: - raise Exception, 'Another graphical element is using parent "%s", cell "%s".'%(str(parent), str(cell)) + raise Exception('Another graphical element is using parent "{}", cell "{}".'.format(str(parent), str(cell))) return e ######################### # Notebook Page Type ######################### elif t == 'notebook': - if not v: return '' #allow for empty notebook - #get a list of all notebooks + if not v: + # Allow for empty notebook + return '' + + # Get a list of all notebooks notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks()) - #check for notebook param syntax - try: notebook_id, page_index = map(str.strip, v.split(',')) - except: raise Exception, 'Bad notebook page format.' - #check that the notebook id is valid - try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] - except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id - #check that page index exists + # Check for notebook param syntax + try: + notebook_id, page_index = map(str.strip, v.split(',')) + except: + raise Exception('Bad notebook page format.') + # Check that the notebook id is valid + try: + notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] + except: + raise Exception('Notebook id "{}" is not an existing notebook id.'.format(notebook_id)) + + # Check that page index exists if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())): - raise Exception, 'Page index "%s" is not a valid index number.'%page_index + raise Exception('Page index "{}" is not a valid index number.'.format(page_index)) return notebook_id, page_index + ######################### # Import Type ######################### elif t == 'import': - n = dict() #new namespace - try: exec v in n - except ImportError: raise Exception, 'Import "%s" failed.'%v - except Exception: raise Exception, 'Bad import syntax: "%s".'%v + # New namespace + n = dict() + try: + exec v in n + except ImportError: + raise Exception('Import "{}" failed.'.format(v)) + except Exception: + raise Exception('Bad import syntax: "{}".'.format(v)) return filter(lambda k: str(k) != '__builtins__', n.keys()) + ######################### - else: raise TypeError, 'Type "%s" not handled'%t + else: + raise TypeError('Type "{}" not handled'.format(t)) def to_code(self): """ @@ -515,15 +612,24 @@ class Param(Element): """ v = self.get_value() t = self.get_type() - if t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): # string types - if not self._init: self.evaluate() - if self._stringify_flag: return '"%s"'%v.replace('"', '\"') - else: return v - elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): #vector types - if not self._init: self.evaluate() - if self._lisitify_flag: return '(%s, )'%v - else: return '(%s)'%v - else: return v + # String types + if t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): + if not self._init: + self.evaluate() + if self._stringify_flag: + return '"%s"' % v.replace('"', '\"') + else: + return v + # Vector types + elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): + if not self._init: + self.evaluate() + if self._lisitify_flag: + return '(%s, )' % v + else: + return '(%s)' % v + else: + return v def get_all_params(self, type): """ @@ -537,7 +643,8 @@ class Param(Element): """ return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], []) - def is_enum(self): return self._type == 'enum' + def is_enum(self): + return self._type == 'enum' def get_value(self): value = self._value @@ -546,34 +653,54 @@ class Param(Element): self.set_value(value) return value - def set_value(self, value): self._value = str(value) #must be a string + def set_value(self, value): + # Must be a string + self._value = str(value) def value_is_default(self): return self._default == self._value - def get_type(self): return self.get_parent().resolve_dependencies(self._type) - def get_tab_label(self): return self._tab_label + def get_type(self): + return self.get_parent().resolve_dependencies(self._type) + + def get_tab_label(self): + return self._tab_label + + def is_param(self): + return True + + def get_name(self): + return self.get_parent().resolve_dependencies(self._name).strip() - def is_param(self): return True - def get_name(self): return self.get_parent().resolve_dependencies(self._name).strip() - def get_key(self): return self._key + def get_key(self): + return self._key ############################################## # Access Options ############################################## - 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 + 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.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() + 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 + # Import/Export Methods ############################################## def export_data(self): """ diff --git a/grc/model/ParseXML.py b/grc/model/ParseXML.py index cd65fa1c89..adf5cc97b7 100644 --- a/grc/model/ParseXML.py +++ b/grc/model/ParseXML.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -41,7 +41,7 @@ def validate_dtd(xml_file, dtd_file=None): dtd_file: the optional dtd file @throws Exception validation fails """ - # perform parsing, use dtd validation if dtd file is not specified + # Perform parsing, use dtd validation if dtd file is not specified parser = etree.XMLParser(dtd_validation=not dtd_file) try: xml = etree.parse(xml_file, parser=parser) @@ -50,7 +50,7 @@ def validate_dtd(xml_file, dtd_file=None): if parser.error_log: raise XMLSyntaxError(parser.error_log) - # perform dtd validation if the dtd file is specified + # Perform dtd validation if the dtd file is specified if not dtd_file: return try: @@ -99,9 +99,11 @@ def _from_file(xml): nested_data = odict() for elem in xml: key, value = _from_file(elem).items()[0] - if nested_data.has_key(key): nested_data[key].append(value) - else: nested_data[key] = [value] - # delistify if the length of values is 1 + if key in nested_data: + nested_data[key].append(value) + else: + nested_data[key] = [value] + # Delistify if the length of values is 1 for key, values in nested_data.iteritems(): if len(values) == 1: nested_data[key] = values[0] @@ -119,7 +121,8 @@ def to_file(nested_data, xml_file): """ xml_data = "" instructions = nested_data.pop('_instructions', None) - if instructions: # create the processing instruction from the array + # Create the processing instruction from the array + if instructions: xml_data += etree.tostring(etree.ProcessingInstruction( 'grc', ' '.join( "{0}='{1}'".format(*item) for item in instructions.iteritems()) @@ -142,7 +145,7 @@ def _to_file(nested_data): """ nodes = list() for key, values in nested_data.iteritems(): - # listify the values if not a list + # Listify the values if not a list if not isinstance(values, (list, set, tuple)): values = [values] for value in values: diff --git a/grc/model/Platform.py b/grc/model/Platform.py index 0ac301f368..c08a8edb22 100644 --- a/grc/model/Platform.py +++ b/grc/model/Platform.py @@ -55,7 +55,7 @@ class Platform(Element): website: the website url for this platform """ - # ensure hier and conf directories + # Ensure hier and conf directories if not os.path.exists(HIER_BLOCKS_LIB_DIR): os.mkdir(HIER_BLOCKS_LIB_DIR) if not os.path.exists(os.path.dirname(PREFS_FILE)): @@ -87,7 +87,7 @@ class Platform(Element): self._default_flow_graph = DEFAULT_FLOW_GRAPH self._generator = Generator self._colors = [(name, color) for name, key, sizeof, color in CORE_TYPES] - #create a dummy flow graph for the blocks + # Create a dummy flow graph for the blocks self._flow_graph = Element(self) self._blocks = None @@ -161,41 +161,40 @@ class Platform(Element): try: flow_graph = self.get_new_flow_graph() flow_graph.grc_file_path = file_path - # other, nested higiter_blocks might be auto-loaded here + # Other, nested higiter_blocks might be auto-loaded here flow_graph.import_data(self.parse_flow_graph(file_path)) flow_graph.rewrite() flow_graph.validate() if not flow_graph.is_valid(): raise Exception('Flowgraph invalid') except Exception as e: - Messages.send('>>> Load Error: %r: %s\n' % (file_path, str(e))) + Messages.send('>>> Load Error: {}: {}\n'.format(file_path, str(e))) return False finally: self._auto_hier_block_generate_chain.discard(file_path) Messages.set_indent(len(self._auto_hier_block_generate_chain)) try: - Messages.send('>>> Generating: %r\n' % file_path) + Messages.send('>>> Generating: {}\n'.format(file_path)) generator = self.get_generator()(flow_graph, file_path) generator.write() except Exception as e: - Messages.send('>>> Generate Error: %r: %s\n' % (file_path, str(e))) + Messages.send('>>> Generate Error: {}: {}\n'.format(file_path, str(e))) return False self.load_block_xml(generator.get_file_path_xml()) return True - def _load_blocks(self): """load the blocks and block tree from the search paths""" - # reset + # Reset self._blocks = odict() self._blocks_n = odict() self._category_trees_n = list() self._domains.clear() self._connection_templates.clear() ParseXML.xml_failures.clear() - # try to parse and load blocks + # Try to parse and load blocks for xml_file in self.iter_xml_files(): try: if xml_file.endswith("block_tree.xml"): @@ -212,8 +211,7 @@ class Platform(Element): def iter_xml_files(self): """Iterator for block descriptions and category trees""" - get_path = lambda x: os.path.abspath(os.path.expanduser(x)) - for block_path in map(get_path, self._block_paths): + for block_path in map(lambda x: os.path.abspath(os.path.expanduser(x)), self._block_paths): if os.path.isfile(block_path): yield block_path elif os.path.isdir(block_path): @@ -223,16 +221,16 @@ class Platform(Element): def _load_block_xml(self, xml_file): """Load block description from xml file""" - # validate and import + # Validate and import ParseXML.validate_dtd(xml_file, self._block_dtd) n = ParseXML.from_file(xml_file).find('block') n['block_wrapper_path'] = xml_file # inject block wrapper path - # get block instance and add it to the list of blocks + # Get block instance and add it to the list of blocks block = self.Block(self._flow_graph, n) key = block.get_key() if key in self._blocks: - print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file) - else: # store the block + print >> sys.stderr, 'Warning: Block with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) + else: # Store the block self._blocks[key] = block self._blocks_n[key] = n return block @@ -250,14 +248,17 @@ class Platform(Element): key = n.find('key') if not key: - print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: %s' % xml_file + print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {}'.foramt(xml_file) return if key in self.get_domains(): # test against repeated keys - print >> sys.stderr, 'Warning: Domain with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file) + print >> sys.stderr, 'Warning: Domain with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) return - to_bool = lambda s, d: d if s is None else \ - s.lower() not in ('false', 'off', '0', '') + #to_bool = lambda s, d: d if s is None else s.lower() not in ('false', 'off', '0', '') + def to_bool(s, d): + if s is not None: + return s.lower() not in ('false', 'off', '0', '') + return d color = n.find('color') or '' try: @@ -265,7 +266,7 @@ class Platform(Element): gtk.gdk.color_parse(color) except (ValueError, ImportError): if color: # no color is okay, default set in GUI - print >> sys.stderr, 'Warning: Can\'t parse color code "%s" for domain "%s" ' % (color, key) + print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key) color = None self._domains[key] = dict( @@ -277,9 +278,9 @@ class Platform(Element): for connection_n in n.findall('connection'): key = (connection_n.find('source_domain'), connection_n.find('sink_domain')) if not all(key): - print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t%s' % xml_file + print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t{}'.format(xml_file) elif key in self._connection_templates: - print >> sys.stderr, 'Warning: Connection template "%s" already exists.\n\t%s' % (key, xml_file) + print >> sys.stderr, 'Warning: Connection template "{}" already exists.\n\t{}'.format(key, xml_file) else: self._connection_templates[key] = connection_n.find('make') or '' @@ -296,7 +297,7 @@ class Platform(Element): @throws exception if the validation fails """ flow_graph_file = flow_graph_file or self._default_flow_graph - open(flow_graph_file, 'r') # test open + open(flow_graph_file, 'r') # Test open ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD) return ParseXML.from_file(flow_graph_file) @@ -309,63 +310,99 @@ class Platform(Element): Args: block_tree: the block tree object """ - #recursive function to load categories and blocks + # Recursive function to load categories and blocks def load_category(cat_n, parent=None): - #add this category + # Add this category parent = (parent or []) + [cat_n.find('name')] block_tree.add_block(parent) - #recursive call to load sub categories + # Recursive call to load sub categories map(lambda c: load_category(c, parent), cat_n.findall('cat')) - #add blocks in this category + # Add blocks in this category for block_key in cat_n.findall('block'): if block_key not in self.get_block_keys(): - print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.' % (block_key) + print >> sys.stderr, 'Warning: Block key "{}" not found when loading category tree.'.format(block_key) continue block = self.get_block(block_key) - #if it exists, the block's category shall not be overridden by the xml tree + # If it exists, the block's category shall not be overridden by the xml tree if not block.get_category(): block.set_category(parent) - # recursively load the category trees and update the categories for each block + # Recursively load the category trees and update the categories for each block for category_tree_n in self._category_trees_n: load_category(category_tree_n) - #add blocks to block tree + # Add blocks to block tree for block in self.get_blocks(): - #blocks with empty categories are hidden - if not block.get_category(): continue + # Blocks with empty categories are hidden + if not block.get_category(): + continue block_tree.add_block(block.get_category(), block) - def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name()) + def __str__(self): + return 'Platform - {}({})'.format(self.get_key(), self.get_name()) - def is_platform(self): return True + def is_platform(self): + return True - def get_new_flow_graph(self): return self.FlowGraph(platform=self) + def get_new_flow_graph(self): + return self.FlowGraph(platform=self) - def get_generator(self): return self._generator + def get_generator(self): + return self._generator ############################################## # Access Blocks ############################################## - def get_block_keys(self): return self._blocks.keys() - def get_block(self, key): return self._blocks[key] - def get_blocks(self): return self._blocks.values() + def get_block_keys(self): + return self._blocks.keys() + + def get_block(self, key): + return self._blocks[key] + + def get_blocks(self): + return self._blocks.values() + def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key]) - def get_domains(self): return self._domains - def get_domain(self, key): return self._domains.get(key) - def get_connection_templates(self): return self._connection_templates - - def get_name(self): return self._name - def get_version(self): return self._version - def get_version_major(self): return self._version_major - def get_version_api(self): return self._version_api - def get_version_minor(self): return self._version_minor - def get_version_short(self): return self._version_short - - def get_key(self): return self._key - def get_license(self): return self._license - def get_website(self): return self._website - def get_colors(self): return self._colors - def get_block_paths(self): return self._block_paths + def get_domains(self): + return self._domains + + def get_domain(self, key): + return self._domains.get(key) + + def get_connection_templates(self): + return self._connection_templates + + def get_name(self): + return self._name + + def get_version(self): + return self._version + + def get_version_major(self): + return self._version_major + + def get_version_api(self): + return self._version_api + + def get_version_minor(self): + return self._version_minor + + def get_version_short(self): + return self._version_short + + def get_key(self): + return self._key + + def get_license(self): + return self._license + + def get_website(self): + return self._website + + def get_colors(self): + return self._colors + + def get_block_paths(self): + return self._block_paths diff --git a/grc/model/Port.py b/grc/model/Port.py index 7197f75d31..ede77353c7 100644 --- a/grc/model/Port.py +++ b/grc/model/Port.py @@ -28,9 +28,11 @@ def _get_source_from_virtual_sink_port(vsp): Resolve the source port that is connected to the given virtual sink port. Use the get source from virtual source to recursively resolve subsequent ports. """ - try: return _get_source_from_virtual_source_port( - vsp.get_enabled_connections()[0].get_source()) - except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp + try: + return _get_source_from_virtual_source_port( + vsp.get_enabled_connections()[0].get_source()) + except: + raise Exception('Could not resolve source for virtual sink port {}'.format(vsp)) def _get_source_from_virtual_source_port(vsp, traversed=[]): @@ -38,20 +40,24 @@ def _get_source_from_virtual_source_port(vsp, traversed=[]): Recursively resolve source ports over the virtual connections. Keep track of traversed sources to avoid recursive loops. """ - if not vsp.get_parent().is_virtual_source(): return vsp - if vsp in traversed: raise Exception, 'Loop found when resolving virtual source %s'%vsp - try: return _get_source_from_virtual_source_port( - _get_source_from_virtual_sink_port( - filter(#get all virtual sinks with a matching stream id - lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), - filter(#get all enabled blocks that are also virtual sinks - lambda b: b.is_virtual_sink(), - vsp.get_parent().get_parent().get_enabled_blocks(), - ), - )[0].get_sinks()[0] - ), traversed + [vsp], - ) - except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp + if not vsp.get_parent().is_virtual_source(): + return vsp + if vsp in traversed: + raise Exception('Loop found when resolving virtual source {}'.format(vsp)) + try: + return _get_source_from_virtual_source_port( + _get_source_from_virtual_sink_port( + filter( # Get all virtual sinks with a matching stream id + lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), + filter( # Get all enabled blocks that are also virtual sinks + lambda b: b.is_virtual_sink(), + vsp.get_parent().get_parent().get_enabled_blocks(), + ), + )[0].get_sinks()[0] + ), traversed + [vsp], + ) + except: + raise Exception('Could not resolve source for virtual source port {}'.format(vsp)) def _get_sink_from_virtual_source_port(vsp): @@ -59,9 +65,12 @@ def _get_sink_from_virtual_source_port(vsp): Resolve the sink port that is connected to the given virtual source port. Use the get sink from virtual sink to recursively resolve subsequent ports. """ - try: return _get_sink_from_virtual_sink_port( - vsp.get_enabled_connections()[0].get_sink()) # Could have many connections, but use first - except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp + try: + # Could have many connections, but use first + return _get_sink_from_virtual_sink_port( + vsp.get_enabled_connections()[0].get_sink()) + except: + raise Exception('Could not resolve source for virtual source port {}'.format(vsp)) def _get_sink_from_virtual_sink_port(vsp, traversed=[]): @@ -69,20 +78,24 @@ def _get_sink_from_virtual_sink_port(vsp, traversed=[]): Recursively resolve sink ports over the virtual connections. Keep track of traversed sinks to avoid recursive loops. """ - if not vsp.get_parent().is_virtual_sink(): return vsp - if vsp in traversed: raise Exception, 'Loop found when resolving virtual sink %s'%vsp - try: return _get_sink_from_virtual_sink_port( - _get_sink_from_virtual_source_port( - filter(#get all virtual source with a matching stream id - lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), - filter(#get all enabled blocks that are also virtual sinks - lambda b: b.is_virtual_source(), - vsp.get_parent().get_parent().get_enabled_blocks(), - ), - )[0].get_sources()[0] - ), traversed + [vsp], - ) - except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp + if not vsp.get_parent().is_virtual_sink(): + return vsp + if vsp in traversed: + raise Exception('Loop found when resolving virtual sink {}'.format(vsp)) + try: + return _get_sink_from_virtual_sink_port( + _get_sink_from_virtual_source_port( + filter( # Get all virtual source with a matching stream id + lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), + filter( # Get all enabled blocks that are also virtual sinks + lambda b: b.is_virtual_source(), + vsp.get_parent().get_parent().get_enabled_blocks(), + ), + )[0].get_sources()[0] + ), traversed + [vsp], + ) + except: + raise Exception('Could not resolve source for virtual sink port {}'.format(vsp)) class Port(Element): @@ -103,49 +116,50 @@ class Port(Element): n['domain'] = DEFAULT_DOMAIN elif n['domain'] == GR_MESSAGE_DOMAIN: n['key'] = n['name'] - n['type'] = 'message' # for port color + n['type'] = 'message' # For port color if n['type'] == 'msg': n['key'] = 'msg' if not n.find('key'): n['key'] = str(next(block.port_counters[dir == 'source'])) - #build the port + # Build the port Element.__init__(self, block) - #grab the data + # Grab the data self._name = n['name'] self._key = n['key'] self._type = n['type'] self._domain = n['domain'] self._hide = n.find('hide') or '' self._dir = dir - self._hide_evaluated = False # updated on rewrite() + self._hide_evaluated = False # Updated on rewrite() self._nports = n.find('nports') or '' self._vlen = n.find('vlen') or '' self._optional = bool(n.find('optional')) - 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 - %s(%s)'%(self.get_name(), self.get_key()) + return 'Source - {}({})'.format(self.get_name(), self.get_key()) if self.is_sink(): - return 'Sink - %s(%s)'%(self.get_name(), self.get_key()) + return 'Sink - {}({})'.format(self.get_name(), self.get_key()) + def get_types(self): + return Constants.TYPE_TO_SIZEOF.keys() - def get_types(self): return Constants.TYPE_TO_SIZEOF.keys() - - def is_type_empty(self): return not self._n['type'] + def is_type_empty(self): + return not self._n['type'] def validate(self): Element.validate(self) if self.get_type() not in self.get_types(): - self.add_error_message('Type "%s" is not a possible type.' % self.get_type()) + 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.get_domains(): - self.add_error_message('Domain key "%s" is not registered.' % self.get_domain()) + self.add_error_message('Domain key "{}" is not registered.'.format(self.get_domain())) if not self.get_enabled_connections() and not self.get_optional(): self.add_error_message('Port is not connected.') - #message port logic + # Message port logic if self.get_type() == 'msg': if self.get_nports(): self.add_error_message('A port of type "msg" cannot have "nports" set.') @@ -157,44 +171,54 @@ class Port(Element): Handle the port cloning for virtual blocks. """ if self.is_type_empty(): - try: #clone type and vlen + try: + # Clone type and vlen source = self.resolve_empty_type() self._type = str(source.get_type()) self._vlen = str(source.get_vlen()) - except: #reset type and vlen + except: + # Reset type and vlen self._type = '' self._vlen = '' Element.rewrite(self) hide = self.get_parent().resolve_dependencies(self._hide).strip().lower() self._hide_evaluated = False if hide in ('false', 'off', '0') else bool(hide) - # update domain if was deduced from (dynamic) port type + # 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() + self._key = '0' # Is rectified in rewrite() def resolve_virtual_source(self): - if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self) - if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self) + if self.get_parent().is_virtual_sink(): + return _get_source_from_virtual_sink_port(self) + if self.get_parent().is_virtual_source(): + return _get_source_from_virtual_source_port(self) def resolve_empty_type(self): if self.is_sink(): try: src = _get_source_from_virtual_sink_port(self) - if not src.is_type_empty(): return src - except: pass + if not src.is_type_empty(): + return src + except: + pass sink = _get_sink_from_virtual_sink_port(self) - if not sink.is_type_empty(): return sink + if not sink.is_type_empty(): + return sink if self.is_source(): try: src = _get_source_from_virtual_source_port(self) - if not src.is_type_empty(): return src - except: pass + if not src.is_type_empty(): + return src + except: + pass sink = _get_sink_from_virtual_source_port(self) - if not sink.is_type_empty(): return sink + if not sink.is_type_empty(): + return sink def get_vlen(self): """ @@ -205,8 +229,10 @@ class Port(Element): the vector length or 1 """ vlen = self.get_parent().resolve_dependencies(self._vlen) - try: return int(self.get_parent().get_parent().evaluate(vlen)) - except: return 1 + try: + return int(self.get_parent().get_parent().evaluate(vlen)) + except: + return 1 def get_nports(self): """ @@ -217,7 +243,8 @@ class Port(Element): Returns: the number of ports or 1 """ - if self._nports == '': return '' + if self._nports == '': + return '' nports = self.get_parent().resolve_dependencies(self._nports) try: @@ -225,7 +252,8 @@ class Port(Element): except: return 1 - def get_optional(self): return bool(self._optional) + def get_optional(self): + return bool(self._optional) def get_color(self): """ @@ -238,7 +266,8 @@ class Port(Element): try: color = Constants.TYPE_TO_COLOR[self.get_type()] vlen = self.get_vlen() - if vlen == 1: return color + if vlen == 1: + return color color_val = int(color[1:], 16) r = (color_val >> 16) & 0xff g = (color_val >> 8) & 0xff @@ -247,7 +276,8 @@ class Port(Element): r = max(r-dark, 0) g = max(g-dark, 0) b = max(b-dark, 0) - return '#%.2x%.2x%.2x'%(r, g, b) + # TODO: Change this to .format() + return '#%.2x%.2x%.2x' % (r, g, b) except: return '#FFFFFF' @@ -270,19 +300,24 @@ class Port(Element): Returns: the cloned port """ - # add index to master port name if there are no clones yet + # 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._key.isdigit(): # also update key for none stream ports + # 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() - if 'nports' in n: n.pop('nports') # remove nports from the key so the copy cannot be a duplicator + # 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) - n['key'] = '99999' if self._key.isdigit() else n['name'] # dummy value 99999 will be fixed later + # Dummy value 99999 will be fixed later + n['key'] = '99999' if self._key.isdigit() else n['name'] - port = self.__class__(self.get_parent(), n, self._dir) # clone + # Clone + port = self.__class__(self.get_parent(), n, self._dir) self._clones.append(port) return port @@ -292,10 +327,11 @@ class Port(Element): Remove the index 0 of the master port name (and key9 if there are no more clones left """ self._clones.remove(port) - # remove index from master port name if there are no more clones + # Remove index from master port name if there are no more clones if not self._clones: self._name = self._n['name'] - if not self._key.isdigit(): # also update key for none stream ports + # Also update key for none stream ports + if not self._key.isdigit(): self._key = self._name def get_name(self): @@ -305,13 +341,26 @@ class Port(Element): number = str(busses.index(self)) + '#' + str(len(self.get_associated_ports())) return self._name + number - def get_key(self): return self._key - def is_sink(self): return self._dir == 'sink' - def is_source(self): return self._dir == 'source' - def is_port(self): return True - def get_type(self): return self.get_parent().resolve_dependencies(self._type) - def get_domain(self): return self._domain - def get_hide(self): return self._hide_evaluated + def get_key(self): + return self._key + + def is_sink(self): + return self._dir == 'sink' + + def is_source(self): + return self._dir == 'source' + + def is_port(self): + return True + + def get_type(self): + return self.get_parent().resolve_dependencies(self._type) + + def get_domain(self): + return self._domain + + def get_hide(self): + return self._hide_evaluated def get_connections(self): """ diff --git a/grc/model/expr_utils.py b/grc/model/expr_utils.py index 9e0b2a4a0a..66911757d6 100644 --- a/grc/model/expr_utils.py +++ b/grc/model/expr_utils.py @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import string VAR_CHARS = string.letters + string.digits + '_' + class graph(object): """ Simple graph structure held in a dictionary. @@ -30,13 +31,16 @@ class graph(object): def __str__(self): return str(self._graph) def add_node(self, node_key): - if self._graph.has_key(node_key): return + if node_key in self._graph: + return self._graph[node_key] = set() def remove_node(self, node_key): - if not self._graph.has_key(node_key): return + if node_key not in self._graph: + return for edges in self._graph.values(): - if node_key in edges: edges.remove(node_key) + if node_key in edges: + edges.remove(node_key) self._graph.pop(node_key) def add_edge(self, src_node_key, dest_node_key): @@ -45,9 +49,12 @@ class graph(object): def remove_edge(self, src_node_key, dest_node_key): self._graph[src_node_key].remove(dest_node_key) - def get_nodes(self): return self._graph.keys() + def get_nodes(self): + return self._graph.keys() + + def get_edges(self, node_key): + return self._graph[node_key] - def get_edges(self, node_key): return self._graph[node_key] def expr_split(expr): """ @@ -66,7 +73,8 @@ def expr_split(expr): quote = '' for char in expr: if quote or char in VAR_CHARS: - if char == quote: quote = '' + if char == quote: + quote = '' tok += char elif char in ("'", '"'): toks.append(tok) @@ -79,6 +87,7 @@ def expr_split(expr): toks.append(tok) return filter(lambda t: t, toks) + def expr_replace(expr, replace_dict): """ Search for vars in the expression and add the prepend. @@ -96,6 +105,7 @@ def expr_replace(expr, replace_dict): expr_splits[i] = replace_dict[es] return ''.join(expr_splits) + def get_variable_dependencies(expr, vars): """ Return a set of variables used in this expression. @@ -110,6 +120,7 @@ def get_variable_dependencies(expr, vars): expr_toks = expr_split(expr) return set(filter(lambda v: v in expr_toks, vars)) + def get_graph(exprs): """ Get a graph representing the variable dependencies @@ -121,14 +132,17 @@ def get_graph(exprs): a graph of variable deps """ vars = exprs.keys() - #get dependencies for each expression, load into graph + # Get dependencies for each expression, load into graph var_graph = graph() - for var in vars: var_graph.add_node(var) + for var in vars: + var_graph.add_node(var) for var, expr in exprs.iteritems(): for dep in get_variable_dependencies(expr, vars): - if dep != var: var_graph.add_edge(dep, var) + if dep != var: + var_graph.add_edge(dep, var) return var_graph + def sort_variables(exprs): """ Get a list of variables in order of dependencies. @@ -142,17 +156,20 @@ def sort_variables(exprs): """ var_graph = get_graph(exprs) sorted_vars = list() - #determine dependency order + # Determine dependency order while var_graph.get_nodes(): - #get a list of nodes with no edges + # Get a list of nodes with no edges indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes()) - if not indep_vars: raise Exception('circular dependency caught in sort_variables') - #add the indep vars to the end of the list + if not indep_vars: + raise Exception('circular dependency caught in sort_variables') + # Add the indep vars to the end of the list sorted_vars.extend(sorted(indep_vars)) - #remove each edge-less node from the graph - for var in indep_vars: var_graph.remove_node(var) + # Remove each edge-less node from the graph + for var in indep_vars: + var_graph.remove_node(var) return reversed(sorted_vars) + def sort_objects(objects, get_id, get_expr): """ Sort a list of objects according to their expressions. @@ -166,12 +183,14 @@ def sort_objects(objects, get_id, get_expr): a list of sorted objects """ id2obj = dict([(get_id(obj), obj) for obj in objects]) - #map obj id to expression code + # Map obj id to expression code id2expr = dict([(get_id(obj), get_expr(obj)) for obj in objects]) - #sort according to dependency + # Sort according to dependency sorted_ids = sort_variables(id2expr) - #return list of sorted objects + # Return list of sorted objects return [id2obj[id] for id in sorted_ids] + if __name__ == '__main__': - for i in sort_variables({'x':'1', 'y':'x+1', 'a':'x+y', 'b':'y+1', 'c':'a+b+x+y'}): print i + for i in sort_variables({'x': '1', 'y': 'x+1', 'a': 'x+y', 'b': 'y+1', 'c': 'a+b+x+y'}): + print i diff --git a/grc/model/extract_docs.py b/grc/model/extract_docs.py index 7c149ce593..a6e0bc971e 100644 --- a/grc/model/extract_docs.py +++ b/grc/model/extract_docs.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2011 Free Software Foundation, Inc. +Copyright 2008-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -32,8 +32,8 @@ import itertools ############################################################################### def docstring_guess_from_key(key): - """Extract the documentation from the python __doc__ strings - + """ + Extract the documentation from the python __doc__ strings By guessing module and constructor names from key Args: @@ -65,9 +65,7 @@ def docstring_guess_from_key(key): else: return doc_strings - pattern = re.compile( - '^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$' - ) + pattern = re.compile('^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$') for match in filter(pattern.match, dir(module)): try: doc_strings[match] = getattr(module, match).__doc__ @@ -78,8 +76,8 @@ def docstring_guess_from_key(key): def docstring_from_make(key, imports, make): - """Extract the documentation from the python __doc__ strings - + """ + Extract the documentation from the python __doc__ strings By importing it and checking a truncated make Args: @@ -95,12 +93,10 @@ def docstring_from_make(key, imports, make): blk_cls = make.partition('(')[0].strip() if '$' in blk_cls: raise ValueError('Not an identifier') - ns = dict() for _import in imports: exec(_import.strip(), ns) blk = eval(blk_cls, ns) - doc_strings = {key: blk.__doc__} except (ImportError, AttributeError, SyntaxError, ValueError): @@ -114,10 +110,11 @@ def docstring_from_make(key, imports, make): ############################################################################### class SubprocessLoader(object): - """Start and manage docstring extraction process - + """ + Start and manage docstring extraction process Manages subprocess and handles RPC. """ + BOOTSTRAP = "import runpy; runpy.run_path({!r}, run_name='__worker__')" AUTH_CODE = random.random() # sort out unwanted output of worker process RESTART = 5 # number of worker restarts before giving up @@ -134,7 +131,7 @@ class SubprocessLoader(object): self._last_cmd = None def start(self): - """Start the worker process handler thread""" + """ Start the worker process handler thread """ if self._thread is not None: return self._shutdown.clear() @@ -143,7 +140,7 @@ class SubprocessLoader(object): thread.start() def run_worker(self): - """Read docstring back from worker stdout and execute callback.""" + """ Read docstring back from worker stdout and execute callback. """ for _ in range(self.RESTART): if self._shutdown.is_set(): break @@ -173,7 +170,7 @@ class SubprocessLoader(object): self.callback_finished() def _handle_worker(self): - """Send commands and responses back from worker.""" + """ Send commands and responses back from worker. """ assert '1' == self._worker.stdout.read(1) for cmd, args in iter(self._queue.get, self.DONE): self._last_cmd = cmd, args @@ -182,13 +179,13 @@ class SubprocessLoader(object): self._handle_response(cmd, args) def _send(self, cmd, args): - """send a command to worker's stdin""" + """ Send a command to worker's stdin """ fd = self._worker.stdin json.dump((self.AUTH_CODE, cmd, args), fd) fd.write('\n'.encode()) def _receive(self): - """receive response from worker's stdout""" + """ Receive response from worker's stdout """ for line in iter(self._worker.stdout.readline, ''): try: key, cmd, args = json.loads(line, encoding='utf-8') @@ -201,7 +198,7 @@ class SubprocessLoader(object): raise IOError("Can't read worker response") def _handle_response(self, cmd, args): - """Handle response from worker, call the callback""" + """ Handle response from worker, call the callback """ if cmd == 'result': key, docs = args self.callback_query_result(key, docs) @@ -211,7 +208,7 @@ class SubprocessLoader(object): print >> sys.stderr, "Unknown response:", cmd, args def query(self, key, imports=None, make=None): - """request docstring extraction for a certain key""" + """ Request docstring extraction for a certain key """ if self._thread is None: self.start() if imports and make: @@ -220,16 +217,16 @@ class SubprocessLoader(object): self._queue.put(('query_key_only', (key,))) def finish(self): - """signal end of requests""" + """ Signal end of requests """ self._queue.put(self.DONE) def wait(self): - """Wait for the handler thread to die""" + """ Wait for the handler thread to die """ if self._thread: self._thread.join() def terminate(self): - """Terminate the worker and wait""" + """ Terminate the worker and wait """ self._shutdown.set() try: self._worker.terminate() @@ -243,8 +240,8 @@ class SubprocessLoader(object): ############################################################################### def worker_main(): - """Main entry point for the docstring extraction process. - + """ + Main entry point for the docstring extraction process. Manages RPC with main process through. Runs a docstring extraction for each key it read on stdin. """ diff --git a/grc/model/odict.py b/grc/model/odict.py index 70ab67d053..20970e947c 100644 --- a/grc/model/odict.py +++ b/grc/model/odict.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2011 Free Software Foundation, Inc. +Copyright 2008-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from UserDict import DictMixin + class odict(DictMixin): def __init__(self, d={}): @@ -57,7 +58,8 @@ class odict(DictMixin): val: the value for the new entry """ index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key) - if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key)) + if key in self._keys: + raise KeyError('Cannot insert, key "{}" already exists'.format(str(key))) self._keys.insert(index+1, key) self._data[key] = val @@ -72,7 +74,8 @@ class odict(DictMixin): val: the value for the new entry """ index = (pos_key is not None) and self._keys.index(pos_key) or 0 - if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key)) + if key in self._keys: + raise KeyError('Cannot insert, key "{}" already exists'.format(str(key))) self._keys.insert(index, key) self._data[key] = val @@ -86,7 +89,8 @@ class odict(DictMixin): Returns: the value or None """ - if self.has_key(key): return self[key] + if key in self: + return self[key] return None def findall(self, key): @@ -100,6 +104,8 @@ class odict(DictMixin): a list of values or empty list """ obj = self.find(key) - if obj is None: obj = list() - if isinstance(obj, list): return obj + if obj is None: + obj = list() + if isinstance(obj, list): + return obj return [obj] |