commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 16/18: Merge remote-tracking branch 'upstre


From: git
Subject: [Commit-gnuradio] [gnuradio] 16/18: Merge remote-tracking branch 'upstream/master' into refactoring
Date: Sun, 24 Apr 2016 19:19:38 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch master
in repository gnuradio.

commit 8cfc8b3408916ccb156fc25102bc1d9346bc004b
Merge: 036264e bdf8517
Author: Sebastian Koslowski <address@hidden>
Date:   Fri Apr 15 21:02:51 2016 +0200

    Merge remote-tracking branch 'upstream/master' into refactoring

 RELEASE-NOTES.md                                   |  170 +-
 cmake/Modules/FindThrift.cmake                     |    6 +-
 cmake/Modules/GrVersion.cmake                      |    8 +-
 cmake/Modules/UseSWIG.cmake                        |    4 +-
 docs/RELEASE-NOTES-3.7.9.2.md                      |  132 +
 docs/doxygen/other/ctrlport.dox                    |    4 +-
 docs/exploring-gnuradio/fm_tx.grc                  |    4 +
 gnuradio-runtime/include/pmt/pmt.h                 |    4 +-
 gnuradio-runtime/lib/tpb_thread_body.cc            |    4 +-
 .../python/gnuradio/ctrlport/gr-perf-monitorx      |   57 +-
 gr-analog/examples/fmtest.py                       |    3 +-
 gr-analog/grc/analog_fm_preemph.xml                |    8 +-
 gr-analog/grc/analog_nbfm_tx.xml                   |    8 +
 gr-analog/grc/analog_wfm_tx.xml                    |    7 +
 gr-analog/lib/sig_source_X_impl.cc.t               |   32 +-
 gr-analog/lib/sig_source_X_impl.h.t                |    2 +-
 gr-analog/python/analog/fm_emph.py                 |  254 +-
 gr-analog/python/analog/nbfm_tx.py                 |    5 +-
 gr-analog/python/analog/wfm_tx.py                  |    5 +-
 gr-blocks/CMakeLists.txt                           |    1 +
 {grc/blocks => gr-blocks/grc}/blks2_error_rate.xml |    1 +
 {grc/blocks => gr-blocks/grc}/blks2_selector.xml   |    1 +
 {grc/blocks => gr-blocks/grc}/blks2_tcp_sink.xml   |    1 +
 {grc/blocks => gr-blocks/grc}/blks2_tcp_source.xml |    1 +
 {grc/blocks => gr-blocks/grc}/blks2_valve.xml      |    1 +
 gr-blocks/grc/blocks_block_tree.xml                |    7 +-
 {grc/blocks => gr-blocks/grc}/xmlrpc_client.xml    |    0
 {grc/blocks => gr-blocks/grc}/xmlrpc_server.xml    |    0
 gr-blocks/include/gnuradio/blocks/head.h           |    2 +-
 .../include/gnuradio/blocks/vector_source_X.h.t    |    1 +
 gr-blocks/lib/head_impl.h                          |    2 +-
 gr-blocks/lib/tagged_stream_align_impl.cc          |    1 +
 gr-blocks/lib/vector_source_X_impl.h.t             |    1 +
 gr-blocks/python/blocks/qa_vector_sink_source.py   |   36 +
 .../python}/grc_gnuradio/CMakeLists.txt            |    8 +-
 {grc => gr-blocks/python}/grc_gnuradio/README      |    0
 {grc => gr-blocks/python}/grc_gnuradio/__init__.py |    0
 .../python}/grc_gnuradio/blks2/__init__.py         |   10 +-
 .../python}/grc_gnuradio/blks2/error_rate.py       |    0
 .../python}/grc_gnuradio/blks2/selector.py         |    0
 .../python}/grc_gnuradio/blks2/tcp.py              |    0
 gr-digital/CMakeLists.txt                          |    1 +
 .../grc}/blks2_packet_decoder.xml                  |    1 +
 .../grc}/blks2_packet_encoder.xml                  |    1 +
 gr-digital/grc/digital_constellation.xml           |   51 +-
 gr-digital/lib/burst_shaper_XX_impl.cc.t           |   38 +-
 gr-digital/lib/correlate_access_code_bb_ts_impl.cc |    4 +-
 gr-digital/lib/correlate_access_code_ff_ts_impl.cc |    4 +-
 gr-digital/python/digital/qa_burst_shaper.py       |   60 +-
 .../digital/qa_correlate_access_code_XX_ts.py      |   90 +
 .../python}/grc_gnuradio/CMakeLists.txt            |   15 +-
 .../python}/grc_gnuradio/blks2/packet.py           |    0
 gr-fec/examples/ber_curve_gen_ldpc.grc             |   22 +-
 gr-fec/grc/fec_bercurve_generator.xml              |    9 +
 gr-fec/grc/ldpc_decoder_def_list.xml               |    6 +-
 gr-fec/grc/variable_ldpc_G_matrix_object.xml       |    2 +-
 gr-fec/grc/variable_ldpc_H_matrix_object.xml       |    2 +-
 gr-fec/grc/variable_ldpc_bit_flip_decoder.xml      |   12 +-
 gr-fec/grc/variable_ldpc_encoder_G.xml             |   11 +-
 gr-fec/grc/variable_ldpc_encoder_H.xml             |    6 +-
 gr-fec/include/gnuradio/fec/polar_decoder_common.h |    6 +-
 gr-fec/ldpc_alist/CMakeLists.txt                   |    4 +-
 gr-fec/ldpc_alist/n_2400_k_1198_gap_33.alist       | 3602 --------------------
 gr-fec/ldpc_alist/n_2400_k_1198_gen_matrix.alist   | 3602 --------------------
 gr-fec/lib/fec_mtrx_impl.cc                        |   13 +-
 gr-fec/lib/ldpc_G_matrix_impl.cc                   |   16 +-
 gr-fec/lib/ldpc_G_matrix_impl.h                    |    1 -
 gr-fec/lib/ldpc_H_matrix_impl.cc                   |   83 +-
 gr-fec/lib/ldpc_H_matrix_impl.h                    |    4 -
 gr-fec/python/fec/LDPC/Generate_LDPC_matrix.py     |    2 +-
 .../fec/LDPC/Generate_LDPC_matrix_functions.py     |   53 +-
 gr-fec/python/fec/bercurve_generator.py            |    6 +
 gr-fft/lib/CMakeLists.txt                          |    1 +
 gr-fft/lib/fft.cc                                  |   53 +-
 gr-filter/examples/synth_to_chan.py                |    2 +-
 gr-filter/include/gnuradio/filter/firdes.h         |  443 ++-
 gr-filter/lib/firdes.cc                            |   10 +-
 gr-qtgui/grc/qtgui_const_sink_x.xml                |   18 +
 gr-qtgui/grc/qtgui_freq_sink_x.xml                 |   18 +
 gr-qtgui/grc/qtgui_histogram_sink_x.xml            |   18 +
 gr-qtgui/grc/qtgui_time_raster_x.xml               |   17 +
 gr-qtgui/grc/qtgui_time_sink_x.xml                 |   18 +
 gr-qtgui/grc/qtgui_waterfall_sink_x.xml            |   18 +
 gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h      |    1 +
 gr-qtgui/include/gnuradio/qtgui/const_sink_c.h     |    1 +
 gr-qtgui/include/gnuradio/qtgui/displayform.h      |    3 +
 gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h      |    1 +
 gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h      |    1 +
 gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h |    1 +
 gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h  |    1 -
 gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h |    1 +
 .../include/gnuradio/qtgui/time_raster_sink_b.h    |    1 +
 .../include/gnuradio/qtgui/time_raster_sink_f.h    |    1 +
 gr-qtgui/include/gnuradio/qtgui/time_sink_c.h      |    1 +
 gr-qtgui/include/gnuradio/qtgui/time_sink_f.h      |    1 +
 gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h |    2 +
 gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h |    1 +
 gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h |    1 +
 gr-qtgui/lib/DisplayPlot.cc                        |    9 +
 gr-qtgui/lib/WaterfallDisplayPlot.cc               |    2 -
 gr-qtgui/lib/const_sink_c_impl.cc                  |    6 +
 gr-qtgui/lib/const_sink_c_impl.h                   |    1 +
 gr-qtgui/lib/displayform.cc                        |   16 +
 gr-qtgui/lib/freq_sink_c_impl.cc                   |    6 +
 gr-qtgui/lib/freq_sink_c_impl.h                    |    1 +
 gr-qtgui/lib/freq_sink_f_impl.cc                   |    6 +
 gr-qtgui/lib/freq_sink_f_impl.h                    |    1 +
 gr-qtgui/lib/freqcontrolpanel.cc                   |    5 +
 gr-qtgui/lib/histogram_sink_f_impl.cc              |    6 +
 gr-qtgui/lib/histogram_sink_f_impl.h               |    1 +
 gr-qtgui/lib/time_raster_sink_b_impl.cc            |    6 +
 gr-qtgui/lib/time_raster_sink_b_impl.h             |    1 +
 gr-qtgui/lib/time_raster_sink_f_impl.cc            |    6 +
 gr-qtgui/lib/time_raster_sink_f_impl.h             |    1 +
 gr-qtgui/lib/time_sink_c_impl.cc                   |   12 +-
 gr-qtgui/lib/time_sink_c_impl.h                    |    1 +
 gr-qtgui/lib/time_sink_f_impl.cc                   |    8 +-
 gr-qtgui/lib/time_sink_f_impl.h                    |    1 +
 gr-qtgui/lib/timecontrolpanel.cc                   |    5 +
 gr-qtgui/lib/waterfall_sink_c_impl.cc              |    6 +
 gr-qtgui/lib/waterfall_sink_c_impl.h               |    1 +
 gr-qtgui/lib/waterfall_sink_f_impl.cc              |    6 +
 gr-qtgui/lib/waterfall_sink_f_impl.h               |    1 +
 gr-uhd/apps/uhd_rx_cfile                           |   27 +-
 gr-uhd/examples/python/fm_tx4.py                   |    3 +-
 gr-uhd/grc/gen_uhd_usrp_blocks.py                  |    4 +-
 gr-utils/python/modtool/gr-newmod/CMakeLists.txt   |    7 +
 .../gr-newmod/cmake/Modules/GrMiscUtils.cmake      |    3 +
 gr-utils/python/modtool/modtool_add.py             |   14 +-
 gr-utils/python/modtool/modtool_rename.py          |    6 +-
 gr-utils/python/modtool/templates.py               |    2 +-
 grc/CMakeLists.txt                                 |    1 -
 grc/blocks/block_tree.xml                          |   17 -
 grc/core/Block.py                                  |    8 +-
 grc/core/Element.py                                |   11 +-
 grc/core/FlowGraph.py                              |    2 +-
 grc/core/Param.py                                  |    6 +-
 grc/core/ParseXML.py                               |    1 +
 grc/core/Port.py                                   |    2 +-
 grc/core/generator/flow_graph.tmpl                 |    9 +-
 grc/gui/ActionHandler.py                           |    3 +
 grc/gui/Actions.py                                 |    6 +
 grc/gui/Bars.py                                    |    1 +
 grc/gui/FlowGraph.py                               |   10 +-
 grc/gui/NotebookPage.py                            |   13 +-
 volk                                               |    2 +-
 146 files changed, 1579 insertions(+), 7846 deletions(-)

diff --cc grc/CMakeLists.txt
index e21f6b2,d05ab51..a764e3d
--- a/grc/CMakeLists.txt
+++ b/grc/CMakeLists.txt
@@@ -133,8 -133,9 +133,7 @@@ endif(WIN32
  ########################################################################
  # Add subdirectories
  ########################################################################
 -add_subdirectory(base)
  add_subdirectory(blocks)
- add_subdirectory(grc_gnuradio)
 -add_subdirectory(freedesktop)
  add_subdirectory(gui)
  add_subdirectory(python)
  add_subdirectory(scripts)
diff --cc grc/core/Block.py
index c2c7d4e,0000000..6708986
mode 100644,000000..100644
--- a/grc/core/Block.py
+++ b/grc/core/Block.py
@@@ -1,848 -1,0 +1,846 @@@
 +"""
 +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
 +"""
 +
 +import collections
 +import itertools
 +
 +from Cheetah.Template import Template
- from UserDict import UserDict
 +
 +from .utils import epy_block_io, odict
 +from . Constants import (
 +    BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI,
 +    ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB,
 +    BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS,
 +    BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED
 +)
 +from . Element import Element
 +from . FlowGraph import _variable_matcher
 +
 +
 +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 "{}" not found in {}.'.format(key, 
_get_keys(lst)))
 +
 +
 +class Block(Element):
 +
 +    is_block = True
 +
 +    def __init__(self, flow_graph, n):
 +        """
 +        Make a new block from nested data.
 +
 +        Args:
 +            flow: graph the parent element
 +            n: the nested odict
 +
 +        Returns:
 +            block a new block
 +        """
 +        # Grab the data
 +        self._doc = (n.find('doc') or '').strip('\n').replace('\\\n', '')
 +        self._imports = map(lambda i: i.strip(), n.findall('import'))
 +        self._make = n.find('make')
 +        self._var_make = n.find('var_make')
 +        self._checks = n.findall('check')
 +        self._callbacks = n.findall('callback')
 +        self._bus_structure_source = n.find('bus_structure_source') or ''
 +        self._bus_structure_sink = n.find('bus_structure_sink') or ''
 +        self.port_counters = [itertools.count(), itertools.count()]
 +
 +        # Build the block
 +        Element.__init__(self, flow_graph)
 +
 +        # Grab the data
 +        params = n.findall('param')
 +        sources = n.findall('source')
 +        sinks = n.findall('sink')
 +        self._name = n.find('name')
 +        self._key = n.find('key')
 +        self._category = n.find('category') or ''
 +        self._flags = n.find('flags') or ''
 +        # Backwards compatibility
 +        if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags:
 +            self._flags += BLOCK_FLAG_THROTTLE
 +        self._grc_source = n.find('grc_source') or ''
 +        self._block_wrapper_path = n.find('block_wrapper_path')
 +        self._bussify_sink = n.find('bus_sink')
 +        self._bussify_source = n.find('bus_source')
 +        self._var_value = n.find('var_value') or '$value'
 +
 +        # 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
 +        self._params = list()
 +
 +        # Add the id param
 +        self.get_params().append(self.get_parent().get_parent().Param(
 +            block=self,
 +            n=odict({
 +                'name': 'ID',
 +                'key': 'id',
 +                'type': 'id',
 +            })
 +        ))
 +        self.get_params().append(self.get_parent().get_parent().Param(
 +            block=self,
 +            n=odict({
 +                'name': 'Enabled',
 +                'key': '_enabled',
 +                'type': 'raw',
 +                'value': 'True',
 +                'hide': 'all',
 +            })
 +        ))
 +        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
 +            if key in self.get_param_keys():
 +                raise Exception('Key "{}" already exists in 
params'.format(key))
 +            # Store the param
 +            self.get_params().append(param)
 +        # 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
 +            if key in self.get_source_keys():
 +                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
 +        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
 +            if key in self.get_sink_keys():
 +                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': ''}
 +
 +        # Virtual source/sink and pad source/sink blocks are
 +        # indistinguishable from normal GR blocks. Make explicit
 +        # checks for them here since they have no work function or
 +        # buffers to manage.
 +        is_virtual_or_pad = self._key in (
 +            "virtual_source", "virtual_sink", "pad_source", "pad_sink")
 +        is_variable = self._key.startswith('variable')
 +
 +        # Disable blocks that are virtual/pads or variables
 +        if is_virtual_or_pad or is_variable:
 +            self._flags += BLOCK_FLAG_DISABLE_BYPASS
 +
 +        if not (is_virtual_or_pad or is_variable or self._key == 'options'):
 +            self.get_params().append(self.get_parent().get_parent().Param(
 +                block=self,
 +                n=odict({'name': 'Block Alias',
 +                         'key': 'alias',
 +                         'type': 'string',
 +                         'hide': 'part',
 +                         'tab': ADVANCED_PARAM_TAB
 +                         })
 +            ))
 +
 +        if (len(sources) or len(sinks)) and not is_virtual_or_pad:
 +            self.get_params().append(self.get_parent().get_parent().Param(
 +                    block=self,
 +                    n=odict({'name': 'Core Affinity',
 +                             'key': 'affinity',
 +                             'type': 'int_vector',
 +                             'hide': 'part',
 +                             'tab': ADVANCED_PARAM_TAB
 +                             })
 +                    ))
 +        if len(sources) and not is_virtual_or_pad:
 +            self.get_params().append(self.get_parent().get_parent().Param(
 +                    block=self,
 +                    n=odict({'name': 'Min Output Buffer',
 +                             'key': 'minoutbuf',
 +                             'type': 'int',
 +                             'hide': 'part',
 +                             'value': '0',
 +                             'tab': ADVANCED_PARAM_TAB
 +                             })
 +                    ))
 +            self.get_params().append(self.get_parent().get_parent().Param(
 +                    block=self,
 +                    n=odict({'name': 'Max Output Buffer',
 +                             'key': 'maxoutbuf',
 +                             'type': 'int',
 +                             'hide': 'part',
 +                             'value': '0',
 +                             'tab': ADVANCED_PARAM_TAB
 +                             })
 +                    ))
 +
 +        self.get_params().append(self.get_parent().get_parent().Param(
 +                block=self,
 +                n=odict({'name': 'Comment',
 +                         'key': 'comment',
 +                         'type': '_multiline',
 +                         'hide': 'part',
 +                         'value': '',
 +                         'tab': ADVANCED_PARAM_TAB
 +                         })
 +                ))
 +
 +        self._epy_source_hash = -1  # for epy blocks
 +        self._epy_reload_error = None
 +
 +        if self._bussify_sink:
 +            self.bussify({'name': 'bus', 'type': 'bus'}, 'sink')
 +        if self._bussify_source:
 +            self.bussify({'name': 'bus', 'type': 'bus'}, 'source')
 +
 +    def get_bus_structure(self, direction):
 +        if direction == 'source':
 +            bus_structure = self._bus_structure_source
 +        else:
 +            bus_structure = self._bus_structure_sink
 +
 +        bus_structure = self.resolve_dependencies(bus_structure)
 +
 +        if not bus_structure:
 +            return ''  # TODO: Don't like empty strings. should change this 
to None eventually
 +
 +        try:
 +            clean_bus_structure = self.get_parent().evaluate(bus_structure)
 +            return clean_bus_structure
 +        except:
 +            return ''
 +
 +    def validate(self):
 +        """
 +        Validate this block.
 +        Call the base class validate.
 +        Evaluate the checks: each check must evaluate to True.
 +        """
 +        Element.validate(self)
 +        # 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 "{}" 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 "{}" 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')
 +
 +        def check_generate_mode(label, flag, valid_options):
 +            block_requires_mode = (
 +                flag in self.get_flags() or
 +                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: {} 
".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'))
 +        if self._epy_reload_error:
 +            
self.get_param('_source_code').add_error_message(str(self._epy_reload_error))
 +
 +    def rewrite(self):
 +        """
 +        Add and remove ports to adjust for the nports.
 +        """
 +        Element.rewrite(self)
 +        # Check and run any custom rewrite function for this block
 +        getattr(self, 'rewrite_' + self._key, lambda: None)()
 +
 +        # 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
 +                num_ports = 1 + len(master_port.get_clones())
 +                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
 +                    continue
 +                # Remove excess cloned ports
 +                for port in master_port.get_clones()[nports-1:]:
 +                    # 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
 +                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/message ports
 +            domain_specific_port_index = collections.defaultdict(int)
 +            for port in filter(lambda p: p.get_key().isdigit(), ports):
 +                domain = port.get_domain()
 +                port._key = str(domain_specific_port_index[domain])
 +                domain_specific_port_index[domain] += 1
 +
 +    def port_controller_modify(self, direction):
 +        """
 +        Change the port controller.
 +
 +        Args:
 +            direction: +1 or -1
 +
 +        Returns:
 +            true for change
 +        """
 +        changed = False
 +        # 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
 +        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
 +            try:
 +                value = param.get_evaluated()
 +                value = value + direction
 +                if 0 < value:
 +                    param.set_value(value)
 +                    changed = True
 +            except:
 +                pass
 +        return changed
 +
 +    def get_doc(self):
 +        platform = self.get_parent().get_parent()
 +        documentation = platform.block_docstrings.get(self._key, {})
 +        from_xml = self._doc.strip()
 +        if from_xml:
 +            documentation[''] = from_xml
 +        return documentation
 +
 +    def get_imports(self, raw=False):
 +        """
 +        Resolve all import statements.
 +        Split each import statement at newlines.
 +        Combine all import statments into a list.
 +        Filter empty imports.
 +
 +        Returns:
 +            a list of import statements
 +        """
 +        if raw:
 +            return self._imports
 +        return filter(lambda i: i, sum(map(lambda i: 
self.resolve_dependencies(i).split('\n'), self._imports), []))
 +
 +    def get_make(self, raw=False):
 +        if raw:
 +            return self._make
 +        return self.resolve_dependencies(self._make)
 +
 +    def get_var_make(self):
 +        return self.resolve_dependencies(self._var_make)
 +
 +    def get_var_value(self):
 +        return self.resolve_dependencies(self._var_value)
 +
 +    def get_callbacks(self):
 +        """
 +        Get a list of function callbacks for this block.
 +
 +        Returns:
 +            a list of strings
 +        """
 +        def make_callback(callback):
 +            callback = self.resolve_dependencies(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):
 +        return self.get_key() == 'virtual_sink'
 +
 +    def is_virtual_source(self):
 +        return self.get_key() == 'virtual_source'
 +
 +    
###########################################################################
 +    # Custom rewrite functions
 +    
###########################################################################
 +
 +    def rewrite_epy_block(self):
 +        flowgraph = self.get_parent()
 +        platform = flowgraph.get_parent()
 +        param_blk = self.get_param('_io_cache')
 +        param_src = self.get_param('_source_code')
 +
 +        src = param_src.get_value()
 +        src_hash = hash(src)
 +        if src_hash == self._epy_source_hash:
 +            return
 +
 +        try:
 +            blk_io = epy_block_io.extract(src)
 +
 +        except Exception as e:
 +            self._epy_reload_error = ValueError(str(e))
 +            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
 +            param_blk.set_value(repr(tuple(blk_io)))
 +
 +        # print "Rewriting embedded python block {!r}".format(self.get_id())
 +
 +        self._epy_source_hash = src_hash
 +        self._name = blk_io.name or blk_io.cls
 +        self._doc = blk_io.doc
 +        self._imports[0] = 'from {} import {}'.format(self.get_id(), 
blk_io.cls)
 +        self._make = '{}({})'.format(blk_io.cls, ', '.join(
 +            '{0}=${0}'.format(key) for key, _ in blk_io.params))
 +
 +        params = {}
 +        for param in list(self._params):
 +            if hasattr(param, '__epy_param__'):
 +                params[param.get_key()] = param
 +                self._params.remove(param)
 +
 +        for key, value in blk_io.params:
-             if key in params:
++            try:
 +                param = params[key]
-                 if not param.value_is_default():
-                     param.set_value(value)
-             else:
++                param.set_default(value)
++            except KeyError:  # need to make a new param
 +                name = key.replace('_', ' ').title()
 +                n = odict(dict(name=name, key=key, type='raw', value=value))
 +                param = platform.Param(block=self, n=n)
 +                setattr(param, '__epy_param__', True)
 +            self._params.append(param)
 +
 +        def update_ports(label, ports, port_specs, direction):
 +            ports_to_remove = list(ports)
 +            iter_ports = iter(ports)
 +            ports_new = []
 +            port_current = next(iter_ports, None)
 +            for key, port_type in port_specs:
 +                reuse_port = (
 +                    port_current is not None and
 +                    port_current.get_type() == port_type and
 +                    (key.isdigit() or port_current.get_key() == key)
 +                )
 +                if reuse_port:
 +                    ports_to_remove.remove(port_current)
 +                    port, port_current = port_current, next(iter_ports, None)
 +                else:
 +                    n = odict(dict(name=label + str(key), type=port_type, 
key=key))
 +                    if port_type == 'message':
 +                        n['name'] = key
 +                        n['optional'] = '1'
 +                    port = platform.Port(block=self, n=n, dir=direction)
 +                ports_new.append(port)
 +            # replace old port list with new one
 +            del ports[:]
 +            ports.extend(ports_new)
 +            # remove excess port connections
 +            for port in ports_to_remove:
 +                for connection in port.get_connections():
 +                    flowgraph.remove_element(connection)
 +
 +        update_ports('in', self.get_sinks(), blk_io.sinks, 'sink')
 +        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')
 +
 +    def filter_bus_port(self, ports):
 +        buslist = [p for p in ports if p._type == 'bus']
 +        return buslist or ports
 +
 +    # Main functions to get and set the block state
 +    # Also kept get_enabled and set_enabled to keep compatibility
 +    def get_state(self):
 +        """
 +        Gets the block's current state.
 +
 +        Returns:
 +            ENABLED - 0
 +            BYPASSED - 1
 +            DISABLED - 2
 +        """
 +        try:
 +            return int(eval(self.get_param('_enabled').get_value()))
 +        except:
 +            return BLOCK_ENABLED
 +
 +    def set_state(self, state):
 +        """
 +        Sets the state for the block.
 +
 +        Args:
 +            ENABLED - 0
 +            BYPASSED - 1
 +            DISABLED - 2
 +        """
 +        if state in [BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED]:
 +            self.get_param('_enabled').set_value(str(state))
 +        else:
 +            self.get_param('_enabled').set_value(str(BLOCK_ENABLED))
 +
 +    # Enable/Disable Aliases
 +    def get_enabled(self):
 +        """
 +        Get the enabled state of the block.
 +
 +        Returns:
 +            true for enabled
 +        """
 +        return not (self.get_state() == BLOCK_DISABLED)
 +
 +    def set_enabled(self, enabled):
 +        """
 +        Set the enabled state of the block.
 +
 +        Args:
 +            enabled: true for enabled
 +
 +        Returns:
 +            True if block changed state
 +        """
 +        old_state = self.get_state()
 +        new_state = BLOCK_ENABLED if enabled else BLOCK_DISABLED
 +        self.set_state(new_state)
 +        return old_state != new_state
 +
 +    # Block bypassing
 +    def get_bypassed(self):
 +        """
 +        Check if the block is bypassed
 +        """
 +        return self.get_state() == BLOCK_BYPASSED
 +
 +    def set_bypassed(self):
 +        """
 +        Bypass the block
 +
 +        Returns:
 +            True if block chagnes state
 +        """
 +        if self.get_state() != BLOCK_BYPASSED and self.can_bypass():
 +            self.set_state(BLOCK_BYPASSED)
 +            return True
 +        return False
 +
 +    def can_bypass(self):
 +        """ Check the number of sinks and sources and see if this block can 
be bypassed """
 +        # Check to make sure this is a single path block
 +        # Could possibly support 1 to many blocks
 +        if len(self.get_sources()) != 1 or len(self.get_sinks()) != 1:
 +            return False
 +        if not (self.get_sources()[0].get_type() == 
self.get_sinks()[0].get_type()):
 +            return False
 +        if self.bypass_disabled():
 +            return False
 +        return True
 +
 +    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 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 has_param(self, key):
 +        try:
 +            _get_elem(self._params, key)
 +            return True
 +        except:
 +            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())
 +
 +    ##############################################
 +    # 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_connections(self):
 +        return sum([port.get_connections() for port in self.get_ports()], [])
 +
 +    def resolve_dependencies(self, tmpl):
 +        """
 +        Resolve a paramater dependency with cheetah templates.
 +
 +        Args:
 +            tmpl: the string with dependencies
 +
 +        Returns:
 +            the resolved value
 +        """
 +        tmpl = str(tmpl)
 +        if '$' not in tmpl:
 +            return tmpl
 +        n = dict((param.get_key(), param.template_arg)
 +                 for param in self.get_params())  # TODO: cache that
 +        try:
 +            return str(Template(tmpl, n))
 +        except Exception as err:
 +            return "Template error: {}\n    {}".format(tmpl, err)
 +
 +    ##############################################
 +    # Controller Modify
 +    ##############################################
 +    def type_controller_modify(self, direction):
 +        """
 +        Change the type controller.
 +
 +        Args:
 +            direction: +1 or -1
 +
 +        Returns:
 +            true for change
 +        """
 +        changed = False
 +        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
 +            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
 +        if type_param:
 +            # 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)
 +                type_param.set_value(keys[new_index])
 +                changed = True
 +            except:
 +                pass
 +        return changed
 +
 +    def form_bus_structure(self, direc):
 +        if direc == '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_gui = self.get_sinks_gui
 +            bus_structure = self.get_bus_structure('sink')
 +
 +        struct = [range(len(get_p()))]
 +        if True in map(lambda a: isinstance(a.get_nports(), int), get_p()):
 +            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
 +                struct = [structlet]
 +        if bus_structure:
 +
 +            struct = bus_structure
 +
 +        self.current_bus_structure[direc] = struct
 +        return struct
 +
 +    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')
 +        else:
 +            get_p = self.get_sinks
 +            get_p_gui = self.get_sinks_gui
 +            bus_structure = self.get_bus_structure('sink')
 +
 +        for elt in get_p():
 +            for connect in elt.get_connections():
 +                self.get_parent().remove_element(connect)
 +
 +        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)
 +
 +            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)
 +        elif 'bus' in map(lambda a: a.get_type(), get_p()):
 +            for elt in get_p_gui():
 +                get_p().remove(elt)
 +            self.current_bus_structure[direc] = ''
 +
 +    ##############################################
 +    # Import/Export Methods
 +    ##############################################
 +    def export_data(self):
 +        """
 +        Export this block's params to nested data.
 +
 +        Returns:
 +            a nested data odict
 +        """
 +        n = odict()
 +        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)
 +        if 'bus' in map(lambda a: a.get_type(), self.get_sources()):
 +            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.
 +        Any param keys that do not exist will be ignored.
 +        Since params can be dynamically created based another param,
 +        call rewrite, and repeat the load until the params stick.
 +        This call to rewrite will also create any dynamic ports
 +        that are needed for the connections creation phase.
 +
 +        Args:
 +            n: the nested data odict
 +        """
 +        my_hash = 0
 +        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
 +                if key in self.get_param_keys():
 +                    self.get_param(key).set_value(value)
 +            # Store hash and call rewrite
 +            my_hash = self.get_hash()
 +            self.rewrite()
 +        bussinks = n.findall('bus_sink')
 +        if len(bussinks) > 0 and not self._bussify_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')
 +        if len(bussrcs) > 0 and not self._bussify_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')
diff --cc grc/core/Element.py
index c999d67,b0f94d0..b96edb0
--- a/grc/core/Element.py
+++ b/grc/core/Element.py
@@@ -63,10 -61,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 child in filter(lambda c: c.get_enabled() and not 
c.get_bypassed(), 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):
@@@ -74,33 -72,27 +74,36 @@@
          Rewrite this element and call rewrite on all children.
          Call this base method before rewriting the element.
          """
 -        for child in self.get_children(): child.rewrite()
 +        for child in self.get_children():
 +            child.rewrite()
 +
 +    def get_enabled(self):
 +        return True
  
 -    def get_enabled(self): return True
 -    def get_bypassed(self): return False
++    def get_bypassed(self):
++        return False
+ 
      ##############################################
 -    ## Tree-like API
 +    # Tree-like API
      ##############################################
 -    def get_parent(self): return self._parent
 -    def get_children(self): return list()
 +    def get_parent(self):
 +        return self._parent
 +
 +    def get_children(self):
 +        return list()
  
      ##############################################
 -    ## Type testing methods
 +    # Type testing
      ##############################################
 -    def is_element(self): return True
 -    def is_platform(self): return False
 -    def is_flow_graph(self): return False
 -    def is_connection(self): return False
 -    def is_block(self): return False
 -    def is_dummy_block(self): return False
 -    def is_source(self): return False
 -    def is_sink(self): return False
 -    def is_port(self): return False
 -    def is_param(self): return False
 +    is_platform = False
 +
 +    is_flow_graph = False
 +
 +    is_block = False
 +    is_dummy_block = False
 +
 +    is_connection = False
 +
 +    is_port = False
 +
 +    is_param = False
diff --cc grc/core/FlowGraph.py
index 177d16b,0000000..313af31
mode 100644,000000..100644
--- a/grc/core/FlowGraph.py
+++ b/grc/core/FlowGraph.py
@@@ -1,594 -1,0 +1,594 @@@
 +# 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
 +
 +import imp
 +import time
 +from itertools import ifilter, chain
 +from operator import methodcaller
 +
 +import re
 +
 +from . import Messages
 +from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION
 +from .Element import Element
 +from .utils import odict, expr_utils
 +
 +_variable_matcher = re.compile('^(variable\w*)$')
 +_parameter_matcher = re.compile('^(parameter)$')
 +_monitors_searcher = re.compile('(ctrlport_monitor)')
 +_bussink_searcher = re.compile('^(bus_sink)$')
 +_bussrc_searcher = re.compile('^(bus_source)$')
 +_bus_struct_sink_searcher = re.compile('^(bus_structure_sink)$')
 +_bus_struct_src_searcher = re.compile('^(bus_structure_source)$')
 +
 +
 +class FlowGraph(Element):
 +
 +    is_flow_graph = True
 +
 +    def __init__(self, platform):
 +        """
 +        Make a flow graph from the arguments.
 +
 +        Args:
 +            platform: a platforms with blocks and contrcutors
 +
 +        Returns:
 +            the flow graph object
 +        """
 +        Element.__init__(self, platform)
 +        self._elements = []
 +        self._timestamp = time.ctime()
 +
 +        self.platform = platform  # todo: make this a lazy prop
 +        self.blocks = []
 +        self.connections = []
 +
 +        self._eval_cache = {}
 +        self.namespace = {}
 +
 +        self.grc_file_path = ''
 +        self._options_block = self.new_block('options')
 +
 +    def __str__(self):
 +        return 'FlowGraph - {}({})'.format(self.get_option('title'), 
self.get_option('id'))
 +
 +    ##############################################
 +    # TODO: Move these to new generator package
 +    ##############################################
 +    def get_imports(self):
 +        """
 +        Get a set of all import statments in this flow graph namespace.
 +
 +        Returns:
 +            a set of import statements
 +        """
 +        imports = sum([block.get_imports() for block in 
self.get_enabled_blocks()], [])
 +        imports = sorted(set(imports))
 +        return imports
 +
 +    def get_variables(self):
 +        """
 +        Get a list of all variables in this flow graph namespace.
 +        Exclude paramterized variables.
 +
 +        Returns:
 +            a sorted list of variable blocks in order of dependency (indep -> 
dep)
 +        """
 +        variables = filter(lambda b: _variable_matcher.match(b.get_key()), 
self.iter_enabled_blocks())
 +        return expr_utils.sort_objects(variables, methodcaller('get_id'), 
methodcaller('get_var_make'))
 +
 +    def get_parameters(self):
 +        """
 +        Get a list of all paramterized variables in this flow graph namespace.
 +
 +        Returns:
 +            a list of paramterized variables
 +        """
 +        parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), 
self.iter_enabled_blocks())
 +        return parameters
 +
 +    def get_monitors(self):
 +        """
 +        Get a list of all ControlPort monitors
 +        """
 +        monitors = filter(lambda b: _monitors_searcher.search(b.get_key()),
 +                          self.iter_enabled_blocks())
 +        return monitors
 +
 +    def get_python_modules(self):
 +        """Iterate over custom code block ID and Source"""
 +        for block in self.iter_enabled_blocks():
 +            if block.get_key() == 'epy_module':
 +                yield block.get_id(), 
block.get_param('source_code').get_value()
 +
 +    def get_bussink(self):
 +        bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), 
self.get_enabled_blocks())
 +
 +        for i in bussink:
 +            for j in i.get_params():
 +                if j.get_name() == 'On/Off' and j.get_value() == 'on':
 +                    return True
 +        return False
 +
 +    def get_bussrc(self):
 +        bussrc = filter(lambda b: _bussrc_searcher.search(b.get_key()), 
self.get_enabled_blocks())
 +
 +        for i in bussrc:
 +            for j in i.get_params():
 +                if j.get_name() == 'On/Off' and j.get_value() == 'on':
 +                    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):
 +        """
 +        Get an iterator of all blocks that are enabled and not bypassed.
 +        """
 +        return ifilter(methodcaller('get_enabled'), self.blocks)
 +
 +    def get_enabled_blocks(self):
 +        """
 +        Get a list of all blocks that are enabled and not bypassed.
 +
 +        Returns:
 +            a list of blocks
 +        """
 +        return list(self.iter_enabled_blocks())
 +
 +    def get_bypassed_blocks(self):
 +        """
 +        Get a list of all blocks that are bypassed.
 +
 +        Returns:
 +            a list of blocks
 +        """
 +        return filter(methodcaller('get_bypassed'), self.blocks)
 +
 +    def get_enabled_connections(self):
 +        """
 +        Get a list of all connections that are enabled.
 +
 +        Returns:
 +            a list of connections
 +        """
 +        return filter(methodcaller('get_enabled'), self.connections)
 +
 +    def get_option(self, key):
 +        """
 +        Get the option for a given key.
 +        The option comes from the special options block.
 +
 +        Args:
 +            key: the param key for the options block
 +
 +        Returns:
 +            the value held by that param
 +        """
 +        return self._options_block.get_param(key).get_evaluated()
 +
 +    ##############################################
 +    # Access Elements
 +    ##############################################
 +    def get_block(self, id):
 +        for block in self.blocks:
 +            if block.get_id() == id:
 +                return block
 +        raise KeyError('No block with ID {!r}'.format(id))
 +
 +    def get_elements(self):
 +        """
 +        Get a list of all the elements.
 +        Always ensure that the options block is in the list (only once).
 +
 +        Returns:
 +            the element list
 +        """
 +        options_block_count = self.blocks.count(self._options_block)
 +        if not options_block_count:
 +            self.blocks.append(self._options_block)
 +        for i in range(options_block_count-1):
 +            self.blocks.remove(self._options_block)
 +
 +        return self.blocks + self.connections
 +
 +    get_children = get_elements
 +
 +    def rewrite(self):
 +        """
 +        Flag the namespace to be renewed.
 +        """
 +
 +        self.renew_namespace()
 +        for child in chain(self.blocks, self.connections):
 +            child.rewrite()
 +
 +        self.bus_ports_rewrite()
 +
 +    def renew_namespace(self):
 +        namespace = {}
 +        # Load imports
 +        for expr in self.get_imports():
 +            try:
 +                exec expr in namespace
 +            except:
 +                pass
 +
 +        for id, expr in self.get_python_modules():
 +            try:
 +                module = imp.new_module(id)
 +                exec expr in module.__dict__
 +                namespace[id] = module
 +            except:
 +                pass
 +
 +        # Load parameters
 +        np = {}  # params don't know each other
 +        for parameter in self.get_parameters():
 +            try:
 +                value = eval(parameter.get_param('value').to_code(), 
namespace)
 +                np[parameter.get_id()] = value
 +            except:
 +                pass
 +        namespace.update(np)  # Merge param namespace
 +
 +        # Load variables
 +        for variable in self.get_variables():
 +            try:
 +                value = eval(variable.get_var_value(), namespace)
 +                namespace[variable.get_id()] = value
 +            except:
 +                pass
 +
 +        self.namespace.clear()
 +        self._eval_cache.clear()
 +        self.namespace.update(namespace)
 +
 +    def evaluate(self, expr):
 +        """
 +        Evaluate the expression.
 +
 +        Args:
 +            expr: the string expression
 +        @throw Exception bad expression
 +
 +        Returns:
 +            the evaluated data
 +        """
 +        # Evaluate
 +        if not expr:
 +            raise Exception('Cannot evaluate empty statement.')
 +        return self._eval_cache.setdefault(expr, eval(expr, self.namespace))
 +
 +    ##############################################
 +    # Add/remove stuff
 +    ##############################################
 +
 +    def new_block(self, key):
 +        """
 +        Get a new block of the specified key.
 +        Add the block to the list of elements.
 +
 +        Args:
 +            key: the block key
 +
 +        Returns:
 +            the new block or None if not found
 +        """
 +        try:
 +            block = self.platform.get_new_block(self, key)
 +            self.blocks.append(block)
 +        except KeyError:
 +            block = None
 +        return block
 +
 +    def connect(self, porta, portb):
 +        """
 +        Create a connection between porta and portb.
 +
 +        Args:
 +            porta: a port
 +            portb: another port
 +        @throw Exception bad connection
 +
 +        Returns:
 +            the new connection
 +        """
 +
 +        connection = self.platform.Connection(
 +            flow_graph=self, porta=porta, portb=portb)
 +        self.connections.append(connection)
 +        return connection
 +
 +    def remove_element(self, element):
 +        """
 +        Remove the element from the list of elements.
 +        If the element is a port, remove the whole block.
 +        If the element is a block, remove its connections.
 +        If the element is a connection, just remove the connection.
 +        """
 +        if element.is_port:
 +            # Found a port, set to parent signal block
 +            element = element.get_parent()
 +
 +        if element in self.blocks:
 +            # Remove block, remove all involved connections
 +            for port in element.get_ports():
 +                map(self.remove_element, port.get_connections())
 +            self.blocks.remove(element)
 +
 +        elif element in self.connections:
 +            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)
 +            self.connections.remove(element)
 +
 +    ##############################################
 +    # Import/Export Methods
 +    ##############################################
 +    def export_data(self):
 +        """
 +        Export this flow graph to nested data.
 +        Export all block and connection data.
 +
 +        Returns:
 +            a nested data odict
 +        """
 +        # sort blocks and connections for nicer diffs
 +        blocks = sorted(self.blocks, key=lambda b: (
 +            b.get_key() != 'options',  # options to the front
 +            not b.get_key().startswith('variable'),  # then vars
 +            str(b)
 +        ))
 +        connections = sorted(self.connections, key=str)
 +        n = odict()
 +        n['timestamp'] = self._timestamp
 +        n['block'] = [b.export_data() for b in blocks]
 +        n['connection'] = [c.export_data() for c in connections]
 +        instructions = odict({
 +            'created': '.'.join(self.get_parent().config.version_parts),
 +            'format': FLOW_GRAPH_FILE_FORMAT_VERSION,
 +        })
 +        return odict({'flow_graph': n, '_instructions': instructions})
 +
 +    def import_data(self, n):
 +        """
 +        Import blocks and connections into this flow graph.
 +        Clear this flowgraph of all previous blocks and connections.
 +        Any blocks or connections in error will be ignored.
 +
 +        Args:
 +            n: the nested data odict
 +        """
 +        # Remove previous elements
 +        del self.blocks[:]
 +        del self.connections[:]
 +        # set file format
 +        try:
 +            instructions = n.find('_instructions') or {}
 +            file_format = int(instructions.get('format', '0')) or 
_guess_file_format_1(n)
 +        except:
 +            file_format = 0
 +
 +        fg_n = n and n.find('flow_graph') or odict()  # use blank data if 
none provided
 +        self._timestamp = fg_n.find('timestamp') or time.ctime()
 +
 +        # build the blocks
 +        self._options_block = self.new_block('options')
 +        for block_n in fg_n.findall('block'):
 +            key = block_n.find('key')
 +            block = self._options_block if key == 'options' else 
self.new_block(key)
 +
 +            if not block:
 +                # we're before the initial fg update(), so no evaluated 
values!
 +                # --> use raw value instead
 +                path_param = 
self._options_block.get_param('hier_block_src_path')
 +                file_path = self.platform.find_file_in_paths(
 +                    filename=key + '.grc',
 +                    paths=path_param.get_value(),
 +                    cwd=self.grc_file_path
 +                )
 +                if file_path:  # grc file found. load and get block
 +                    self.platform.load_and_generate_flow_graph(file_path)
 +                    block = self.new_block(key)  # can be None
 +
 +            if not block:  # looks like this block key cannot be found
 +                # create a dummy block instead
 +                block = self.new_block('dummy_block')
 +                # Ugly ugly ugly
 +                _initialize_dummy_block(block, block_n)
 +                print('Block key "%s" not found' % key)
 +
 +            block.import_data(block_n)
 +
-         self.rewrite()
++        self.rewrite()  # evaluate stuff like nports before adding connections
 +
 +        # build the connections
 +        def verify_and_get_port(key, block, dir):
 +            ports = block.get_sinks() if dir == 'sink' else 
block.get_sources()
 +            for port in ports:
 +                if key == port.get_key():
 +                    break
 +                if not key.isdigit() and port.get_type() == '' and key == 
port.get_name():
 +                    break
 +            else:
 +                if block.is_dummy_block:
 +                    port = _dummy_block_add_port(block, key, dir)
 +                else:
 +                    raise LookupError('%s key %r not in %s block keys' % 
(dir, key, dir))
 +            return port
 +
 +        errors = False
 +        for connection_n in fg_n.findall('connection'):
 +            # get the block ids and port keys
 +            source_block_id = connection_n.find('source_block_id')
 +            sink_block_id = connection_n.find('sink_block_id')
 +            source_key = connection_n.find('source_key')
 +            sink_key = connection_n.find('sink_key')
 +            try:
 +                source_block = self.get_block(source_block_id)
 +                sink_block = self.get_block(sink_block_id)
 +
 +                # fix old, numeric message ports keys
 +                if file_format < 1:
 +                    source_key, sink_key = _update_old_message_port_keys(
 +                        source_key, sink_key, source_block, sink_block)
 +
 +                # build the connection
 +                source_port = verify_and_get_port(source_key, source_block, 
'source')
 +                sink_port = verify_and_get_port(sink_key, sink_block, 'sink')
 +                self.connect(source_port, sink_port)
 +            except LookupError as e:
 +                Messages.send_error_load(
 +                    'Connection between {}({}) and {}({}) could not be 
made.\n\t{}'.format(
 +                        source_block_id, source_key, sink_block_id, sink_key, 
e))
 +                errors = True
 +
 +        self.rewrite()  # global rewrite
 +        return errors
 +
 +    ##############################################
 +    # Needs to go
 +    ##############################################
 +    def bus_ports_rewrite(self):
 +        # todo: move to block.rewrite()
 +        for block in self.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')
 +                else:
 +                    get_p = block.get_sinks
 +                    get_p_gui = block.get_sinks_gui
 +                    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()))
 +                        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])
 +                    elif len(get_p_gui()) < len(bus_structure):
 +                        n = {'name': 'bus', 'type': 'bus'}
 +                        if True in map(
 +                                lambda a: isinstance(a.get_nports(), int),
 +                                get_p()):
 +                            n['nports'] = str(1)
 +
 +                        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)
 +
 +                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())
 +                            for elt in source.get_connections():
 +                                self.remove_element(elt)
 +                            for j in sink:
 +                                self.connect(source, j)
 +
 +
 +def _update_old_message_port_keys(source_key, sink_key, source_block, 
sink_block):
 +    """
 +    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
 +    message connections. These have to be replaced by the name of the
 +    respective port. The correct message port is deduced from the integer
 +    value of the key (assuming the order has not changed).
 +
 +    The connection ends are updated only if both ends translate into a
 +    message port.
 +    """
 +    try:
 +        # get ports using the "old way" (assuming liner indexed keys)
 +        source_port = source_block.get_sources()[int(source_key)]
 +        sink_port = sink_block.get_sinks()[int(sink_key)]
 +        if source_port.get_type() == "message" and sink_port.get_type() == 
"message":
 +            source_key, sink_key = source_port.get_key(), sink_port.get_key()
 +    except (ValueError, IndexError):
 +        pass
 +    return source_key, sink_key  # do nothing
 +
 +
 +def _guess_file_format_1(n):
 +    """
 +    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
 +            connection_n.find('sink_key').isdigit()
 +        ) for connection_n in n.find('flow_graph').findall('connection'))
 +        if has_non_numeric_message_keys:
 +            return 1
 +    except:
 +        pass
 +    return 0
 +
 +
 +def _initialize_dummy_block(block, block_n):
 +    """
 +    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
 +    block.get_enabled = lambda: False
 +    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'})
 +            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 """
 +    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():
 +        block.get_sources().append(port)
 +    else:
 +        block.get_sinks().append(port)
 +    return port
diff --cc grc/core/Param.py
index 04c4967,0000000..d155800
mode 100644,000000..100644
--- a/grc/core/Param.py
+++ b/grc/core/Param.py
@@@ -1,738 -1,0 +1,740 @@@
 +"""
 +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
 +"""
 +
 +import ast
 +import weakref
 +import re
 +
 +from . import Constants
 +from .Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES
 +from .Element import Element
 +from .utils import odict
 +
 +# Blacklist certain ids, its not complete, but should help
 +import __builtin__
 +
 +
 +ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 
'forms', 'firdes'] + dir(__builtin__)
 +try:
 +    from gnuradio import gr
 +    ID_BLACKLIST.extend(attr for attr in dir(gr.top_block()) if not 
attr.startswith('_'))
 +except ImportError:
 +    pass
 +
 +_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 "{}" not found in {}.'.format(key, 
_get_keys(lst)))
 +
 +
 +def num_to_str(num):
 +    """ Display logic for numbers """
 +    def eng_notation(value, fmt='g'):
 +        """Convert a number to a string in engineering notation.  E.g., 5e-9 
-> 5n"""
 +        template = '{:' + fmt + '}{}'
 +        magnitude = abs(value)
 +        for exp, symbol in zip(range(9, -15-1, -3), 'GMk munpf'):
 +            factor = 10 ** exp
 +            if magnitude >= factor:
 +                return template.format(value / factor, symbol.strip())
 +        return template.format(value, '')
 +
 +    if isinstance(num, COMPLEX_TYPES):
 +        num = complex(num)  # Cast to python complex
 +        if num == 0:
 +            return '0'
 +        output = eng_notation(num.real) if num.real else ''
 +        output += eng_notation(num.imag, '+g' if output else 'g') + 'j' if 
num.imag else ''
 +        return output
 +    else:
 +        return str(num)
 +
 +
 +class Option(Element):
 +
 +    def __init__(self, param, n):
 +        Element.__init__(self, param)
 +        self._name = n.find('name')
 +        self._key = n.find('key')
 +        self._opts = dict()
 +        opts = n.findall('opt')
 +        # 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
 +        for opt in opts:
 +            # 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 {}({})'.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()
 +
 +
 +class TemplateArg(object):
 +    """
 +    A cheetah template argument created from a param.
 +    The str of this class evaluates to the param's to code method.
 +    The use of this class as a dictionary (enum only) will reveal the enum 
opts.
 +    The __call__ or () method can return the param evaluated to a raw python 
data type.
 +    """
 +
 +    def __init__(self, param):
 +        self._param = weakref.proxy(param)
 +
 +    def __getitem__(self, item):
 +        return str(self._param.get_opt(item)) if self._param.is_enum() else 
NotImplemented
 +
 +    def __str__(self):
 +        return str(self._param.to_code())
 +
 +    def __call__(self):
 +        return self._param.get_evaluated()
 +
 +
 +class Param(Element):
 +
 +    is_param = True
 +
 +    def __init__(self, block, n):
 +        """
 +        Make a new param from nested data.
 +
 +        Args:
 +            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
 +        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
 +        self._n = n
 +        # 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 self._tab_label not in block.get_param_tab_labels():
 +            block.get_param_tab_labels().append(self._tab_label)
 +        # Build the param
 +        Element.__init__(self, block)
 +        # 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
 +            if key in self.get_option_keys():
 +                raise Exception('Key "{}" already exists in 
options'.format(key))
 +            # Store the option
 +            self.get_options().append(option)
 +        # Test the enum options
 +        if self.is_enum():
 +            # Test against options with identical keys
 +            if len(set(self.get_option_keys())) != len(self.get_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 "{}" 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 "{}" is not in the possible values 
of "{}".'.format(self.get_value(), self.get_option_keys()))
 +        else:
 +            self._value = value or ''
 +        self._default = value
 +        self._init = False
 +        self._hostage_cells = list()
 +        self.template_arg = TemplateArg(self)
 +
 +    def get_types(self):
 +        return (
 +            'raw', 'enum',
 +            'complex', 'real', 'float', 'int',
 +            'complex_vector', 'real_vector', 'float_vector', 'int_vector',
 +            'hex', 'string', 'bool',
 +            'file_open', 'file_save', '_multiline', 
'_multiline_python_external',
 +            'id', 'stream_id',
 +            'grid_pos', 'notebook', 'gui_hint',
 +            'import',
 +        )
 +
 +    def __repr__(self):
 +        """
 +        Get the repr (nice string format) for this param.
 +
 +        Returns:
 +            the string representation
 +        """
 +        ##################################################
 +        # 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
 +                    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
 +                    string = string[:max_len-3] + '...'
 +            return string
 +
 +        ##################################################
 +        # 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()
 +
 +        ##################################################
 +        # Split up formatting by type
 +        ##################################################
 +        # 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 len(e) > 8:
 +                # Large vectors use code
 +                dt_str = self.get_value()
 +                truncate = 1
 +            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:
 +            # Other types
 +            dt_str = str(e)
 +
 +        # Done
 +        return _truncate(dt_str, truncate)
 +
 +    def __repr2__(self):
 +        """
 +        Get the repr (nice string format) for this param.
 +
 +        Returns:
 +            the string representation
 +        """
 +        if self.is_enum():
 +            return self.get_option(self.get_value()).get_name()
 +        return self.get_value()
 +
 +    def __str__(self):
 +        return 'Param - {}({})'.format(self.get_name(), self.get_key())
 +
 +    def get_color(self):
 +        """
 +        Get the color that represents this param's type.
 +
 +        Returns:
 +            a hex color code.
 +        """
 +        try:
 +            return {
 +                # Number types
 +                'complex': Constants.COMPLEX_COLOR_SPEC,
 +                'real': Constants.FLOAT_COLOR_SPEC,
 +                'float': Constants.FLOAT_COLOR_SPEC,
 +                'int': Constants.INT_COLOR_SPEC,
 +                # Vector types
 +                'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC,
 +                'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
 +                'float_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
 +                'int_vector': Constants.INT_VECTOR_COLOR_SPEC,
 +                # Special
 +                'bool': Constants.INT_COLOR_SPEC,
 +                'hex': Constants.INT_COLOR_SPEC,
 +                'string': Constants.BYTE_VECTOR_COLOR_SPEC,
 +                'id': Constants.ID_COLOR_SPEC,
 +                'stream_id': Constants.ID_COLOR_SPEC,
 +                'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
 +                'notebook': Constants.INT_VECTOR_COLOR_SPEC,
 +                'raw': Constants.WILDCARD_COLOR_SPEC,
 +            }[self.get_type()]
 +        except:
 +            return '#FFFFFF'
 +
 +    def get_hide(self):
 +        """
 +        Get the hide value from the base class.
 +        Hide the ID parameter for most blocks. Exceptions below.
 +        If the parameter controls a port type, vlen, or nports, return part.
 +        If the parameter is an empty grid position, return part.
 +        These parameters are redundant to display in the flow graph view.
 +
 +        Returns:
 +            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 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'
 +        return hide
 +
 +    def validate(self):
 +        """
 +        Validate the param.
 +        The value must be evaluated and type must a possible type.
 +        """
 +        Element.validate(self)
 +        if self.get_type() not in self.get_types():
 +            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))
 +
 +    def get_evaluated(self):
 +        return self._evaluated
 +
 +    def evaluate(self):
 +        """
 +        Evaluate the value.
 +
 +        Returns:
 +            evaluated type
 +        """
 +        self._init = True
 +        self._lisitify_flag = False
 +        self._stringify_flag = False
 +        self._hostage_cells = list()
 +        t = self.get_type()
 +        v = self.get_value()
 +
 +        #########################
 +        # Enum Type
 +        #########################
 +        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 "{}" 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 "{}" 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 "{}" is invalid for type 
float.'.format(str(e)))
 +                return e
 +            elif t == 'int':
 +                if not isinstance(e, INT_TYPES):
 +                    raise Exception('Expression "{}" is invalid for type 
integer.'.format(str(e)))
 +                return e
 +            elif t == 'hex':
 +                return hex(e)
 +            elif t == 'bool':
 +                if not isinstance(e, bool):
 +                    raise Exception('Expression "{}" is invalid for type 
bool.'.format(str(e)))
 +                return e
 +            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:
 +                # 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 "{}" 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 "{}" 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 "{}" 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
 +            try:
 +                e = self.get_parent().get_parent().evaluate(v)
 +                if not isinstance(e, str):
 +                    raise Exception()
 +            except:
 +                self._stringify_flag = True
 +                e = str(v)
 +            if t == '_multiline_python_external':
 +                ast.parse(e)  # Raises SyntaxError
 +            return e
 +        #########################
 +        # Unique ID Type
 +        #########################
 +        elif t == 'id':
 +            # Can python use this as a variable?
 +            if not _check_id_matcher.match(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)]
 +
 +            # 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 "{}" 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
 +            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
 +            if self.get_parent().is_virtual_sink():
 +                # 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 "{}" 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 = '?'
 +
 +            # 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}
 +
 +            # 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
 +
 +                def __call__(self, w):
 +                    return (self._ws.replace('addWidget', 'addLayout') if 
'layout' in w else self._ws) % w
 +
 +                def __str__(self):
 +                    return self._ws
 +            return GuiHint(widget_str)
 +        #########################
 +        # Grid Position Type
 +        #########################
 +        elif t == '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.')
 +            row, col, row_span, col_span = e
 +            # Check row, col
 +            if row < 0 or col < 0:
 +                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
 +            for r in range(row_span):
 +                for c in range(col_span):
 +                    self._hostage_cells.append((my_parent, (row+r, col+c)))
 +            # 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 "{}", cell "{}".'.format(str(parent), str(cell)))
 +            return e
 +        #########################
 +        # Notebook Page Type
 +        #########################
 +        elif t == 'notebook':
 +            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 "{}" 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 "{}" is not a valid index 
number.'.format(page_index))
 +            return notebook_id, page_index
 +
 +        #########################
 +        # Import Type
 +        #########################
 +        elif t == 'import':
 +            # 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 "{}" not handled'.format(t))
 +
 +    def to_code(self):
 +        """
 +        Convert the value to code.
 +        For string and list types, check the init flag, call evaluate().
 +        This ensures that evaluate() was called to set the xxxify_flags.
 +
 +        Returns:
 +            a string representing the code
 +        """
 +        v = self.get_value()
 +        t = self.get_type()
 +        # 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):
 +        """
 +        Get all the params from the flowgraph that have the given type.
 +
 +        Args:
 +            type: the specified type
 +
 +        Returns:
 +            a list of params
 +        """
 +        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 get_value(self):
 +        value = self._value
 +        if self.is_enum() and value not in self.get_option_keys():
 +            value = self.get_option_keys()[0]
 +            self.set_value(value)
 +        return value
 +
 +    def set_value(self, value):
 +        # Must be a string
 +        self._value = str(value)
 +
-     def value_is_default(self):
-         return self._default == self._value
++    def set_default(self, value):
++        if self._default == self._value:
++            self.set_value(value)
++        self._default = str(value)
 +
 +    def get_type(self):
 +        return self.get_parent().resolve_dependencies(self._type)
 +
 +    def get_tab_label(self):
 +        return self._tab_label
 +
 +    def get_name(self):
 +        return self.get_parent().resolve_dependencies(self._name).strip()
 +
 +    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
 +
 +    ##############################################
 +    # 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()
 +
 +    ##############################################
 +    # Import/Export Methods
 +    ##############################################
 +    def export_data(self):
 +        """
 +        Export this param's key/value.
 +
 +        Returns:
 +            a nested data odict
 +        """
 +        n = odict()
 +        n['key'] = self.get_key()
 +        n['value'] = self.get_value()
 +        return n
diff --cc grc/core/ParseXML.py
index 987fa2a,e05fc14..c9f6541
--- a/grc/core/ParseXML.py
+++ b/grc/core/ParseXML.py
@@@ -18,10 -18,10 +18,11 @@@ Foundation, Inc., 51 Franklin Street, F
  """
  
  from lxml import etree
 -from . import odict
 +
 +from .utils import odict
  
  xml_failures = {}
+ etree.set_default_parser(etree.XMLParser(remove_comments=True))
  
  
  class XMLSyntaxError(Exception):
diff --cc grc/core/Port.py
index 4964a94,0000000..6a8f484
mode 100644,000000..100644
--- a/grc/core/Port.py
+++ b/grc/core/Port.py
@@@ -1,404 -1,0 +1,404 @@@
 +"""
 +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
 +"""
 +
 +from .Constants import DEFAULT_DOMAIN, GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN
 +from .Element import Element
 +
 +from . import Constants
 +
 +
 +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 
{}'.format(vsp))
 +
 +
 +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 
{}'.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):
 +    """
 +    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:
 +        # 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=[]):
 +    """
 +    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 
{}'.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):
 +
 +    is_port = True
 +
 +    def __init__(self, block, n, dir):
 +        """
 +        Make a new port from nested data.
 +
 +        Args:
 +            block: the parent element
 +            n: the nested odict
 +            dir: the direction
 +        """
 +        self._n = n
 +        if n['type'] == 'message':
 +            n['domain'] = GR_MESSAGE_DOMAIN
 +        if 'domain' not in n:
 +            n['domain'] = DEFAULT_DOMAIN
 +        elif n['domain'] == GR_MESSAGE_DOMAIN:
 +            n['key'] = n['name']
 +            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
 +        Element.__init__(self, block)
 +        # Grab the data
 +        self._name = n['name']
 +        self._key = n['key']
-         self._type = n['type']
++        self._type = n['type'] or ''
 +        self._domain = n['domain']
 +        self._hide = n.find('hide') or ''
 +        self._dir = dir
 +        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)
 +
 +    def __str__(self):
 +        if self.is_source:
 +            return 'Source - {}({})'.format(self.get_name(), self.get_key())
 +        if self.is_sink:
 +            return 'Sink - {}({})'.format(self.get_name(), self.get_key())
 +
 +    def get_types(self):
 +        return Constants.TYPE_TO_SIZEOF.keys()
 +
 +    def is_type_empty(self):
 +        return not self._n['type']
 +
 +    def validate(self):
 +        Element.validate(self)
 +        if self.get_type() not in self.get_types():
 +            self.add_error_message('Type "{}" is not a possible 
type.'.format(self.get_type()))
 +        platform = self.get_parent().get_parent().get_parent()
 +        if self.get_domain() not in platform.domains:
 +            self.add_error_message('Domain key "{}" is not 
registered.'.format(self.get_domain()))
 +        if not self.get_enabled_connections() and not self.get_optional():
 +            self.add_error_message('Port is not connected.')
 +        # 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.')
 +            if self.get_vlen() != 1:
 +                self.add_error_message('A port of type "msg" must have a 
"vlen" of 1.')
 +
 +    def rewrite(self):
 +        """
 +        Handle the port cloning for virtual blocks.
 +        """
 +        if self.is_type_empty():
 +            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
 +                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
 +        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()
 +
 +    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)
 +
 +    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
 +            sink = _get_sink_from_virtual_sink_port(self)
 +            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
 +            sink = _get_sink_from_virtual_source_port(self)
 +            if not sink.is_type_empty():
 +                return sink
 +
 +    def get_vlen(self):
 +        """
 +        Get the vector length.
 +        If the evaluation of vlen cannot be cast to an integer, return 1.
 +
 +        Returns:
 +            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
 +
 +    def get_nports(self):
 +        """
 +        Get the number of ports.
 +        If already blank, return a blank
 +        If the evaluation of nports cannot be cast to a positive integer, 
return 1.
 +
 +        Returns:
 +            the number of ports or 1
 +        """
 +        if self._nports == '':
 +            return ''
 +
 +        nports = self.get_parent().resolve_dependencies(self._nports)
 +        try:
 +            return max(1, 
int(self.get_parent().get_parent().evaluate(nports)))
 +        except:
 +            return 1
 +
 +    def get_optional(self):
 +        return bool(self._optional)
 +
 +    def get_color(self):
 +        """
 +        Get the color that represents this port's type.
 +        Codes differ for ports where the vec length is 1 or greater than 1.
 +
 +        Returns:
 +            a hex color code.
 +        """
 +        try:
 +            color = Constants.TYPE_TO_COLOR[self.get_type()]
 +            vlen = self.get_vlen()
 +            if vlen == 1:
 +                return color
 +            color_val = int(color[1:], 16)
 +            r = (color_val >> 16) & 0xff
 +            g = (color_val >> 8) & 0xff
 +            b = (color_val >> 0) & 0xff
 +            dark = (0, 0, 30, 50, 70)[min(4, vlen)]
 +            r = max(r-dark, 0)
 +            g = max(g-dark, 0)
 +            b = max(b-dark, 0)
 +            # TODO: Change this to .format()
 +            return '#%.2x%.2x%.2x' % (r, g, b)
 +        except:
 +            return '#FFFFFF'
 +
 +    def get_clones(self):
 +        """
 +        Get the clones of this master port (nports > 1)
 +
 +        Returns:
 +            a list of ports
 +        """
 +        return self._clones
 +
 +    def add_clone(self):
 +        """
 +        Create a clone of this (master) port and store a reference in 
self._clones.
 +
 +        The new port name (and key for message ports) will have index 1... 
appended.
 +        If this is the first clone, this (master) port will get a 0 appended 
to its name (and key)
 +
 +        Returns:
 +            the cloned port
 +        """
 +        # Add index to master port name if there are no clones yet
 +        if not self._clones:
 +            self._name = self._n['name'] + '0'
 +            # Also update key for none stream ports
 +            if not self._key.isdigit():
 +                self._key = self._name
 +
 +        # Prepare a copy of the odict for the clone
 +        n = self._n.copy()
 +        # Remove nports from the key so the copy cannot be a duplicator
 +        if 'nports' in n:
 +            n.pop('nports')
 +        n['name'] = self._n['name'] + str(len(self._clones) + 1)
 +        # Dummy value 99999 will be fixed later
 +        n['key'] = '99999' if self._key.isdigit() else n['name']
 +
 +        # Clone
 +        port = self.__class__(self.get_parent(), n, self._dir)
 +        self._clones.append(port)
 +        return port
 +
 +    def remove_clone(self, port):
 +        """
 +        Remove a cloned port (from the list of clones only)
 +        Remove the index 0 of the master port name (and key9 if there are no 
more clones left
 +        """
 +        self._clones.remove(port)
 +        # Remove index from master port name if there are no more clones
 +        if not self._clones:
 +            self._name = self._n['name']
 +            # Also update key for none stream ports
 +            if not self._key.isdigit():
 +                self._key = self._name
 +
 +    def get_name(self):
 +        number = ''
 +        if self.get_type() == 'bus':
 +            busses = filter(lambda a: a._dir == self._dir, 
self.get_parent().get_ports_gui())
 +            number = str(busses.index(self)) + '#' + 
str(len(self.get_associated_ports()))
 +        return self._name + number
 +
 +    def get_key(self):
 +        return self._key
 +
 +    @property
 +    def is_sink(self):
 +        return self._dir == 'sink'
 +
 +    @property
 +    def is_source(self):
 +        return self._dir == 'source'
 +
 +    def get_type(self):
 +        return self.get_parent().resolve_dependencies(self._type)
 +
 +    def get_domain(self):
 +        return self._domain
 +
 +    def get_hide(self):
 +        return self._hide_evaluated
 +
 +    def get_connections(self):
 +        """
 +        Get all connections that use this port.
 +
 +        Returns:
 +            a list of connection objects
 +        """
 +        connections = self.get_parent().get_parent().connections
 +        connections = filter(lambda c: c.get_source() is self or c.get_sink() 
is self, connections)
 +        return connections
 +
 +    def get_enabled_connections(self):
 +        """
 +        Get all enabled connections that use this port.
 +
 +        Returns:
 +            a list of connection objects
 +        """
 +        return filter(lambda c: c.get_enabled(), self.get_connections())
 +
 +    def get_associated_ports(self):
 +        if not self.get_type() == 'bus':
 +            return [self]
 +        else:
 +            if self.is_source:
 +                get_ports = self.get_parent().get_sources
 +                bus_structure = 
self.get_parent().current_bus_structure['source']
 +            else:
 +                get_ports = self.get_parent().get_sinks
 +                bus_structure = 
self.get_parent().current_bus_structure['sink']
 +
 +            ports = [i for i in get_ports() if not i.get_type() == 'bus']
 +            if bus_structure:
 +                busses = [i for i in get_ports() if i.get_type() == 'bus']
 +                bus_index = busses.index(self)
 +                ports = filter(lambda a: ports.index(a) in 
bus_structure[bus_index], ports)
 +            return ports
diff --cc grc/gui/FlowGraph.py
index c7c64c6,e940661..15488cc
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@@ -207,7 -190,9 +209,9 @@@ class FlowGraph(Element, _Flowgraph)
          for block_n in blocks_n:
              block_key = block_n.find('key')
              if block_key == 'options': continue
 -            block = self.get_new_block(block_key)
 +            block = self.new_block(block_key)
+             if not block:
+                 continue  # unknown block was pasted (e.g. dummy block)
              selected.add(block)
              #set params
              params_n = block_n.findall('param')



reply via email to

[Prev in Thread] Current Thread [Next in Thread]