diff options
-rw-r--r-- | grc/core/Platform.py | 91 | ||||
-rw-r--r-- | grc/core/generator/FlowGraphProxy.py | 126 | ||||
-rw-r--r-- | grc/core/generator/Generator.py | 3 |
3 files changed, 164 insertions, 56 deletions
diff --git a/grc/core/Platform.py b/grc/core/Platform.py index 7aa1caedd1..40e3e9cd5e 100644 --- a/grc/core/Platform.py +++ b/grc/core/Platform.py @@ -38,21 +38,8 @@ class Platform(Element): is_platform = True def __init__(self): - """ - Make a platform for gnuradio. - - Args: - name: the platform name - version: the version string - key: the unique platform key - block_paths: the file paths to blocks in this platform - block_dtd: the dtd validator for xml block wrappers - default_flow_graph: the default flow graph file path - generator: the generator class for this platform - colors: a list of title, color_spec tuples - license: a multi-line license (first line is copyright) - website: the website url for this platform - """ + """ Make a platform for gnuradio """ + Element.__init__(self) # Ensure hier and conf directories if not os.path.exists(HIER_BLOCKS_LIB_DIR): @@ -68,7 +55,6 @@ class Platform(Element): callback_finished=lambda: self.block_docstrings_loaded_callback() ) - Element.__init__(self) self._name = 'GNU Radio Companion' # Save the version string to the first version = (gr.version(), gr.major_version(), gr.api_version(), gr.minor_version()) @@ -97,43 +83,9 @@ class Platform(Element): self._connection_templates = dict() self.load_blocks() + _move_old_pref_file() self._auto_hier_block_generate_chain = set() - def _save_docstring_extraction_result(self, key, docstrings): - docs = {} - for match, docstring in docstrings.iteritems(): - if not docstring or match.endswith('_sptr'): - continue - docstring = docstring.replace('\n\n', '\n').strip() - docs[match] = docstring - self.block_docstrings[key] = docs - - @staticmethod - def _move_old_pref_file(): - if PREFS_FILE == PREFS_FILE_OLD: - return # prefs file overridden with env var - if os.path.exists(PREFS_FILE_OLD) and not os.path.exists(PREFS_FILE): - try: - import shutil - shutil.move(PREFS_FILE_OLD, PREFS_FILE) - except Exception as e: - print >> sys.stderr, e - - def load_blocks(self): - self._docstring_extractor.start() - self._load_blocks() - self._docstring_extractor.finish() - # self._docstring_extractor.wait() - - def load_block_xml(self, xml_file): - block = self._load_block_xml(self, xml_file) - self._docstring_extractor.query( - block.get_key(), - block.get_imports(raw=True), - block.get_make(raw=True) - ) - return block - @staticmethod def find_file_in_paths(filename, paths, cwd): """Checks the provided paths relative to cwd for a certain filename""" @@ -185,8 +137,9 @@ class Platform(Element): self.load_block_xml(generator.get_file_path_xml()) return True - def _load_blocks(self): + def load_blocks(self): """load the blocks and block tree from the search paths""" + self._docstring_extractor.start() # Reset self._blocks = odict() self._blocks_n = odict() @@ -202,7 +155,7 @@ class Platform(Element): elif xml_file.endswith('domain.xml'): self.load_domain_xml(xml_file) else: - self._load_block_xml(xml_file) + self.load_block_xml(xml_file) except ParseXML.XMLSyntaxError as e: # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file) pass @@ -210,6 +163,9 @@ class Platform(Element): raise print >> sys.stderr, 'Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file) + self._docstring_extractor.finish() + # self._docstring_extractor.wait() + def iter_xml_files(self): """Iterator for block descriptions and category trees""" for block_path in map(lambda x: os.path.abspath(os.path.expanduser(x)), self._block_paths): @@ -220,7 +176,7 @@ class Platform(Element): for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)): yield os.path.join(dirpath, filename) - def _load_block_xml(self, xml_file): + def load_block_xml(self, xml_file): """Load block description from xml file""" # Validate and import ParseXML.validate_dtd(xml_file, self._block_dtd) @@ -234,7 +190,21 @@ class Platform(Element): else: # Store the block self._blocks[key] = block self._blocks_n[key] = n - return block + + self._docstring_extractor.query( + block.get_key(), + block.get_imports(raw=True), + block.get_make(raw=True) + ) + + def _save_docstring_extraction_result(self, key, docstrings): + docs = {} + for match, docstring in docstrings.iteritems(): + if not docstring or match.endswith('_sptr'): + continue + docstring = docstring.replace('\n\n', '\n').strip() + docs[match] = docstring + self.block_docstrings[key] = docs def load_category_tree_xml(self, xml_file): """Validate and parse category tree file and add it to list""" @@ -404,3 +374,14 @@ class Platform(Element): def get_block_paths(self): return self._block_paths + + +def _move_old_pref_file(): + if PREFS_FILE == PREFS_FILE_OLD: + return # prefs file overridden with env var + if os.path.exists(PREFS_FILE_OLD) and not os.path.exists(PREFS_FILE): + try: + import shutil + shutil.move(PREFS_FILE_OLD, PREFS_FILE) + except Exception as e: + print >> sys.stderr, e diff --git a/grc/core/generator/FlowGraphProxy.py b/grc/core/generator/FlowGraphProxy.py new file mode 100644 index 0000000000..e0e28fc7b0 --- /dev/null +++ b/grc/core/generator/FlowGraphProxy.py @@ -0,0 +1,126 @@ +# 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 +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + +class FlowGraphProxy(object): + + def __init__(self, fg): + self._fg = fg + + def __getattr__(self, item): + return getattr(self._fg, item) + + def get_hier_block_stream_io(self, direction): + """ + Get a list of stream io signatures for this flow graph. + + Args: + direction: a string of 'in' or 'out' + + Returns: + a list of dicts with: type, label, vlen, size, optional + """ + return filter(lambda p: p['type'] != "message", self.get_hier_block_io(direction)) + + def get_hier_block_message_io(self, direction): + """ + Get a list of message io signatures for this flow graph. + + Args: + direction: a string of 'in' or 'out' + + Returns: + a list of dicts with: type, label, vlen, size, optional + """ + return filter(lambda p: p['type'] == "message", self.get_hier_block_io(direction)) + + def get_hier_block_io(self, direction): + """ + Get a list of io ports for this flow graph. + + Args: + direction: a string of 'in' or 'out' + + Returns: + a list of dicts with: type, label, vlen, size, optional + """ + pads = self.get_pad_sources() if direction in ('sink', 'in') else \ + self.get_pad_sinks() if direction in ('source', 'out') else [] + ports = [] + for pad in pads: + master = { + 'label': str(pad.get_param('label').get_evaluated()), + 'type': str(pad.get_param('type').get_evaluated()), + 'vlen': str(pad.get_param('vlen').get_value()), + 'size': pad.get_param('type').get_opt('size'), + 'optional': bool(pad.get_param('optional').get_evaluated()), + } + num_ports = pad.get_param('num_streams').get_evaluated() + if num_ports > 1: + for i in xrange(num_ports): + clone = master.copy() + clone['label'] += str(i) + ports.append(clone) + else: + ports.append(master) + return ports + + def get_pad_sources(self): + """ + Get a list of pad source blocks sorted by id order. + + Returns: + a list of pad source blocks in this flow graph + """ + pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks()) + return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) + + def get_pad_sinks(self): + """ + Get a list of pad sink blocks sorted by id order. + + Returns: + a list of pad sink blocks in this flow graph + """ + pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks()) + return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) + + def get_pad_port_global_key(self, port): + """ + Get the key for a port of a pad source/sink to use in connect() + This takes into account that pad blocks may have multiple ports + + Returns: + the key (str) + """ + key_offset = 0 + pads = self.get_pad_sources() if port.is_source else self.get_pad_sinks() + for pad in pads: + # using the block param 'type' instead of the port domain here + # to emphasize that hier block generation is domain agnostic + is_message_pad = pad.get_param('type').get_evaluated() == "message" + if port.get_parent() == pad: + if is_message_pad: + key = pad.get_param('label').get_value() + else: + key = str(key_offset + int(port.get_key())) + return key + else: + # assuming we have either only sources or sinks + if not is_message_pad: + key_offset += len(pad.get_ports()) + return -1
\ No newline at end of file diff --git a/grc/core/generator/Generator.py b/grc/core/generator/Generator.py index 4cb04bd4da..5ac8478471 100644 --- a/grc/core/generator/Generator.py +++ b/grc/core/generator/Generator.py @@ -28,6 +28,7 @@ from distutils.spawn import find_executable from Cheetah.Template import Template +from .FlowGraphProxy import FlowGraphProxy from .. import ParseXML from ..utils import expr_utils, odict from ..Constants import ( @@ -82,7 +83,7 @@ class TopBlockGenerator(object): flow_graph: the flow graph object file_path: the path to write the file to """ - self._flow_graph = flow_graph + self._flow_graph = FlowGraphProxy(flow_graph) self._generate_options = self._flow_graph.get_option('generate_options') self._mode = TOP_BLOCK_FILE_MODE dirname = self._dirname = os.path.dirname(file_path) |